From be4f60b0622ac25245830b3d7b601394559d54fe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 17 Aug 2011 15:39:27 +0200 Subject: [PATCH] jpeg: port to 0.11 Also disable smoke for now. --- configure.ac | 2 +- ext/jpeg/Makefile.am | 11 +- ext/jpeg/gstjpeg.c | 4 + ext/jpeg/gstjpegdec.c | 458 +++++++++++++++++++++++++------------------------- ext/jpeg/gstjpegdec.h | 23 +-- ext/jpeg/gstjpegenc.c | 286 ++++++++++++++++--------------- ext/jpeg/gstjpegenc.h | 28 ++- 7 files changed, 408 insertions(+), 404 deletions(-) diff --git a/configure.ac b/configure.ac index 4c0d8b8..1ca8435 100644 --- a/configure.ac +++ b/configure.ac @@ -315,7 +315,7 @@ dnl Make sure you have a space before and after all plugins GST_PLUGINS_NONPORTED=" deinterlace flx goom2k1 icydemux id3demux \ imagefreeze interleave law matroska monoscope shapewipe smpte \ videobox videocrop videomixer \ - annodex apetag cairo cairo_gobject dv1394 flac gdk_pixbuf jpeg libdv libpng \ + annodex apetag cairo cairo_gobject dv1394 flac gdk_pixbuf libdv libpng \ oss oss4 shout2 \ soup taglib wavpack " AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/ext/jpeg/Makefile.am b/ext/jpeg/Makefile.am index a72f12f..eb581e1 100644 --- a/ext/jpeg/Makefile.am +++ b/ext/jpeg/Makefile.am @@ -3,10 +3,8 @@ plugin_LTLIBRARIES = libgstjpeg.la libgstjpeg_la_SOURCES = \ gstjpeg.c \ gstjpegenc.c \ - gstjpegdec.c \ - gstsmokeenc.c \ - smokecodec.c \ - gstsmokedec.c + gstjpegdec.c +# deprected gstsmokeenc.c smokecodec.c gstsmokedec.c libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ @@ -16,6 +14,5 @@ libgstjpeg_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ gstjpeg.h \ - gstjpegdec.h gstjpegenc.h \ - gstsmokeenc.h gstsmokedec.h \ - smokecodec.h smokeformat.h + gstjpegdec.h gstjpegenc.h +# deprecated gstsmokeenc.h gstsmokedec.h smokecodec.h smokeformat.h diff --git a/ext/jpeg/gstjpeg.c b/ext/jpeg/gstjpeg.c index b9d6e04..1a7006b 100644 --- a/ext/jpeg/gstjpeg.c +++ b/ext/jpeg/gstjpeg.c @@ -27,8 +27,10 @@ #include "gstjpeg.h" #include "gstjpegdec.h" #include "gstjpegenc.h" +#if 0 #include "gstsmokeenc.h" #include "gstsmokedec.h" +#endif GType gst_idct_method_get_type (void) @@ -59,6 +61,7 @@ plugin_init (GstPlugin * plugin) GST_TYPE_JPEG_DEC)) return FALSE; +#if 0 if (!gst_element_register (plugin, "smokeenc", GST_RANK_PRIMARY, GST_TYPE_SMOKEENC)) return FALSE; @@ -66,6 +69,7 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "smokedec", GST_RANK_PRIMARY, GST_TYPE_SMOKEDEC)) return FALSE; +#endif return TRUE; } diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c index 1660df6..13a78ff 100644 --- a/ext/jpeg/gstjpegdec.c +++ b/ext/jpeg/gstjpegdec.c @@ -66,12 +66,10 @@ static GstStaticPadTemplate gst_jpeg_dec_src_pad_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") "; " - GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; " - GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; " - GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; " - GST_VIDEO_CAPS_GRAY8) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE + ("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }")) ); + /* *INDENT-ON* */ static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template = @@ -88,31 +86,12 @@ GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug); #define GST_CAT_DEFAULT jpeg_dec_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); -/* These macros are adapted from videotestsrc.c - * and/or gst-plugins/gst/games/gstvideoimage.c */ -#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width)) -#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2) -#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2) - -#define I420_Y_OFFSET(w,h) (0) -#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h))) -#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -static GstElementClass *parent_class; /* NULL */ - -static void gst_jpeg_dec_base_init (gpointer g_class); -static void gst_jpeg_dec_class_init (GstJpegDecClass * klass); -static void gst_jpeg_dec_init (GstJpegDec * jpegdec); - static void gst_jpeg_dec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstFlowReturn gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event); static GstStateChangeReturn gst_jpeg_dec_change_state (GstElement * element, @@ -123,29 +102,8 @@ static void gst_jpeg_dec_reset_qos (GstJpegDec * dec); static void gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion, GstClockTime * time); -GType -gst_jpeg_dec_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo jpeg_dec_info = { - sizeof (GstJpegDecClass), - (GBaseInitFunc) gst_jpeg_dec_base_init, - NULL, - (GClassInitFunc) gst_jpeg_dec_class_init, - NULL, - NULL, - sizeof (GstJpegDec), - 0, - (GInstanceInitFunc) gst_jpeg_dec_init, - }; - - type = g_type_register_static (GST_TYPE_ELEMENT, "GstJpegDec", - &jpeg_dec_info, 0); - } - return type; -} +#define gst_jpeg_dec_parent_class parent_class +G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_ELEMENT); static void gst_jpeg_dec_finalize (GObject * object) @@ -160,20 +118,6 @@ gst_jpeg_dec_finalize (GObject * object) } static void -gst_jpeg_dec_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template)); - gst_element_class_set_details_simple (element_class, "JPEG image decoder", - "Codec/Decoder/Image", - "Decode images from JPEG format", "Wim Taymans "); -} - -static void gst_jpeg_dec_class_init (GstJpegDecClass * klass) { GstElementClass *gstelement_class; @@ -209,6 +153,14 @@ gst_jpeg_dec_class_init (GstJpegDecClass * klass) -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template)); + gst_element_class_set_details_simple (gstelement_class, "JPEG image decoder", + "Codec/Decoder/Image", + "Decode images from JPEG format", "Wim Taymans "); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_jpeg_dec_change_state); @@ -404,8 +356,6 @@ gst_jpeg_dec_init (GstJpegDec * dec) gst_pad_new_from_static_template (&gst_jpeg_dec_sink_pad_template, "sink"); gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); - gst_pad_set_setcaps_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_jpeg_dec_setcaps)); gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (gst_jpeg_dec_chain)); gst_pad_set_event_function (dec->sinkpad, @@ -743,21 +693,19 @@ guarantee_huff_tables (j_decompress_ptr dinfo) } static gboolean -gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps) +gst_jpeg_dec_setcaps (GstJpegDec * dec, GstCaps * caps) { GstStructure *s; - GstJpegDec *dec; const GValue *framerate; - dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad)); s = gst_caps_get_structure (caps, 0); if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) { - dec->framerate_numerator = gst_value_get_fraction_numerator (framerate); - dec->framerate_denominator = gst_value_get_fraction_denominator (framerate); + dec->in_fps_n = gst_value_get_fraction_numerator (framerate); + dec->in_fps_d = gst_value_get_fraction_denominator (framerate); dec->packetized = TRUE; GST_DEBUG ("got framerate of %d/%d fps => packetized mode", - dec->framerate_numerator, dec->framerate_denominator); + dec->in_fps_n, dec->in_fps_d); } /* do not extract width/height here. we do that in the chain @@ -806,7 +754,7 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes) { gint i; - if (G_LIKELY (dec->idr_width_allocated == maxrowbytes)) + if (G_LIKELY (dec->idr_width_allocated >= maxrowbytes)) return TRUE; /* FIXME: maybe just alloc one or three blocks altogether? */ @@ -827,19 +775,28 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes) } static void -gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, guchar * base[1], - guint width, guint height, guint pstride, guint rstride) +gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame) { guchar *rows[16]; guchar **scanarray[1] = { rows }; gint i, j, k; gint lines; + guint8 *base[1]; + gint width, height; + gint pstride, rstride; GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale"); + width = GST_VIDEO_FRAME_WIDTH (frame); + height = GST_VIDEO_FRAME_HEIGHT (frame); + if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width)))) return; + base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0); + pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); + rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); + memcpy (rows, dec->idr_y, 16 * sizeof (gpointer)); i = 0; @@ -863,19 +820,30 @@ gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, guchar * base[1], } static void -gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3], - guint width, guint height, guint pstride, guint rstride) +gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame) { guchar *r_rows[16], *g_rows[16], *b_rows[16]; guchar **scanarray[3] = { r_rows, g_rows, b_rows }; gint i, j, k; gint lines; + guint8 *base[3]; + guint pstride, rstride; + gint width, height; GST_DEBUG_OBJECT (dec, "indirect decoding of RGB"); + width = GST_VIDEO_FRAME_WIDTH (frame); + height = GST_VIDEO_FRAME_HEIGHT (frame); + if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width)))) return; + for (i = 0; i < 3; i++) + base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i); + + pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); + rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); + memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer)); memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer)); memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer)); @@ -905,20 +873,35 @@ gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3], } static void -gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3], - guchar * last[3], guint width, guint height, gint r_v, gint r_h, gint comp) +gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, + gint r_v, gint r_h, gint comp) { guchar *y_rows[16], *u_rows[16], *v_rows[16]; guchar **scanarray[3] = { y_rows, u_rows, v_rows }; gint i, j, k; gint lines; + guchar *base[3], *last[3]; + gint stride[3]; + gint width, height; GST_DEBUG_OBJECT (dec, "unadvantageous width or r_h, taking slow route involving memcpy"); + width = GST_VIDEO_FRAME_WIDTH (frame); + height = GST_VIDEO_FRAME_HEIGHT (frame); + if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width)))) return; + for (i = 0; i < 3; i++) { + base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i); + stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i); + /* make sure we don't make jpeglib write beyond our buffer, + * which might happen if (height % (r_v*DCTSIZE)) != 0 */ + last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * + (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1)); + } + memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer)); memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer)); memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer)); @@ -937,30 +920,30 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3], if (G_LIKELY (lines > 0)) { for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) { if (G_LIKELY (base[0] <= last[0])) { - memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width)); - base[0] += I420_Y_ROWSTRIDE (width); + memcpy (base[0], y_rows[j], stride[0]); + base[0] += stride[0]; } if (r_v == 2) { if (G_LIKELY (base[0] <= last[0])) { - memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width)); - base[0] += I420_Y_ROWSTRIDE (width); + memcpy (base[0], y_rows[j + 1], stride[0]); + base[0] += stride[0]; } } if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) { if (r_h == 2) { - memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width)); - memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width)); + memcpy (base[1], u_rows[k], stride[1]); + memcpy (base[2], v_rows[k], stride[2]); } else if (r_h == 1) { - hresamplecpy1 (base[1], u_rows[k], I420_U_ROWSTRIDE (width)); - hresamplecpy1 (base[2], v_rows[k], I420_V_ROWSTRIDE (width)); + hresamplecpy1 (base[1], u_rows[k], stride[1]); + hresamplecpy1 (base[2], v_rows[k], stride[2]); } else { /* FIXME: implement (at least we avoid crashing by doing nothing) */ } } if (r_v == 2 || (k & 1) != 0) { - base[1] += I420_U_ROWSTRIDE (width); - base[2] += I420_V_ROWSTRIDE (width); + base[1] += stride[1]; + base[2] += stride[2]; } } } else { @@ -969,27 +952,8 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3], } } -#ifndef GST_DISABLE_GST_DEBUG -static inline void -dump_lines (guchar * base[3], guchar ** line[3], int v_samp0, int width) -{ - int j; - - for (j = 0; j < (v_samp0 * DCTSIZE); ++j) { - GST_LOG ("[%02d] %5d %5d %5d", j, - (line[0][j] >= base[0]) ? - (int) (line[0][j] - base[0]) / I420_Y_ROWSTRIDE (width) : -1, - (line[1][j] >= base[1]) ? - (int) (line[1][j] - base[1]) / I420_U_ROWSTRIDE (width) : -1, - (line[2][j] >= base[2]) ? - (int) (line[2][j] - base[2]) / I420_V_ROWSTRIDE (width) : -1); - } -} -#endif - static GstFlowReturn -gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3], - guchar * last[3], guint width, guint height) +gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame) { guchar **line[3]; /* the jpeg line buffer */ guchar *y[4 * DCTSIZE] = { NULL, }; /* alloc enough for the lines */ @@ -997,6 +961,9 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3], guchar *v[4 * DCTSIZE] = { NULL, }; gint i, j; gint lines, v_samp[3]; + guchar *base[3], *last[3]; + gint stride[3]; + guint width, height; line[0] = y; line[1] = u; @@ -1009,35 +976,45 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3], if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2)) goto format_not_supported; + width = GST_VIDEO_FRAME_WIDTH (frame); + height = GST_VIDEO_FRAME_HEIGHT (frame); + + for (i = 0; i < 3; i++) { + base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i); + stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i); + /* make sure we don't make jpeglib write beyond our buffer, + * which might happen if (height % (r_v*DCTSIZE)) != 0 */ + last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * + (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1)); + } + /* let jpeglib decode directly into our final buffer */ GST_DEBUG_OBJECT (dec, "decoding directly into output buffer"); for (i = 0; i < height; i += v_samp[0] * DCTSIZE) { for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) { /* Y */ - line[0][j] = base[0] + (i + j) * I420_Y_ROWSTRIDE (width); + line[0][j] = base[0] + (i + j) * stride[0]; if (G_UNLIKELY (line[0][j] > last[0])) line[0][j] = last[0]; /* U */ if (v_samp[1] == v_samp[0]) { - line[1][j] = base[1] + ((i + j) / 2) * I420_U_ROWSTRIDE (width); + line[1][j] = base[1] + ((i + j) / 2) * stride[1]; } else if (j < (v_samp[1] * DCTSIZE)) { - line[1][j] = base[1] + ((i / 2) + j) * I420_U_ROWSTRIDE (width); + line[1][j] = base[1] + ((i / 2) + j) * stride[1]; } if (G_UNLIKELY (line[1][j] > last[1])) line[1][j] = last[1]; /* V */ if (v_samp[2] == v_samp[0]) { - line[2][j] = base[2] + ((i + j) / 2) * I420_V_ROWSTRIDE (width); + line[2][j] = base[2] + ((i + j) / 2) * stride[2]; } else if (j < (v_samp[2] * DCTSIZE)) { - line[2][j] = base[2] + ((i / 2) + j) * I420_V_ROWSTRIDE (width); + line[2][j] = base[2] + ((i / 2) + j) * stride[2]; } if (G_UNLIKELY (line[2][j] > last[2])) line[2][j] = last[2]; } - /* dump_lines (base, line, v_samp[0], width); */ - lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE); if (G_UNLIKELY (!lines)) { GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0"); @@ -1127,38 +1104,96 @@ gst_jpeg_dec_do_qos (GstJpegDec * dec, GstClockTime timestamp) return TRUE; } -static void +static gboolean +gst_jpeg_dec_buffer_pool (GstJpegDec * dec, GstCaps * caps) +{ + GstQuery *query; + GstBufferPool *pool = NULL; + guint size, min, max, prefix, alignment; + GstStructure *config; + + GST_DEBUG_OBJECT (dec, "setting up bufferpool"); + + /* find a pool for the negotiated caps now */ + query = gst_query_new_allocation (caps, TRUE); + + if (gst_pad_peer_query (dec->srcpad, query)) { + /* we got configuration from our peer, parse them */ + gst_query_parse_allocation_params (query, &size, &min, &max, &prefix, + &alignment, &pool); + size = MAX (size, dec->info.size); + } else { + GST_DEBUG_OBJECT (dec, "peer query failed, using defaults"); + size = dec->info.size; + min = max = 0; + prefix = 0; + alignment = 15; + } + gst_query_unref (query); + + if (pool == NULL) { + /* we did not get a pool, make one ourselves then */ + pool = gst_buffer_pool_new (); + } + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set (config, caps, size, min, max, prefix, + alignment | 15); + /* and store */ + gst_buffer_pool_set_config (pool, config); + + if (dec->pool) { + gst_buffer_pool_set_active (dec->pool, FALSE); + gst_object_unref (dec->pool); + } + dec->pool = pool; + + /* and activate */ + gst_buffer_pool_set_active (pool, TRUE); + + return TRUE; +} + +static gboolean gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc) { GstCaps *caps; GstVideoFormat format; + GstVideoInfo info; - if (G_UNLIKELY (width == dec->caps_width && height == dec->caps_height && - dec->framerate_numerator == dec->caps_framerate_numerator && - dec->framerate_denominator == dec->caps_framerate_denominator && - clrspc == dec->clrspc)) - return; + if (G_UNLIKELY (width == dec->info.width && height == dec->info.height && + dec->in_fps_n == dec->info.fps_n && dec->in_fps_d == dec->info.fps_d + && clrspc == dec->clrspc)) + return TRUE; + + gst_video_info_init (&info); /* framerate == 0/1 is a still frame */ - if (dec->framerate_denominator == 0) { - dec->framerate_numerator = 0; - dec->framerate_denominator = 1; + if (dec->in_fps_d == 0) { + info.fps_n = 0; + info.fps_d = 1; + } else { + info.fps_n = dec->in_fps_n; + info.fps_d = dec->in_fps_d; } /* calculate or assume an average frame duration for QoS purposes */ GST_OBJECT_LOCK (dec); - if (dec->framerate_numerator != 0) { - dec->qos_duration = gst_util_uint64_scale (GST_SECOND, - dec->framerate_denominator, dec->framerate_numerator); + if (info.fps_n != 0) { + dec->qos_duration = + gst_util_uint64_scale (GST_SECOND, info.fps_d, info.fps_n); + dec->duration = dec->qos_duration; } else { /* if not set just use 25fps */ dec->qos_duration = gst_util_uint64_scale (GST_SECOND, 1, 25); + dec->duration = GST_CLOCK_TIME_NONE; } GST_OBJECT_UNLOCK (dec); if (dec->cinfo.jpeg_color_space == JCS_RGB) { gint i; GstCaps *allowed_caps; + GstVideoInfo tmpinfo; GST_DEBUG_OBJECT (dec, "selecting RGB format"); /* retrieve allowed caps, and find the first one that reasonably maps @@ -1170,7 +1205,7 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc) * and get_pad_template_caps doesn't */ caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad)); } - /* avoid lists of fourcc, etc */ + /* avoid lists of formats, etc */ allowed_caps = gst_caps_normalize (caps); gst_caps_unref (caps); caps = NULL; @@ -1183,10 +1218,11 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc) /* sigh, ds and _parse_caps need fixed caps for parsing, fixate */ gst_pad_fixate_caps (dec->srcpad, caps); GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps); - if (!gst_video_format_parse_caps (caps, &format, NULL, NULL)) + + if (!gst_video_info_from_caps (&tmpinfo, caps)) continue; /* we'll settle for the first (preferred) downstream rgb format */ - if (gst_video_format_is_rgb (format)) + if (GST_VIDEO_INFO_IS_RGB (&tmpinfo)) break; /* default fall-back */ format = GST_VIDEO_FORMAT_RGB; @@ -1194,51 +1230,31 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc) if (caps) gst_caps_unref (caps); gst_caps_unref (allowed_caps); - caps = gst_video_format_new_caps (format, width, height, - dec->framerate_numerator, dec->framerate_denominator, 1, 1); - dec->outsize = gst_video_format_get_size (format, width, height); - /* some format info */ - dec->offset[0] = - gst_video_format_get_component_offset (format, 0, width, height); - dec->offset[1] = - gst_video_format_get_component_offset (format, 1, width, height); - dec->offset[2] = - gst_video_format_get_component_offset (format, 2, width, height); - /* equal for all components */ - dec->stride = gst_video_format_get_row_stride (format, 0, width); - dec->inc = gst_video_format_get_pixel_stride (format, 0); } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) { /* TODO is anything else then 8bit supported in jpeg? */ format = GST_VIDEO_FORMAT_GRAY8; - caps = gst_video_format_new_caps (format, width, height, - dec->framerate_numerator, dec->framerate_denominator, 1, 1); - dec->outsize = gst_video_format_get_size (format, width, height); - dec->offset[0] = - gst_video_format_get_component_offset (format, 0, width, height); - dec->stride = gst_video_format_get_row_stride (format, 0, width); - dec->inc = gst_video_format_get_pixel_stride (format, 0); } else { /* go for plain and simple I420 */ /* TODO other YUV cases ? */ - 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", GST_TYPE_FRACTION, dec->framerate_numerator, - dec->framerate_denominator, NULL); - dec->outsize = I420_SIZE (width, height); + format = GST_VIDEO_FORMAT_I420; } + gst_video_info_set_format (&info, format, width, height); + caps = gst_video_info_to_caps (&info); + 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, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor); gst_pad_set_caps (dec->srcpad, caps); + + dec->info = info; + dec->clrspc = clrspc; + + gst_jpeg_dec_buffer_pool (dec, caps); gst_caps_unref (caps); - dec->caps_width = width; - dec->caps_height = height; - dec->caps_framerate_numerator = dec->framerate_numerator; - dec->caps_framerate_denominator = dec->framerate_denominator; + return TRUE; } static GstFlowReturn @@ -1247,17 +1263,12 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf) GstFlowReturn ret = GST_FLOW_OK; GstJpegDec *dec; GstBuffer *outbuf = NULL; -#ifndef GST_DISABLE_GST_DEBUG - guchar *data; -#endif - guchar *outdata; - guchar *base[3], *last[3]; gint img_len; - guint outsize; gint width, height; gint r_h, r_v; guint code, hdr_ok; GstClockTime timestamp, duration; + GstVideoFrame frame; dec = GST_JPEG_DEC (GST_PAD_PARENT (pad)); @@ -1323,9 +1334,13 @@ again: goto skip_decoding; #ifndef GST_DISABLE_GST_DEBUG - data = (guint8 *) gst_adapter_peek (dec->adapter, 4); - GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1], - data[2], data[3]); + { + guchar data[4]; + + gst_adapter_copy (dec->adapter, data, 0, 4); + GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1], + data[2], data[3]); + } #endif gst_jpeg_dec_fill_input_buffer (&dec->cinfo); @@ -1425,16 +1440,14 @@ again: gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space); - ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE, - dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf); + ret = gst_buffer_pool_acquire_buffer (dec->pool, &outbuf, NULL); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto alloc_failed; - outdata = GST_BUFFER_DATA (outbuf); - outsize = GST_BUFFER_SIZE (outbuf); + if (!gst_video_frame_map (&frame, &dec->info, outbuf, GST_MAP_READWRITE)) + goto invalid_frame; - GST_LOG_OBJECT (dec, "width %d, height %d, buffer size %d, required size %d", - width, height, outsize, dec->outsize); + GST_LOG_OBJECT (dec, "width %d, height %d", width, height); GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts; @@ -1442,10 +1455,9 @@ again: if (GST_CLOCK_TIME_IS_VALID (duration)) { /* use duration from incoming buffer for outgoing buffer */ dec->next_ts += duration; - } else if (dec->framerate_numerator != 0) { - duration = gst_util_uint64_scale (GST_SECOND, - dec->framerate_denominator, dec->framerate_numerator); - dec->next_ts += duration; + } else if (GST_CLOCK_TIME_IS_VALID (dec->duration)) { + duration = dec->duration; + dec->next_ts += dec->duration; } else { duration = GST_CLOCK_TIME_NONE; dec->next_ts = GST_CLOCK_TIME_NONE; @@ -1457,32 +1469,10 @@ again: GST_BUFFER_DURATION (outbuf) = duration; if (dec->cinfo.jpeg_color_space == JCS_RGB) { - base[0] = outdata + dec->offset[0]; - base[1] = outdata + dec->offset[1]; - base[2] = outdata + dec->offset[2]; - gst_jpeg_dec_decode_rgb (dec, base, width, height, dec->inc, dec->stride); + gst_jpeg_dec_decode_rgb (dec, &frame); } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) { - base[0] = outdata + dec->offset[0]; - gst_jpeg_dec_decode_grayscale (dec, base, width, height, dec->inc, - dec->stride); + gst_jpeg_dec_decode_grayscale (dec, &frame); } else { - /* mind the swap, jpeglib outputs blue chroma first - * ensonic: I see no swap? - */ - base[0] = outdata + I420_Y_OFFSET (width, height); - base[1] = outdata + I420_U_OFFSET (width, height); - base[2] = outdata + I420_V_OFFSET (width, height); - - /* make sure we don't make jpeglib write beyond our buffer, - * which might happen if (height % (r_v*DCTSIZE)) != 0 */ - last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1)); - last[1] = - base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) - - 1)); - last[2] = - base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) - - 1)); - GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)", dec->cinfo.rec_outbuf_height); @@ -1497,11 +1487,10 @@ again: || dec->cinfo.comp_info[2].h_samp_factor != 1)) { GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec, "indirect decoding using extra buffer copy"); - gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h, + gst_jpeg_dec_decode_indirect (dec, &frame, r_v, r_h, dec->cinfo.num_components); } else { - ret = gst_jpeg_dec_decode_direct (dec, base, last, width, height); - + ret = gst_jpeg_dec_decode_direct (dec, &frame); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto decode_direct_failed; } @@ -1510,9 +1499,11 @@ again: GST_LOG_OBJECT (dec, "decompressing finished"); jpeg_finish_decompress (&dec->cinfo); + gst_video_frame_unmap (&frame); + /* Clipping */ if (dec->segment.format == GST_FORMAT_TIME) { - gint64 start, stop, clip_start, clip_stop; + guint64 start, stop, clip_start, clip_stop; GST_LOG_OBJECT (dec, "Attempting clipping"); @@ -1618,6 +1609,13 @@ alloc_failed: } goto exit; } +invalid_frame: + { + jpeg_abort_decompress (&dec->cinfo); + gst_buffer_unref (outbuf); + ret = GST_FLOW_OK; + goto exit; + } drop_buffer: { GST_WARNING_OBJECT (dec, "Outgoing buffer is outside configured segment"); @@ -1663,11 +1661,12 @@ gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_QOS:{ + GstQOSType type; GstClockTimeDiff diff; GstClockTime timestamp; gdouble proportion; - gst_event_parse_qos (event, &proportion, &diff, ×tamp); + gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp); gst_jpeg_dec_update_qos (dec, proportion, diff, timestamp); break; } @@ -1684,7 +1683,7 @@ gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event) static gboolean gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event) { - gboolean ret = TRUE; + gboolean ret = TRUE, forward = TRUE; GstJpegDec *dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad)); GST_DEBUG_OBJECT (dec, "event : %s", GST_EVENT_TYPE_NAME (event)); @@ -1702,30 +1701,28 @@ gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event) dec->parse_resync = FALSE; gst_jpeg_dec_reset_qos (dec); break; - case GST_EVENT_NEWSEGMENT:{ - gboolean update; - gdouble rate, applied_rate; - GstFormat format; - gint64 start, stop, position; - - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, - &format, &start, &stop, &position); - - GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT [%" GST_TIME_FORMAT - " - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]", - GST_TIME_ARGS (start), GST_TIME_ARGS (stop), - GST_TIME_ARGS (position)); - - gst_segment_set_newsegment_full (&dec->segment, update, rate, - applied_rate, format, start, stop, position); + case GST_EVENT_SEGMENT: + gst_event_copy_segment (event, &dec->segment); + GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT %" GST_SEGMENT_FORMAT, + &dec->segment); + break; + case GST_EVENT_CAPS: + { + GstCaps *caps; + gst_event_parse_caps (event, &caps); + ret = gst_jpeg_dec_setcaps (dec, caps); + forward = FALSE; break; } default: break; } - ret = gst_pad_push_event (dec->srcpad, event); + if (forward) + ret = gst_pad_push_event (dec->srcpad, event); + else + gst_event_unref (event); return ret; } @@ -1786,11 +1783,9 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_READY_TO_PAUSED: dec->error_count = 0; dec->good_count = 0; - dec->framerate_numerator = 0; - dec->framerate_denominator = 1; - dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0; - dec->caps_width = -1; - dec->caps_height = -1; + dec->in_fps_n = 0; + dec->in_fps_d = 1; + gst_video_info_init (&dec->info); dec->clrspc = -1; dec->packetized = FALSE; dec->next_ts = 0; @@ -1815,6 +1810,11 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition) g_free (dec->cur_buf); dec->cur_buf = NULL; gst_jpeg_dec_free_buffers (dec); + if (dec->pool) { + gst_buffer_pool_set_active (dec->pool, FALSE); + gst_object_unref (dec->pool); + } + dec->pool = NULL; break; default: break; diff --git a/ext/jpeg/gstjpegdec.h b/ext/jpeg/gstjpegdec.h index 7daf7b6..4946ee5 100644 --- a/ext/jpeg/gstjpegdec.h +++ b/ext/jpeg/gstjpegdec.h @@ -90,21 +90,16 @@ struct _GstJpegDec { GstClockTime earliest_time; GstClockTime qos_duration; - /* video state */ - gint framerate_numerator; - gint framerate_denominator; - - /* negotiated state */ - gint caps_framerate_numerator; - gint caps_framerate_denominator; - gint caps_width; - gint caps_height; - gint outsize; - gint clrspc; + /* input state */ + gint in_fps_n; + gint in_fps_d; + + /* negotiated output state */ + GstBufferPool *pool; + GstVideoInfo info; + GstClockTime duration; - gint offset[3]; - gint stride; - gint inc; + gint clrspc; /* parse state */ gint parse_offset; diff --git a/ext/jpeg/gstjpegenc.c b/ext/jpeg/gstjpegenc.c index 655f139..80993e9 100644 --- a/ext/jpeg/gstjpegenc.c +++ b/ext/jpeg/gstjpegenc.c @@ -54,7 +54,6 @@ GST_DEBUG_CATEGORY_STATIC (jpegenc_debug); /* JpegEnc signals and args */ enum { - FRAME_ENCODED, /* FILL ME */ LAST_SIGNAL }; @@ -71,8 +70,8 @@ static void gst_jpegenc_reset (GstJpegEnc * enc); static void gst_jpegenc_finalize (GObject * object); static GstFlowReturn gst_jpegenc_chain (GstPad * pad, GstBuffer * buf); -static gboolean gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_jpegenc_getcaps (GstPad * pad); +static gboolean gst_jpegenc_sink_event (GstPad * pad, GstEvent * event); +static GstCaps *gst_jpegenc_getcaps (GstPad * pad, GstCaps * filter); static void gst_jpegenc_resync (GstJpegEnc * jpegenc); static void gst_jpegenc_set_property (GObject * object, guint prop_id, @@ -82,8 +81,6 @@ static void gst_jpegenc_get_property (GObject * object, guint prop_id, static GstStateChangeReturn gst_jpegenc_change_state (GstElement * element, GstStateChange transition); -static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 }; - #define gst_jpegenc_parent_class parent_class G_DEFINE_TYPE (GstJpegEnc, gst_jpegenc, GST_TYPE_ELEMENT); @@ -121,11 +118,6 @@ gst_jpegenc_class_init (GstJpegEncClass * klass) gobject_class->set_property = gst_jpegenc_set_property; gobject_class->get_property = gst_jpegenc_get_property; - gst_jpegenc_signals[FRAME_ENCODED] = - g_signal_new ("frame-encoded", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstJpegEncClass, frame_encoded), NULL, - NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - g_object_class_install_property (gobject_class, PROP_QUALITY, g_param_spec_int ("quality", "Quality", "Quality of encoding", 0, 100, JPEG_DEFAULT_QUALITY, @@ -160,6 +152,42 @@ gst_jpegenc_class_init (GstJpegEncClass * klass) } static void +ensure_memory (GstJpegEnc * jpegenc) +{ + GstMemory *new_memory; + gsize old_size, desired_size, new_size; + guint8 *new_data; + + old_size = jpegenc->output_size; + if (old_size == 0) + desired_size = jpegenc->bufsize; + else + desired_size = old_size * 2; + + /* Our output memory wasn't big enough. + * Make a new memory that's twice the size, */ + new_memory = gst_allocator_alloc (NULL, desired_size, 3); + new_data = gst_memory_map (new_memory, &new_size, NULL, GST_MAP_READWRITE); + + /* copy previous data if any */ + if (jpegenc->output_mem) { + memcpy (new_data, jpegenc->output_data, old_size); + gst_memory_unmap (jpegenc->output_mem, jpegenc->output_data, + jpegenc->output_size); + gst_memory_unref (jpegenc->output_mem); + } + + /* drop it into place, */ + jpegenc->output_mem = new_memory; + jpegenc->output_data = new_data; + jpegenc->output_size = new_size; + + /* and last, update libjpeg on where to work. */ + jpegenc->jdest.next_output_byte = new_data + old_size; + jpegenc->jdest.free_in_buffer = new_size - old_size; +} + +static void gst_jpegenc_init_destination (j_compress_ptr cinfo) { GST_DEBUG ("gst_jpegenc_chain: init_destination"); @@ -168,34 +196,12 @@ gst_jpegenc_init_destination (j_compress_ptr cinfo) static boolean gst_jpegenc_flush_destination (j_compress_ptr cinfo) { - GstBuffer *overflow_buffer; - guint32 old_buffer_size; GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data); + GST_DEBUG_OBJECT (jpegenc, "gst_jpegenc_chain: flush_destination: buffer too small"); - /* Our output buffer wasn't big enough. - * Make a new buffer that's twice the size, */ - old_buffer_size = GST_BUFFER_SIZE (jpegenc->output_buffer); - - gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad, - GST_BUFFER_OFFSET_NONE, old_buffer_size * 2, - GST_PAD_CAPS (jpegenc->srcpad), &overflow_buffer); - memcpy (GST_BUFFER_DATA (overflow_buffer), - GST_BUFFER_DATA (jpegenc->output_buffer), old_buffer_size); - - gst_buffer_copy_metadata (overflow_buffer, jpegenc->output_buffer, - GST_BUFFER_COPY_TIMESTAMPS); - - /* drop it into place, */ - gst_buffer_unref (jpegenc->output_buffer); - jpegenc->output_buffer = overflow_buffer; - - /* and last, update libjpeg on where to work. */ - jpegenc->jdest.next_output_byte = - GST_BUFFER_DATA (jpegenc->output_buffer) + old_buffer_size; - jpegenc->jdest.free_in_buffer = - GST_BUFFER_SIZE (jpegenc->output_buffer) - old_buffer_size; + ensure_memory (jpegenc); return TRUE; } @@ -206,14 +212,11 @@ gst_jpegenc_term_destination (j_compress_ptr cinfo) GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data); GST_DEBUG_OBJECT (jpegenc, "gst_jpegenc_chain: term_source"); - /* Trim the buffer size and push it. */ - GST_BUFFER_SIZE (jpegenc->output_buffer) = - GST_BUFFER_SIZE (jpegenc->output_buffer) - jpegenc->jdest.free_in_buffer; - - g_signal_emit (G_OBJECT (jpegenc), gst_jpegenc_signals[FRAME_ENCODED], 0); - - jpegenc->last_ret = gst_pad_push (jpegenc->srcpad, jpegenc->output_buffer); - jpegenc->output_buffer = NULL; + /* Trim the buffer size. we will push it in the chain function */ + gst_memory_unmap (jpegenc->output_mem, jpegenc->output_data, + jpegenc->output_size - jpegenc->jdest.free_in_buffer); + jpegenc->output_data = NULL; + jpegenc->output_size = 0; } static void @@ -226,8 +229,8 @@ gst_jpegenc_init (GstJpegEnc * jpegenc) GST_DEBUG_FUNCPTR (gst_jpegenc_chain)); gst_pad_set_getcaps_function (jpegenc->sinkpad, GST_DEBUG_FUNCPTR (gst_jpegenc_getcaps)); - gst_pad_set_setcaps_function (jpegenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_jpegenc_setcaps)); + gst_pad_set_event_function (jpegenc->sinkpad, + GST_DEBUG_FUNCPTR (gst_jpegenc_sink_event)); gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->sinkpad); jpegenc->srcpad = @@ -236,8 +239,7 @@ gst_jpegenc_init (GstJpegEnc * jpegenc) gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->srcpad); /* reset the initial video state */ - jpegenc->width = -1; - jpegenc->height = -1; + gst_video_info_init (&jpegenc->info); /* setup jpeglib */ memset (&jpegenc->cinfo, 0, sizeof (jpegenc->cinfo)); @@ -277,11 +279,7 @@ gst_jpegenc_reset (GstJpegEnc * enc) } } - enc->width = -1; - enc->height = -1; - enc->format = GST_VIDEO_FORMAT_UNKNOWN; - enc->fps_den = enc->par_den = 0; - enc->height = enc->width = 0; + gst_video_info_init (&enc->info); } static void @@ -295,7 +293,7 @@ gst_jpegenc_finalize (GObject * object) } static GstCaps * -gst_jpegenc_getcaps (GstPad * pad) +gst_jpegenc_getcaps (GstPad * pad, GstCaps * filter) { GstJpegEnc *jpegenc = GST_JPEGENC (gst_pad_get_parent (pad)); GstCaps *caps, *othercaps; @@ -306,7 +304,7 @@ gst_jpegenc_getcaps (GstPad * pad) /* we want to proxy properties like width, height and framerate from the other end of the element */ - othercaps = gst_pad_peer_get_caps_reffed (jpegenc->srcpad); + othercaps = gst_pad_peer_get_caps (jpegenc->srcpad, filter); if (othercaps == NULL || gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps)) { caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); @@ -343,59 +341,41 @@ done: } static gboolean -gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps) +gst_jpegenc_setcaps (GstJpegEnc * enc, GstCaps * caps) { - GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad)); - GstVideoFormat format; - gint width, height; - gint fps_num, fps_den; - gint par_num, par_den; + GstVideoInfo info; gint i; GstCaps *othercaps; gboolean ret; + const GstVideoFormatInfo *vinfo; /* get info from caps */ - if (!gst_video_format_parse_caps (caps, &format, &width, &height)) + if (!gst_video_info_from_caps (&info, caps)) goto refuse_caps; - /* optional; pass along if present */ - fps_num = fps_den = -1; - par_num = par_den = -1; - gst_video_parse_caps_framerate (caps, &fps_num, &fps_den); - gst_video_parse_caps_pixel_aspect_ratio (caps, &par_num, &par_den); - - if (width == enc->width && height == enc->height && enc->format == format - && fps_num == enc->fps_num && fps_den == enc->fps_den - && par_num == enc->par_num && par_den == enc->par_den) - return TRUE; /* store input description */ - enc->format = format; - enc->width = width; - enc->height = height; - enc->fps_num = fps_num; - enc->fps_den = fps_den; - enc->par_num = par_num; - enc->par_den = par_den; + enc->info = info; + + vinfo = info.finfo; /* prepare a cached image description */ - enc->channels = 3 + (gst_video_format_has_alpha (format) ? 1 : 0); + enc->channels = 3 + (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vinfo) ? 1 : 0); /* ... but any alpha is disregarded in encoding */ - if (gst_video_format_is_gray (format)) + if (GST_VIDEO_FORMAT_INFO_IS_GRAY (vinfo)) enc->channels = 1; else enc->channels = 3; + enc->h_max_samp = 0; enc->v_max_samp = 0; for (i = 0; i < enc->channels; ++i) { - enc->cwidth[i] = gst_video_format_get_component_width (format, i, width); - enc->cheight[i] = gst_video_format_get_component_height (format, i, height); - enc->offset[i] = gst_video_format_get_component_offset (format, i, width, - height); - enc->stride[i] = gst_video_format_get_row_stride (format, i, width); - enc->inc[i] = gst_video_format_get_pixel_stride (format, i); - enc->h_samp[i] = GST_ROUND_UP_4 (width) / enc->cwidth[i]; + enc->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (&info, i); + enc->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (&info, i); + enc->inc[i] = GST_VIDEO_INFO_COMP_PSTRIDE (&info, i); + + enc->h_samp[i] = GST_ROUND_UP_4 (info.width) / enc->cwidth[i]; enc->h_max_samp = MAX (enc->h_max_samp, enc->h_samp[i]); - enc->v_samp[i] = GST_ROUND_UP_4 (height) / enc->cheight[i]; + enc->v_samp[i] = GST_ROUND_UP_4 (info.height) / enc->cheight[i]; enc->v_max_samp = MAX (enc->v_max_samp, enc->v_samp[i]); } /* samp should only be 1, 2 or 4 */ @@ -411,14 +391,13 @@ gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps) othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad)); gst_caps_set_simple (othercaps, - "width", G_TYPE_INT, enc->width, "height", G_TYPE_INT, enc->height, NULL); - if (enc->fps_den > 0) + "width", G_TYPE_INT, info.width, "height", G_TYPE_INT, info.height, NULL); + if (info.fps_d > 0) gst_caps_set_simple (othercaps, - "framerate", GST_TYPE_FRACTION, enc->fps_num, enc->fps_den, NULL); - if (enc->par_den > 0) + "framerate", GST_TYPE_FRACTION, info.fps_n, info.fps_d, NULL); + if (info.par_d > 0) gst_caps_set_simple (othercaps, - "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_num, enc->par_den, - NULL); + "pixel-aspect-ratio", GST_TYPE_FRACTION, info.par_n, info.par_d, NULL); ret = gst_pad_set_caps (enc->srcpad, othercaps); gst_caps_unref (othercaps); @@ -426,38 +405,64 @@ gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps) if (ret) gst_jpegenc_resync (enc); - gst_object_unref (enc); - return ret; /* ERRORS */ refuse_caps: { GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps); - gst_object_unref (enc); return FALSE; } } +static gboolean +gst_jpegenc_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + res = gst_jpegenc_setcaps (enc, caps); + break; + } + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (enc); + + return res; +} + static void gst_jpegenc_resync (GstJpegEnc * jpegenc) { gint width, height; gint i, j; + const GstVideoFormatInfo *finfo; GST_DEBUG_OBJECT (jpegenc, "resync"); - jpegenc->cinfo.image_width = width = jpegenc->width; - jpegenc->cinfo.image_height = height = jpegenc->height; + finfo = jpegenc->info.finfo; + + jpegenc->cinfo.image_width = width = GST_VIDEO_INFO_WIDTH (&jpegenc->info); + jpegenc->cinfo.image_height = height = GST_VIDEO_INFO_HEIGHT (&jpegenc->info); jpegenc->cinfo.input_components = jpegenc->channels; GST_DEBUG_OBJECT (jpegenc, "width %d, height %d", width, height); - GST_DEBUG_OBJECT (jpegenc, "format %d", jpegenc->format); + GST_DEBUG_OBJECT (jpegenc, "format %d", + GST_VIDEO_INFO_FORMAT (&jpegenc->info)); - if (gst_video_format_is_rgb (jpegenc->format)) { + if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) { GST_DEBUG_OBJECT (jpegenc, "RGB"); jpegenc->cinfo.in_color_space = JCS_RGB; - } else if (gst_video_format_is_gray (jpegenc->format)) { + } else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) { GST_DEBUG_OBJECT (jpegenc, "gray"); jpegenc->cinfo.in_color_space = JCS_GRAYSCALE; } else { @@ -466,7 +471,7 @@ gst_jpegenc_resync (GstJpegEnc * jpegenc) } /* input buffer size as max output */ - jpegenc->bufsize = gst_video_format_get_size (jpegenc->format, width, height); + jpegenc->bufsize = GST_VIDEO_INFO_SIZE (&jpegenc->info); jpeg_set_defaults (&jpegenc->cinfo); jpegenc->cinfo.raw_data_in = TRUE; /* duh, libjpeg maps RGB to YUV ... and don't expect some conversion */ @@ -506,42 +511,41 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf) { GstFlowReturn ret; GstJpegEnc *jpegenc; - guchar *data; - gulong size; - guint height; + guint height, width; guchar *base[3], *end[3]; + guint stride[3]; gint i, j, k; + GstBuffer *outbuf; + GstVideoFrame frame; jpegenc = GST_JPEGENC (GST_OBJECT_PARENT (pad)); - if (G_UNLIKELY (jpegenc->width <= 0 || jpegenc->height <= 0)) + if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&jpegenc->info) == + GST_VIDEO_FORMAT_UNKNOWN)) goto not_negotiated; - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); + if (!gst_video_frame_map (&frame, &jpegenc->info, buf, GST_MAP_READ)) + goto invalid_frame; - GST_LOG_OBJECT (jpegenc, "got buffer of %lu bytes", size); + height = GST_VIDEO_FRAME_HEIGHT (&frame); + width = GST_VIDEO_FRAME_WIDTH (&frame); - ret = - gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad, - GST_BUFFER_OFFSET_NONE, jpegenc->bufsize, GST_PAD_CAPS (jpegenc->srcpad), - &jpegenc->output_buffer); - - if (ret != GST_FLOW_OK) - goto done; - - gst_buffer_copy_metadata (jpegenc->output_buffer, buf, - GST_BUFFER_COPY_TIMESTAMPS); - - height = jpegenc->height; + GST_LOG_OBJECT (jpegenc, "got buffer of %lu bytes", + gst_buffer_get_size (buf)); for (i = 0; i < jpegenc->channels; i++) { - base[i] = data + jpegenc->offset[i]; - end[i] = base[i] + jpegenc->cheight[i] * jpegenc->stride[i]; + base[i] = GST_VIDEO_FRAME_COMP_DATA (&frame, i); + stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i); + end[i] = base[i] + GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i) * stride[i]; } - jpegenc->jdest.next_output_byte = GST_BUFFER_DATA (jpegenc->output_buffer); - jpegenc->jdest.free_in_buffer = GST_BUFFER_SIZE (jpegenc->output_buffer); + jpegenc->output_mem = gst_allocator_alloc (NULL, jpegenc->bufsize, 3); + jpegenc->output_data = + gst_memory_map (jpegenc->output_mem, &jpegenc->output_size, NULL, + GST_MAP_READWRITE); + + jpegenc->jdest.next_output_byte = jpegenc->output_data; + jpegenc->jdest.free_in_buffer = jpegenc->output_size; /* prepare for raw input */ #if JPEG_LIB_VERSION >= 70 @@ -559,8 +563,8 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf) for (k = 0; k < jpegenc->channels; k++) { for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) { jpegenc->line[k][j] = base[k]; - if (base[k] + jpegenc->stride[k] < end[k]) - base[k] += jpegenc->stride[k]; + if (base[k] + stride[k] < end[k]) + base[k] += stride[k]; } } jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line, @@ -581,8 +585,8 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf) src += jpegenc->inc[k]; dst++; } - if (base[k] + jpegenc->stride[k] < end[k]) - base[k] += jpegenc->stride[k]; + if (base[k] + stride[k] < end[k]) + base[k] += stride[k]; } } jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line, @@ -590,22 +594,34 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf) } } - /* This will ensure that gst_jpegenc_term_destination is called; we push - the final output buffer from there */ + /* This will ensure that gst_jpegenc_term_destination is called */ jpeg_finish_compress (&jpegenc->cinfo); GST_LOG_OBJECT (jpegenc, "compressing done"); -done: + outbuf = gst_buffer_new (); + gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1); + gst_buffer_take_memory (outbuf, -1, jpegenc->output_mem); + jpegenc->output_mem = NULL; + + ret = gst_pad_push (jpegenc->srcpad, outbuf); + + gst_video_frame_unmap (&frame); gst_buffer_unref (buf); return ret; -/* ERRORS */ + /* ERRORS */ not_negotiated: { GST_WARNING_OBJECT (jpegenc, "no input format set (no caps on buffer)"); - ret = GST_FLOW_NOT_NEGOTIATED; - goto done; + gst_buffer_unref (buf); + return GST_FLOW_NOT_NEGOTIATED; + } +invalid_frame: + { + GST_WARNING_OBJECT (jpegenc, "invalid frame received"); + gst_buffer_unref (buf); + return GST_FLOW_OK; } } diff --git a/ext/jpeg/gstjpegenc.h b/ext/jpeg/gstjpegenc.h index f7a3ef0..f677887 100644 --- a/ext/jpeg/gstjpegenc.h +++ b/ext/jpeg/gstjpegenc.h @@ -46,8 +46,6 @@ G_BEGIN_DECLS typedef struct _GstJpegEnc GstJpegEnc; typedef struct _GstJpegEncClass GstJpegEncClass; -#define GST_JPEG_ENC_MAX_COMPONENT 4 - struct _GstJpegEnc { GstElement element; @@ -56,20 +54,15 @@ struct _GstJpegEnc GstPad *sinkpad, *srcpad; /* stream/image properties */ - GstVideoFormat format; - gint width; - gint height; + GstVideoInfo info; gint channels; - gint fps_num, fps_den; - gint par_num, par_den; + /* standard video_format indexed */ - gint stride[GST_JPEG_ENC_MAX_COMPONENT]; - gint offset[GST_JPEG_ENC_MAX_COMPONENT]; - gint inc[GST_JPEG_ENC_MAX_COMPONENT]; - gint cwidth[GST_JPEG_ENC_MAX_COMPONENT]; - gint cheight[GST_JPEG_ENC_MAX_COMPONENT]; - gint h_samp[GST_JPEG_ENC_MAX_COMPONENT]; - gint v_samp[GST_JPEG_ENC_MAX_COMPONENT]; + gint inc[GST_VIDEO_MAX_COMPONENTS]; + gint cwidth[GST_VIDEO_MAX_COMPONENTS]; + gint cheight[GST_VIDEO_MAX_COMPONENTS]; + gint h_samp[GST_VIDEO_MAX_COMPONENTS]; + gint v_samp[GST_VIDEO_MAX_COMPONENTS]; gint h_max_samp; gint v_max_samp; gboolean planar; @@ -92,15 +85,14 @@ struct _GstJpegEnc /* cached return state for any problems that may occur in callbacks */ GstFlowReturn last_ret; - GstBuffer *output_buffer; + GstMemory *output_mem; + gpointer output_data; + gsize output_size; }; struct _GstJpegEncClass { GstElementClass parent_class; - - /* signals */ - void (*frame_encoded) (GstElement * element); }; GType gst_jpegenc_get_type (void); -- 2.7.4