Imported Upstream version 0.10.23
[profile/ivi/gst-plugins-bad.git] / ext / jp2k / gstjasperdec.c
1 /* GStreamer Jasper based j2k image decoder
2  * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-jasperdec
22  *
23  * Decodes jpeg2000 images.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 #include <gst/gst.h>
30 #include <gst/video/video.h>
31 #include <string.h>
32
33 #include <jasper/jasper.h>
34
35 #include "gstjasperdec.h"
36
37 GST_DEBUG_CATEGORY_STATIC (gst_jasper_dec_debug);
38 #define GST_CAT_DEFAULT gst_jasper_dec_debug
39
40 enum
41 {
42   ARG_0,
43 };
44
45 /* FIXME 0.11: Use a single caps name for jpeg2000 codestreams
46  * and drop the "boxed" variant
47  */
48
49 static GstStaticPadTemplate gst_jasper_dec_sink_template =
50     GST_STATIC_PAD_TEMPLATE ("sink",
51     GST_PAD_SINK,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS ("image/x-j2c, "
54         "framerate = " GST_VIDEO_FPS_RANGE ", "
55         "fields = (int) 1; "
56         "image/x-jpc, "
57         "framerate = " GST_VIDEO_FPS_RANGE ", "
58         "fields = (int) 1; " "image/jp2")
59     );
60
61 static GstStaticPadTemplate gst_jasper_dec_src_template =
62     GST_STATIC_PAD_TEMPLATE ("src",
63     GST_PAD_SRC,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; "
66         GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; "
67         GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; "
68         GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, Y41B, Y42B, v308 }"))
69     );
70
71 static void gst_jasper_dec_reset (GstJasperDec * dec);
72 static GstStateChangeReturn gst_jasper_dec_change_state (GstElement * element,
73     GstStateChange transition);
74 static gboolean gst_jasper_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
75 static GstFlowReturn gst_jasper_dec_chain (GstPad * pad, GstBuffer * buffer);
76 static gboolean gst_jasper_dec_src_event (GstPad * pad, GstEvent * event);
77 static gboolean gst_jasper_dec_sink_event (GstPad * pad, GstEvent * event);
78 static void gst_jasper_dec_update_qos (GstJasperDec * dec, gdouble proportion,
79     GstClockTime time);
80 static void gst_jasper_dec_reset_qos (GstJasperDec * dec);
81 static void gst_jasper_dec_read_qos (GstJasperDec * dec, gdouble * proportion,
82     GstClockTime * time);
83
84 /* minor trick:
85  * keep original naming but use unique name here for a happy type system
86  */
87
88 typedef GstJasperDec GstJp2kDec;
89 typedef GstJasperDecClass GstJp2kDecClass;
90
91 GST_BOILERPLATE (GstJp2kDec, gst_jasper_dec, GstElement, GST_TYPE_ELEMENT);
92
93 static void
94 gst_jasper_dec_base_init (gpointer g_class)
95 {
96   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
97
98   gst_element_class_add_static_pad_template (element_class,
99       &gst_jasper_dec_src_template);
100   gst_element_class_add_static_pad_template (element_class,
101       &gst_jasper_dec_sink_template);
102   gst_element_class_set_details_simple (element_class,
103       "Jasper JPEG2000 image decoder", "Codec/Decoder/Image",
104       "Decodes JPEG2000 encoded images using jasper",
105       "Mark Nauwelaerts <mnauw@users.sf.net>");
106 }
107
108 /* initialize the plugin's class */
109 static void
110 gst_jasper_dec_class_init (GstJasperDecClass * klass)
111 {
112   GstElementClass *gstelement_class;
113
114   gstelement_class = (GstElementClass *) klass;
115
116   GST_DEBUG_CATEGORY_INIT (gst_jasper_dec_debug, "jp2kdec", 0,
117       "Jasper JPEG2000 decoder");
118
119   gstelement_class->change_state =
120       GST_DEBUG_FUNCPTR (gst_jasper_dec_change_state);
121 }
122
123 static void
124 gst_jasper_dec_init (GstJasperDec * dec, GstJasperDecClass * klass)
125 {
126   dec->sinkpad =
127       gst_pad_new_from_static_template (&gst_jasper_dec_sink_template, "sink");
128   gst_pad_set_setcaps_function (dec->sinkpad,
129       GST_DEBUG_FUNCPTR (gst_jasper_dec_sink_setcaps));
130   gst_pad_set_chain_function (dec->sinkpad,
131       GST_DEBUG_FUNCPTR (gst_jasper_dec_chain));
132   gst_pad_set_event_function (dec->sinkpad,
133       GST_DEBUG_FUNCPTR (gst_jasper_dec_sink_event));
134   gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
135
136   dec->srcpad =
137       gst_pad_new_from_static_template (&gst_jasper_dec_src_template, "src");
138   gst_pad_use_fixed_caps (dec->srcpad);
139   gst_pad_set_event_function (dec->srcpad,
140       GST_DEBUG_FUNCPTR (gst_jasper_dec_src_event));
141   gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
142
143   dec->codec_data = NULL;
144   dec->buf = NULL;
145   gst_jasper_dec_reset (dec);
146 }
147
148 static void
149 gst_jasper_dec_reset (GstJasperDec * dec)
150 {
151   if (dec->codec_data)
152     gst_buffer_unref (dec->codec_data);
153   dec->codec_data = NULL;
154   if (dec->buf)
155     g_free (dec->buf);
156   dec->buf = NULL;
157   dec->fmt = -1;
158   dec->clrspc = JAS_CLRSPC_UNKNOWN;
159   dec->format = GST_VIDEO_FORMAT_UNKNOWN;
160   gst_jasper_dec_reset_qos (dec);
161   gst_segment_init (&dec->segment, GST_FORMAT_TIME);
162   dec->discont = TRUE;
163 }
164
165 static gboolean
166 gst_jasper_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
167 {
168   GstJasperDec *dec;
169   const GValue *framerate;
170   GstStructure *s;
171   const gchar *mimetype;
172   guint32 fourcc;
173
174   dec = GST_JASPER_DEC (GST_PAD_PARENT (pad));
175   s = gst_caps_get_structure (caps, 0);
176   mimetype = gst_structure_get_name (s);
177
178   /* reset negotiation */
179   dec->fmt = -1;
180   dec->strip = 0;
181   dec->format = GST_VIDEO_FORMAT_UNKNOWN;
182   if (dec->codec_data) {
183     gst_buffer_unref (dec->codec_data);
184     dec->codec_data = NULL;
185   }
186
187   if (!strcmp (mimetype, "image/x-j2c") || !strcmp (mimetype, "image/x-jpc")) {
188     const GValue *codec_data;
189     gint fields;
190
191     /* we only handle single field, packetized input */
192     if (gst_structure_get_value (s, "framerate") == NULL)
193       goto refuse_caps;
194     if (gst_structure_get_int (s, "fields", &fields) && fields != 1)
195       goto refuse_caps;
196
197     if (!gst_structure_get_fourcc (s, "fourcc", &fourcc))
198       goto refuse_caps;
199     switch (fourcc) {
200       case GST_MAKE_FOURCC ('s', 'R', 'G', 'B'):
201         dec->clrspc = JAS_CLRSPC_SRGB;
202         break;
203       case GST_MAKE_FOURCC ('s', 'Y', 'U', 'V'):
204         dec->clrspc = JAS_CLRSPC_SYCBCR;
205         break;
206       default:
207         goto refuse_caps;
208         break;
209     }
210
211     dec->fmt = jas_image_strtofmt ((char *) "jpc");
212     /* strip the j2c box stuff it is embedded in */
213     if (!strcmp (mimetype, "image/x-jpc"))
214       dec->strip = 0;
215     else
216       dec->strip = 8;
217
218     codec_data = gst_structure_get_value (s, "codec_data");
219     if (codec_data) {
220       dec->codec_data = gst_value_get_buffer (codec_data);
221       gst_buffer_ref (dec->codec_data);
222     }
223   } else if (!strcmp (mimetype, "image/jp2"))
224     dec->fmt = jas_image_strtofmt ((char *) "jp2");
225
226   if (dec->fmt < 0)
227     goto refuse_caps;
228
229   if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
230     dec->framerate_numerator = gst_value_get_fraction_numerator (framerate);
231     dec->framerate_denominator = gst_value_get_fraction_denominator (framerate);
232     GST_DEBUG_OBJECT (dec, "got framerate of %d/%d fps => packetized mode",
233         dec->framerate_numerator, dec->framerate_denominator);
234   } else {
235     dec->framerate_numerator = 0;
236     dec->framerate_denominator = 1;
237     GST_DEBUG_OBJECT (dec, "no framerate, assuming single image");
238   }
239
240   return TRUE;
241
242 refuse_caps:
243   {
244     GST_WARNING_OBJECT (dec, "refused caps %" GST_PTR_FORMAT, caps);
245     return FALSE;
246   }
247 }
248
249 static GstFlowReturn
250 gst_jasper_dec_negotiate (GstJasperDec * dec, jas_image_t * image)
251 {
252   GstFlowReturn flow_ret = GST_FLOW_OK;
253   gint width, height, channels;
254   gint i, j;
255   gboolean negotiate = FALSE;
256   jas_clrspc_t clrspc;
257   GstCaps *allowed_caps, *caps;
258
259   width = jas_image_width (image);
260   height = jas_image_height (image);
261   channels = jas_image_numcmpts (image);
262
263   GST_LOG_OBJECT (dec, "%d x %d, %d components", width, height, channels);
264
265   /* jp2c bitstream has no real colour space info (kept in container),
266    * so decoder may only pretend to know, where it really does not */
267   if (!jas_clrspc_isunknown (dec->clrspc)) {
268     clrspc = dec->clrspc;
269     GST_DEBUG_OBJECT (dec, "forcing container supplied colour space %d",
270         clrspc);
271     jas_image_setclrspc (image, clrspc);
272   } else
273     clrspc = jas_image_clrspc (image);
274
275   if (!width || !height || !channels || jas_clrspc_isunknown (clrspc))
276     goto fail_image;
277
278   if (dec->width != width || dec->height != height ||
279       dec->channels != channels || dec->clrspc != clrspc)
280     negotiate = TRUE;
281
282   if (channels != 3)
283     goto not_supported;
284
285   for (i = 0; i < channels; i++) {
286     gint cheight, cwidth, depth, sgnd;
287
288     cheight = jas_image_cmptheight (image, i);
289     cwidth = jas_image_cmptwidth (image, i);
290     depth = jas_image_cmptprec (image, i);
291     sgnd = jas_image_cmptsgnd (image, i);
292
293     GST_LOG_OBJECT (dec, "image component %d, %dx%d, depth %d, sgnd %d", i,
294         cwidth, cheight, depth, sgnd);
295
296     if (depth != 8 || sgnd)
297       goto not_supported;
298
299     if (dec->cheight[i] != cheight || dec->cwidth[i] != cwidth) {
300       dec->cheight[i] = cheight;
301       dec->cwidth[i] = cwidth;
302       negotiate = TRUE;
303     }
304   }
305
306   if (!negotiate && dec->format != GST_VIDEO_FORMAT_UNKNOWN)
307     goto done;
308
309   /* clear and refresh to new state */
310   flow_ret = GST_FLOW_NOT_NEGOTIATED;
311   dec->format = GST_VIDEO_FORMAT_UNKNOWN;
312   dec->width = width;
313   dec->height = height;
314   dec->channels = channels;
315
316   /* retrieve allowed caps, and find the first one that reasonably maps
317    * to the parameters of the colourspace */
318   caps = gst_pad_get_allowed_caps (dec->srcpad);
319   if (!caps) {
320     GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
321     /* need to copy because get_allowed_caps returns a ref,
322        and get_pad_template_caps doesn't */
323     caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
324   }
325   /* avoid lists of fourcc, etc */
326   allowed_caps = gst_caps_normalize (caps);
327   gst_caps_unref (caps);
328   caps = NULL;
329   GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);
330
331   for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
332     GstVideoFormat format;
333     gboolean ok;
334
335     if (caps)
336       gst_caps_unref (caps);
337     caps = gst_caps_copy_nth (allowed_caps, i);
338     /* sigh, ds and _parse_caps need fixed caps for parsing, fixate */
339     gst_pad_fixate_caps (dec->srcpad, caps);
340     GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps);
341     if (!gst_video_format_parse_caps (caps, &format, NULL, NULL))
342       continue;
343     if (gst_video_format_is_rgb (format) &&
344         jas_clrspc_fam (clrspc) == JAS_CLRSPC_FAM_RGB) {
345       GST_DEBUG_OBJECT (dec, "trying RGB");
346       if ((dec->cmpt[0] = jas_image_getcmptbytype (image,
347                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
348           (dec->cmpt[1] = jas_image_getcmptbytype (image,
349                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
350           (dec->cmpt[2] = jas_image_getcmptbytype (image,
351                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
352         GST_DEBUG_OBJECT (dec, "missing RGB color component");
353         continue;
354       }
355     } else if (gst_video_format_is_yuv (format) &&
356         jas_clrspc_fam (clrspc) == JAS_CLRSPC_FAM_YCBCR) {
357       GST_DEBUG_OBJECT (dec, "trying YUV");
358       if ((dec->cmpt[0] = jas_image_getcmptbytype (image,
359                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_Y))) < 0 ||
360           (dec->cmpt[1] = jas_image_getcmptbytype (image,
361                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_CB))) < 0 ||
362           (dec->cmpt[2] = jas_image_getcmptbytype (image,
363                   JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_CR))) < 0) {
364         GST_DEBUG_OBJECT (dec, "missing YUV color component");
365         continue;
366       }
367     } else
368       continue;
369     /* match format with validity checks */
370     ok = TRUE;
371     for (j = 0; j < channels; j++) {
372       gint cmpt;
373
374       cmpt = dec->cmpt[j];
375       if (dec->cwidth[cmpt] != gst_video_format_get_component_width (format, j,
376               width) ||
377           dec->cheight[cmpt] != gst_video_format_get_component_height (format,
378               j, height))
379         ok = FALSE;
380     }
381     /* commit to this format */
382     if (ok) {
383       dec->format = format;
384       break;
385     }
386   }
387
388   if (caps)
389     gst_caps_unref (caps);
390   gst_caps_unref (allowed_caps);
391
392   if (dec->format != GST_VIDEO_FORMAT_UNKNOWN) {
393     /* cache some video format properties */
394     for (j = 0; j < channels; ++j) {
395       dec->offset[j] = gst_video_format_get_component_offset (dec->format, j,
396           dec->width, dec->height);
397       dec->inc[j] = gst_video_format_get_pixel_stride (dec->format, j);
398       dec->stride[j] = gst_video_format_get_row_stride (dec->format, j,
399           dec->width);
400     }
401     dec->image_size = gst_video_format_get_size (dec->format, width, height);
402     dec->alpha = gst_video_format_has_alpha (dec->format);
403
404     if (dec->buf)
405       g_free (dec->buf);
406     dec->buf = g_new0 (glong, dec->width);
407
408     caps = gst_video_format_new_caps (dec->format, dec->width, dec->height,
409         dec->framerate_numerator, dec->framerate_denominator, 1, 1);
410
411     GST_DEBUG_OBJECT (dec, "Set format to %d, size to %dx%d", dec->format,
412         dec->width, dec->height);
413
414     if (!gst_pad_set_caps (dec->srcpad, caps))
415       flow_ret = GST_FLOW_NOT_NEGOTIATED;
416     else
417       flow_ret = GST_FLOW_OK;
418
419     gst_caps_unref (caps);
420   }
421
422 done:
423   return flow_ret;
424
425   /* ERRORS */
426 fail_image:
427   {
428     GST_DEBUG_OBJECT (dec, "Failed to process decoded image.");
429     flow_ret = GST_FLOW_NOT_NEGOTIATED;
430     goto done;
431   }
432 not_supported:
433   {
434     GST_DEBUG_OBJECT (dec, "Decoded image has unsupported colour space.");
435     GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Unsupported colorspace"));
436     flow_ret = GST_FLOW_ERROR;
437     goto done;
438   }
439 }
440
441 static GstFlowReturn
442 gst_jasper_dec_get_picture (GstJasperDec * dec, guint8 * data,
443     guint size, GstBuffer ** outbuf)
444 {
445   GstFlowReturn ret = GST_FLOW_OK;
446   jas_stream_t *stream = NULL;
447   jas_image_t *image = NULL;
448   gint i;
449
450   g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
451
452   *outbuf = NULL;
453
454   if (!(stream = jas_stream_memopen ((gpointer) data, size)))
455     goto fail_stream;
456
457   if (!(image = jas_image_decode (stream, dec->fmt, (char *) "")))
458     goto fail_decode;
459
460   ret = gst_jasper_dec_negotiate (dec, image);
461   if (ret != GST_FLOW_OK)
462     goto fail_negotiate;
463
464   ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
465       GST_BUFFER_OFFSET_NONE,
466       dec->image_size, GST_PAD_CAPS (dec->srcpad), outbuf);
467
468   if (ret != GST_FLOW_OK)
469     goto no_buffer;
470
471   if (dec->alpha)
472     memset (GST_BUFFER_DATA (*outbuf), 0xff, dec->image_size);
473
474   for (i = 0; i < dec->channels; ++i) {
475     gint x, y, cwidth, cheight, inc, stride, cmpt;
476     guint8 *row_pix, *out_pix;
477     glong *tb;
478
479     inc = dec->inc[i];
480     stride = dec->stride[i];
481     cmpt = dec->cmpt[i];
482     cheight = dec->cheight[cmpt];
483     cwidth = dec->cwidth[cmpt];
484
485     GST_LOG_OBJECT (dec,
486         "retrieve component %d<=%d, size %dx%d, offset %d, inc %d, stride %d",
487         i, cmpt, cwidth, cheight, dec->offset[i], inc, stride);
488
489     out_pix = GST_BUFFER_DATA (*outbuf) + dec->offset[i];
490
491     for (y = 0; y < cheight; y++) {
492       row_pix = out_pix;
493       tb = dec->buf;
494       if (jas_image_readcmpt2 (image, i, 0, y, cwidth, 1, dec->buf))
495         goto fail_image;
496       for (x = 0; x < cwidth; x++) {
497         *out_pix = *tb;
498         tb++;
499         out_pix += inc;
500       }
501       out_pix = row_pix + stride;
502     }
503   }
504
505   GST_LOG_OBJECT (dec, "all components retrieved");
506
507 done:
508   if (image)
509     jas_image_destroy (image);
510   if (stream)
511     jas_stream_close (stream);
512
513   return ret;
514
515   /* ERRORS */
516 fail_stream:
517   {
518     GST_DEBUG_OBJECT (dec, "Failed to create inputstream.");
519     goto fail;
520   }
521 fail_decode:
522   {
523     GST_DEBUG_OBJECT (dec, "Failed to decode image.");
524     goto fail;
525   }
526 fail_image:
527   {
528     GST_DEBUG_OBJECT (dec, "Failed to process decoded image.");
529     goto fail;
530   }
531 fail:
532   {
533     if (*outbuf)
534       gst_buffer_unref (*outbuf);
535     *outbuf = NULL;
536     GST_ELEMENT_WARNING (dec, STREAM, DECODE, (NULL), (NULL));
537     ret = GST_FLOW_OK;
538     goto done;
539   }
540 no_buffer:
541   {
542     GST_DEBUG_OBJECT (dec, "Failed to create outbuffer - %s",
543         gst_flow_get_name (ret));
544     goto done;
545   }
546 fail_negotiate:
547   {
548     GST_DEBUG_OBJECT (dec, "Failed to determine output caps.");
549     goto done;
550   }
551 }
552
553 /* Perform qos calculations before decoding the next frame. Returns TRUE if the
554  * frame should be decoded, FALSE if the frame can be dropped entirely */
555 static gboolean
556 gst_jasper_dec_do_qos (GstJasperDec * dec, GstClockTime timestamp)
557 {
558   GstClockTime qostime, earliest_time;
559   gdouble proportion;
560
561   /* no timestamp, can't do QoS => decode frame */
562   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
563     GST_LOG_OBJECT (dec, "invalid timestamp, can't do QoS, decode frame");
564     return TRUE;
565   }
566
567   /* get latest QoS observation values */
568   gst_jasper_dec_read_qos (dec, &proportion, &earliest_time);
569
570   /* skip qos if we have no observation (yet) => decode frame */
571   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
572     GST_LOG_OBJECT (dec, "no observation yet, decode frame");
573     return TRUE;
574   }
575
576   /* qos is done on running time */
577   qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
578       timestamp);
579
580   /* see how our next timestamp relates to the latest qos timestamp */
581   GST_LOG_OBJECT (dec, "qostime %" GST_TIME_FORMAT ", earliest %"
582       GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
583
584   if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
585     GST_DEBUG_OBJECT (dec, "we are late, drop frame");
586     return FALSE;
587   }
588
589   GST_LOG_OBJECT (dec, "decode frame");
590   return TRUE;
591 }
592
593 static GstFlowReturn
594 gst_jasper_dec_chain (GstPad * pad, GstBuffer * buf)
595 {
596   GstJasperDec *dec;
597   GstFlowReturn ret = GST_FLOW_OK;
598   GstClockTime ts;
599   GstBuffer *outbuf = NULL;
600   guint8 *data;
601   guint size;
602   gboolean decode;
603
604   dec = GST_JASPER_DEC (GST_PAD_PARENT (pad));
605
606   if (dec->fmt < 0)
607     goto not_negotiated;
608
609   ts = GST_BUFFER_TIMESTAMP (buf);
610
611   GST_LOG_OBJECT (dec, "buffer with ts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
612
613   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))
614     dec->discont = TRUE;
615
616   decode = gst_jasper_dec_do_qos (dec, ts);
617
618   /* FIXME: do clipping */
619
620   if (G_UNLIKELY (!decode)) {
621     dec->discont = TRUE;
622     goto done;
623   }
624
625   /* strip possible prefix */
626   if (dec->strip) {
627     GstBuffer *tmp;
628
629     tmp = gst_buffer_create_sub (buf, dec->strip,
630         GST_BUFFER_SIZE (buf) - dec->strip);
631     gst_buffer_copy_metadata (tmp, buf, GST_BUFFER_COPY_TIMESTAMPS);
632     gst_buffer_unref (buf);
633     buf = tmp;
634   }
635   /* preprend possible codec_data */
636   if (dec->codec_data) {
637     GstBuffer *tmp;
638
639     tmp = gst_buffer_merge (dec->codec_data, buf);
640     gst_buffer_copy_metadata (tmp, buf, GST_BUFFER_COPY_TIMESTAMPS);
641     gst_buffer_unref (buf);
642     buf = tmp;
643   }
644
645   /* now really feed the data to decoder */
646   data = GST_BUFFER_DATA (buf);
647   size = GST_BUFFER_SIZE (buf);
648
649   ret = gst_jasper_dec_get_picture (dec, data, size, &outbuf);
650
651   if (outbuf) {
652     gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);
653     if (dec->discont) {
654       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
655       dec->discont = FALSE;
656     }
657
658     if (ret == GST_FLOW_OK)
659       ret = gst_pad_push (dec->srcpad, outbuf);
660     else
661       gst_buffer_unref (outbuf);
662   }
663
664 done:
665   gst_buffer_unref (buf);
666
667   return ret;
668
669   /* ERRORS */
670 not_negotiated:
671   {
672     GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
673         ("format wasn't negotiated before chain function"));
674     ret = GST_FLOW_NOT_NEGOTIATED;
675     goto done;
676   }
677 }
678
679 static void
680 gst_jasper_dec_update_qos (GstJasperDec * dec, gdouble proportion,
681     GstClockTime time)
682 {
683   GST_OBJECT_LOCK (dec);
684   dec->proportion = proportion;
685   dec->earliest_time = time;
686   GST_OBJECT_UNLOCK (dec);
687 }
688
689 static void
690 gst_jasper_dec_reset_qos (GstJasperDec * dec)
691 {
692   gst_jasper_dec_update_qos (dec, 0.5, GST_CLOCK_TIME_NONE);
693 }
694
695 static void
696 gst_jasper_dec_read_qos (GstJasperDec * dec, gdouble * proportion,
697     GstClockTime * time)
698 {
699   GST_OBJECT_LOCK (dec);
700   *proportion = dec->proportion;
701   *time = dec->earliest_time;
702   GST_OBJECT_UNLOCK (dec);
703 }
704
705 static gboolean
706 gst_jasper_dec_src_event (GstPad * pad, GstEvent * event)
707 {
708   GstJasperDec *dec;
709   gboolean res;
710
711   dec = GST_JASPER_DEC (gst_pad_get_parent (pad));
712
713   switch (GST_EVENT_TYPE (event)) {
714     case GST_EVENT_QOS:{
715       GstClockTimeDiff diff;
716       GstClockTime timestamp;
717       gdouble proportion;
718
719       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
720
721       gst_jasper_dec_update_qos (dec, proportion, timestamp + diff);
722       break;
723     }
724     default:
725       break;
726   }
727
728   res = gst_pad_push_event (dec->sinkpad, event);
729
730   gst_object_unref (dec);
731   return res;
732 }
733
734 static gboolean
735 gst_jasper_dec_sink_event (GstPad * pad, GstEvent * event)
736 {
737   GstJasperDec *dec;
738   gboolean res = FALSE;
739
740   dec = GST_JASPER_DEC (gst_pad_get_parent (pad));
741
742   switch (GST_EVENT_TYPE (event)) {
743     case GST_EVENT_FLUSH_STOP:
744       gst_jasper_dec_reset_qos (dec);
745       gst_segment_init (&dec->segment, GST_FORMAT_TIME);
746       dec->discont = TRUE;
747       break;
748     case GST_EVENT_NEWSEGMENT:{
749       gboolean update;
750       GstFormat fmt;
751       gint64 start, stop, time;
752       gdouble rate, arate;
753
754       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
755           &start, &stop, &time);
756
757       switch (fmt) {
758         case GST_FORMAT_TIME:
759           /* great, our native segment format */
760           break;
761         case GST_FORMAT_BYTES:
762           /* hmm .. */
763           if (start != 0 || time != 0)
764             goto invalid_bytes_segment;
765           /* create bogus segment in TIME format, starting from 0 */
766           gst_event_unref (event);
767           fmt = GST_FORMAT_TIME;
768           start = 0;
769           stop = -1;
770           time = 0;
771           event = gst_event_new_new_segment (update, rate, fmt, start, stop,
772               time);
773           break;
774         default:
775           /* invalid format */
776           goto invalid_format;
777       }
778
779       gst_segment_set_newsegment_full (&dec->segment, update, rate, arate,
780           fmt, start, stop, time);
781
782       GST_DEBUG_OBJECT (dec, "NEWSEGMENT %" GST_SEGMENT_FORMAT, &dec->segment);
783       break;
784     }
785     default:
786       break;
787   }
788
789   res = gst_pad_push_event (dec->srcpad, event);
790
791 done:
792
793   gst_object_unref (dec);
794   return res;
795
796 /* ERRORS */
797 invalid_format:
798   {
799     GST_WARNING_OBJECT (dec, "unknown format received in NEWSEGMENT event");
800     gst_event_unref (event);
801     goto done;
802   }
803 invalid_bytes_segment:
804   {
805     GST_WARNING_OBJECT (dec, "can't handle NEWSEGMENT event in BYTES format "
806         "with a non-0 start or non-0 time value");
807     gst_event_unref (event);
808     goto done;
809   }
810 }
811
812 static GstStateChangeReturn
813 gst_jasper_dec_change_state (GstElement * element, GstStateChange transition)
814 {
815   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
816   GstJasperDec *dec = GST_JASPER_DEC (element);
817
818   switch (transition) {
819     case GST_STATE_CHANGE_NULL_TO_READY:
820       if (jas_init ())
821         goto fail_init;
822       break;
823     case GST_STATE_CHANGE_READY_TO_PAUSED:
824       break;
825     default:
826       break;
827   }
828
829   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
830   if (ret == GST_STATE_CHANGE_FAILURE)
831     return ret;
832
833   switch (transition) {
834     case GST_STATE_CHANGE_PAUSED_TO_READY:
835       gst_jasper_dec_reset (dec);
836       break;
837     case GST_STATE_CHANGE_READY_TO_NULL:
838       jas_cleanup ();
839       break;
840     default:
841       break;
842   }
843
844   return ret;
845
846   /* ERRORS */
847 fail_init:
848   {
849     GST_ELEMENT_ERROR (dec, LIBRARY, INIT, (NULL), (NULL));
850     return GST_STATE_CHANGE_FAILURE;
851   }
852 }