diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/jpeg/gstjpegdec.c | 150 | ||||
-rw-r--r-- | ext/jpeg/gstjpegdec.h | 5 |
2 files changed, 96 insertions, 59 deletions
diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c index 382e457c..e1a456f7 100644 --- a/ext/jpeg/gstjpegdec.c +++ b/ext/jpeg/gstjpegdec.c @@ -54,7 +54,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("image/jpeg, " "width = (int) [ " G_STRINGIFY (MIN_WIDTH) ", " G_STRINGIFY (MAX_WIDTH) " ], " "height = (int) [ " G_STRINGIFY (MIN_HEIGHT) ", " - G_STRINGIFY (MAX_HEIGHT) " ], " "framerate = (double) [ 1, MAX ]") + G_STRINGIFY (MAX_HEIGHT) " ], " "framerate = (double) [ 0, MAX ]") ); GST_DEBUG_CATEGORY (jpeg_dec_debug); @@ -243,10 +243,6 @@ gst_jpeg_dec_init (GstJpegDec * dec) (&gst_jpeg_dec_src_pad_template), "src"); gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - dec->packetized = FALSE; - dec->next_ts = 0; - dec->fps = 1.0; - /* setup jpeglib */ memset (&dec->cinfo, 0, sizeof (dec->cinfo)); memset (&dec->jerr, 0, sizeof (dec->jerr)); @@ -696,7 +692,6 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) GstFlowReturn ret; GstJpegDec *dec; GstBuffer *outbuf; - GstCaps *caps; gulong size; guchar *data, *outdata; guchar *base[3], *last[3]; @@ -704,11 +699,15 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) gint width, height; gint r_h, r_v; gint i; + guint code; + GstClockTime timestamp, duration; dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad)); - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) { - dec->next_ts = GST_BUFFER_TIMESTAMP (buf); + timestamp = GST_BUFFER_TIMESTAMP (buf); + + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + dec->next_ts = timestamp; } if (dec->tempbuf) { @@ -719,7 +718,7 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) buf = NULL; if (!gst_jpeg_dec_ensure_header (dec)) - return GST_FLOW_OK; /* need more data */ + goto need_more_data; /* If we know that each input buffer contains data * for a whole jpeg image (e.g. MJPEG streams), just @@ -727,25 +726,13 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) * the jpeg data */ if (dec->packetized) { img_len = GST_BUFFER_SIZE (dec->tempbuf); -#if 0 - /* This does not work, e.g. avidemux adds an - * extra 0 at the end of the buffer */ - if (!gst_jpeg_dec_have_end_marker (dec)) { - gst_util_dump_mem (GST_BUFFER_DATA (dec->tempbuf), - GST_BUFFER_SIZE (dec->tempbuf)); - GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("JPEG input without EOI marker"), - (NULL)); - ret = GST_FLOW_ERROR; - goto done; - } -#endif } else { /* Parse jpeg image to handle jpeg input that * is not aligned to buffer boundaries */ img_len = gst_jpeg_dec_parse_image_data (dec); if (img_len == 0) - return GST_FLOW_OK; /* need more data */ + goto need_more_data; } data = (guchar *) GST_BUFFER_DATA (dec->tempbuf); @@ -756,17 +743,13 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) dec->jsrc.pub.bytes_in_buffer = size; if (setjmp (dec->jerr.setjmp_buffer)) { - guint code = dec->jerr.pub.msg_code; + code = dec->jerr.pub.msg_code; if (code == JERR_INPUT_EOF) { GST_DEBUG ("jpeg input EOF error, we probably need more data"); - return GST_FLOW_OK; + goto need_more_data; } - GST_ELEMENT_ERROR (dec, STREAM, DECODE, - (_("Failed to decode JPEG image")), - ("Error #%u: %s", code, dec->jerr.pub.jpeg_message_table[code])); - ret = GST_FLOW_ERROR; - goto done; + goto decode_error; } GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1], @@ -796,41 +779,52 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) height = dec->cinfo.output_height; if (width < MIN_WIDTH || width > MAX_WIDTH || - height < MIN_HEIGHT || height > MAX_HEIGHT) { - GST_ELEMENT_ERROR (dec, STREAM, DECODE, - ("Picture is too small or too big (%ux%u)", width, height), - ("Picture is too small or too big (%ux%u)", width, height)); - ret = GST_FLOW_ERROR; - goto done; - } + height < MIN_HEIGHT || height > MAX_HEIGHT) + goto wrong_size; + + if (width != dec->caps_width || height != dec->caps_height || + dec->fps != dec->caps_fps) { + GstCaps *caps; - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), - "width", G_TYPE_INT, width, - "height", G_TYPE_INT, height, - "framerate", G_TYPE_DOUBLE, (double) dec->fps, NULL); + /* framerate == 0.0 is a still frame */ + caps = gst_caps_new_simple ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", G_TYPE_DOUBLE, (double) dec->fps, NULL); - GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps); - GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor); + GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", + dec->cinfo.max_v_samp_factor); - if (gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, - I420_SIZE (width, height), caps, &outbuf) != GST_FLOW_OK) { - GST_DEBUG_OBJECT (dec, "failed to alloc buffer"); + gst_pad_set_caps (dec->srcpad, caps); gst_caps_unref (caps); - return GST_FLOW_ERROR; + + dec->caps_width = width; + dec->caps_height = height; + dec->caps_fps = dec->fps; } - gst_caps_unref (caps); - caps = NULL; + ret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, + I420_SIZE (width, height), GST_PAD_CAPS (dec->srcpad), &outbuf); + if (ret != GST_FLOW_OK) + goto alloc_failed; outdata = GST_BUFFER_DATA (outbuf); GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts; - GST_BUFFER_DURATION (outbuf) = GST_SECOND / dec->fps; + + if (dec->packetized) { + duration = GST_SECOND / dec->fps; + dec->next_ts += duration; + } else { + duration = GST_CLOCK_TIME_NONE; + dec->next_ts = GST_CLOCK_TIME_NONE; + } + GST_BUFFER_DURATION (outbuf) = duration; + GST_LOG_OBJECT (dec, "width %d, height %d, buffer size %d, required size %d", width, height, GST_BUFFER_SIZE (outbuf), I420_SIZE (width, height)); - dec->next_ts += GST_BUFFER_DURATION (outbuf); - /* mind the swap, jpeglib outputs blue chroma first */ base[0] = outdata + I420_Y_OFFSET (width, height); base[1] = outdata + I420_U_OFFSET (width, height); @@ -864,9 +858,7 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) jpeg_finish_decompress (&dec->cinfo); GST_LOG_OBJECT (dec, "pushing buffer"); - gst_pad_push (dec->srcpad, outbuf); - - ret = GST_FLOW_OK; + ret = gst_pad_push (dec->srcpad, outbuf); done: if (GST_BUFFER_SIZE (dec->tempbuf) == img_len) { @@ -879,8 +871,45 @@ done: gst_buffer_unref (dec->tempbuf); dec->tempbuf = buf; } - return ret; + + /* special cases */ +need_more_data: + { + GST_LOG_OBJECT (dec, "we need more data"); + return GST_FLOW_OK; + } + /* ERRORS */ +wrong_size: + { + GST_ELEMENT_ERROR (dec, STREAM, DECODE, + ("Picture is too small or too big (%ux%u)", width, height), + ("Picture is too small or too big (%ux%u)", width, height)); + ret = GST_FLOW_ERROR; + goto done; + } +decode_error: + { + GST_ELEMENT_ERROR (dec, STREAM, DECODE, + (_("Failed to decode JPEG image")), + ("Error #%u: %s", code, dec->jerr.pub.jpeg_message_table[code])); + ret = GST_FLOW_ERROR; + goto done; + } +alloc_failed: + { + const gchar *reason; + + reason = gst_flow_get_name (ret); + + GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason); + if (GST_FLOW_IS_FATAL (ret)) { + GST_ELEMENT_ERROR (dec, STREAM, DECODE, + ("Buffer allocation failed, reason: %s", reason), + ("Buffer allocation failed, reason: %s", reason)); + } + return ret; + } } static GstStateChangeReturn @@ -892,10 +921,13 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition) dec = GST_JPEG_DEC (element); switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - dec->next_ts = 0; + case GST_STATE_CHANGE_READY_TO_PAUSED: + dec->fps = 0.0; + dec->caps_fps = 0.0; + dec->caps_width = -1; + dec->caps_height = -1; dec->packetized = FALSE; - break; + dec->next_ts = 0; default: break; } diff --git a/ext/jpeg/gstjpegdec.h b/ext/jpeg/gstjpegdec.h index 8bfe8287..4d8f42c0 100644 --- a/ext/jpeg/gstjpegdec.h +++ b/ext/jpeg/gstjpegdec.h @@ -78,6 +78,11 @@ struct _GstJpegDec { /* video state */ gdouble fps; + /* negotiated state */ + gdouble caps_fps; + gint caps_width; + gint caps_height; + struct jpeg_decompress_struct cinfo; struct GstJpegDecErrorMgr jerr; struct GstJpegDecSourceMgr jsrc; |