From 9097da30e833cea1b62f03ebed3634427fc72343 Mon Sep 17 00:00:00 2001 From: Luciana Fujii Pontello Date: Fri, 29 Mar 2013 17:57:12 +0100 Subject: [PATCH] rsvg: Port to 1.0 Also port the decoder to the GstVideoDecoder --- configure.ac | 2 +- ext/rsvg/gstrsvgdec.c | 543 +++++++++++++++------------------------------- ext/rsvg/gstrsvgdec.h | 8 +- ext/rsvg/gstrsvgoverlay.c | 67 +++--- ext/rsvg/gstrsvgoverlay.h | 5 +- 5 files changed, 212 insertions(+), 413 deletions(-) diff --git a/configure.ac b/configure.ac index 72d79dc..9f98cc6 100644 --- a/configure.ac +++ b/configure.ac @@ -326,7 +326,7 @@ GST_PLUGINS_NONPORTED=" aiff \ linsys vcd \ apexsink cdaudio dc1394 dirac directfb \ gsettings ladspa \ - musepack musicbrainz nas neon ofa openal rsvg sdl sndfile timidity \ + musepack musicbrainz nas neon ofa openal sdl sndfile timidity \ directdraw direct3d9 acm wininet \ xvid lv2 teletextdec sndio" AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/ext/rsvg/gstrsvgdec.c b/ext/rsvg/gstrsvgdec.c index fb9cf2f..ce32983 100644 --- a/ext/rsvg/gstrsvgdec.c +++ b/ext/rsvg/gstrsvgdec.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <2009> Sebastian Dröge + * Copyright (C) <2013> Luciana Fujii * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -45,37 +46,42 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_CAPS ("image/svg+xml; image/svg")); #if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_BGRA +#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_MAKE ("BGRA") +#define GST_RSVG_VIDEO_FORMAT GST_VIDEO_FORMAT_BGRA #else -#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_ARGB +#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_MAKE ("ARGB") +#define GST_RSVG_VIDEO_FORMAT GST_VIDEO_FORMAT_ARGB #endif static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_RSVG_VIDEO_CAPS)); -GST_BOILERPLATE (GstRsvgDec, gst_rsvg_dec, GstElement, GST_TYPE_ELEMENT); +#define gst_rsv_dec_parent_class parent_class +G_DEFINE_TYPE (GstRsvgDec, gst_rsvg_dec, GST_TYPE_VIDEO_DECODER); -static void gst_rsvg_dec_reset (GstRsvgDec * rsvg); +static gboolean gst_rsvg_dec_reset (GstVideoDecoder * decoder, gboolean hard); -static GstFlowReturn gst_rsvg_dec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_rsvg_dec_sink_set_caps (GstPad * pad, GstCaps * caps); -static gboolean gst_rsvg_dec_sink_event (GstPad * pad, GstEvent * event); - -static gboolean gst_rsvg_dec_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_rsvg_dec_src_query (GstPad * pad, GstQuery * query); -static const GstQueryType *gst_rsvg_dec_src_query_type (GstPad * pad); -static gboolean gst_rsvg_dec_src_set_caps (GstPad * pad, GstCaps * caps); - -static GstStateChangeReturn gst_rsvg_dec_change_state (GstElement * element, - GstStateChange transition); +static gboolean gst_rsvg_dec_stop (GstVideoDecoder * decoder); +static gboolean gst_rsvg_dec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state); +static GstFlowReturn gst_rsvg_dec_parse (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos); +static GstFlowReturn gst_rsvg_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame); +static GstFlowReturn gst_rsvg_decode_image (GstRsvgDec * rsvg, + GstBuffer * buffer, GstVideoCodecFrame * frame); static void gst_rsvg_dec_finalize (GObject * object); static void -gst_rsvg_dec_base_init (gpointer g_class) +gst_rsvg_dec_class_init (GstRsvgDecClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (rsvgdec_debug, "rsvgdec", 0, "RSVG decoder"); gst_element_class_set_static_metadata (element_class, "SVG image decoder", "Codec/Decoder/Image", @@ -86,70 +92,46 @@ gst_rsvg_dec_base_init (gpointer g_class) gst_static_pad_template_get (&sink_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); + + gobject_class->finalize = gst_rsvg_dec_finalize; + video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_rsvg_dec_stop); + video_decoder_class->reset = GST_DEBUG_FUNCPTR (gst_rsvg_dec_reset); + video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_rsvg_dec_set_format); + video_decoder_class->parse = GST_DEBUG_FUNCPTR (gst_rsvg_dec_parse); + video_decoder_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_rsvg_dec_handle_frame); } static void -gst_rsvg_dec_class_init (GstRsvgDecClass * klass) +dec_reset (GstRsvgDec * rsvg) { - GstElementClass *element_class = (GstElementClass *) klass; - GObjectClass *gobject_class = (GObjectClass *) klass; - - GST_DEBUG_CATEGORY_INIT (rsvgdec_debug, "rsvgdec", 0, "RSVG decoder"); - - gobject_class->finalize = gst_rsvg_dec_finalize; - element_class->change_state = GST_DEBUG_FUNCPTR (gst_rsvg_dec_change_state); + rsvg->fps_n = 0; + rsvg->fps_d = 1; } static void -gst_rsvg_dec_init (GstRsvgDec * rsvg, GstRsvgDecClass * klass) +gst_rsvg_dec_init (GstRsvgDec * rsvg) { - rsvg->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_setcaps_function (rsvg->sinkpad, gst_rsvg_dec_sink_set_caps); - gst_pad_set_event_function (rsvg->sinkpad, gst_rsvg_dec_sink_event); - gst_pad_set_chain_function (rsvg->sinkpad, gst_rsvg_dec_chain); - gst_element_add_pad (GST_ELEMENT (rsvg), rsvg->sinkpad); - - rsvg->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_set_event_function (rsvg->srcpad, gst_rsvg_dec_src_event); - gst_pad_set_query_function (rsvg->srcpad, gst_rsvg_dec_src_query); - gst_pad_set_query_type_function (rsvg->srcpad, gst_rsvg_dec_src_query_type); - gst_pad_set_setcaps_function (rsvg->srcpad, gst_rsvg_dec_src_set_caps); - gst_element_add_pad (GST_ELEMENT (rsvg), rsvg->srcpad); - - rsvg->adapter = gst_adapter_new (); - - gst_rsvg_dec_reset (rsvg); + GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg); + gst_video_decoder_set_packetized (decoder, FALSE); + dec_reset (rsvg); } static void gst_rsvg_dec_finalize (GObject * object) { - GstRsvgDec *rsvg = GST_RSVG_DEC (object); - - if (rsvg->adapter) { - g_object_unref (rsvg->adapter); - rsvg->adapter = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); + G_OBJECT_CLASS (gst_rsvg_dec_parent_class)->finalize (object); } -static void -gst_rsvg_dec_reset (GstRsvgDec * dec) + +static gboolean +gst_rsvg_dec_reset (GstVideoDecoder * decoder, gboolean hard) { - gst_adapter_clear (dec->adapter); - dec->width = dec->height = 0; - dec->fps_n = 0; - dec->fps_d = 1; - dec->first_timestamp = GST_CLOCK_TIME_NONE; - dec->frame_count = 0; - - gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED); - dec->need_newsegment = TRUE; - - g_list_foreach (dec->pending_events, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->pending_events); - dec->pending_events = NULL; + GstRsvgDec *dec = GST_RSVG_DEC (decoder); + + dec_reset (dec); + + return TRUE; } #define CAIRO_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \ @@ -183,9 +165,10 @@ gst_rsvg_decode_unpremultiply (guint8 * data, gint width, gint height) } static GstFlowReturn -gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size, - GstBuffer ** buffer) +gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer, + GstVideoCodecFrame * frame) { + GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg); GstFlowReturn ret = GST_FLOW_OK; cairo_t *cr; cairo_surface_t *surface; @@ -193,10 +176,17 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size, GError *error = NULL; RsvgDimensionData dimension; gdouble scalex, scaley; + GstMapInfo minfo; + GstVideoFrame vframe; + GstVideoCodecState *output_state; GST_LOG_OBJECT (rsvg, "parsing svg"); - handle = rsvg_handle_new_from_data (data, size, &error); + if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) { + GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); + return GST_FLOW_ERROR; + } + handle = rsvg_handle_new_from_data (minfo.data, minfo.size, &error); if (!handle) { GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message); g_error_free (error); @@ -204,82 +194,45 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size, } rsvg_handle_get_dimensions (handle, &dimension); - if (rsvg->width != dimension.width || rsvg->height != dimension.height) { - GstCaps *caps1, *caps2, *caps3; - GstStructure *s; - - GST_LOG_OBJECT (rsvg, "resolution changed, updating caps"); - - caps1 = gst_caps_copy (gst_pad_get_pad_template_caps (rsvg->srcpad)); - caps2 = gst_pad_peer_get_caps (rsvg->srcpad); - if (caps2) { - caps3 = gst_caps_intersect (caps1, caps2); - gst_caps_unref (caps1); - gst_caps_unref (caps2); - caps1 = caps3; - caps3 = NULL; - } - - if (gst_caps_is_empty (caps1)) { - GST_ERROR_OBJECT (rsvg, "Unable to negotiate a format"); - gst_caps_unref (caps1); - g_object_unref (handle); - return GST_FLOW_NOT_NEGOTIATED; - } - caps2 = gst_caps_copy (gst_pad_get_pad_template_caps (rsvg->srcpad)); - s = gst_caps_get_structure (caps2, 0); - gst_structure_set (s, "width", G_TYPE_INT, dimension.width, "height", - G_TYPE_INT, dimension.height, "framerate", GST_TYPE_FRACTION, 0, 1, - NULL); - caps3 = gst_caps_intersect (caps1, caps2); - if (!gst_caps_is_empty (caps3)) { - gst_caps_truncate (caps3); - gst_pad_set_caps (rsvg->srcpad, caps3); - gst_caps_unref (caps1); - gst_caps_unref (caps2); - gst_caps_unref (caps3); - rsvg->width = dimension.width; - rsvg->height = dimension.height; - } else { - gst_caps_unref (caps2); - gst_caps_unref (caps3); - gst_caps_truncate (caps1); - - s = gst_caps_get_structure (caps1, 0); - gst_structure_set (s, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); - - if (!gst_caps_is_fixed (caps1) - && (!gst_structure_fixate_field_nearest_int (s, "width", - dimension.width) - || !gst_structure_fixate_field_nearest_int (s, "height", - dimension.height))) { - g_object_unref (handle); - GST_ERROR_OBJECT (rsvg, "Failed to fixate caps"); - return GST_FLOW_NOT_NEGOTIATED; - } - gst_pad_set_caps (rsvg->srcpad, caps1); - gst_structure_get_int (s, "width", &rsvg->width); - gst_structure_get_int (s, "height", &rsvg->height); - gst_caps_unref (caps1); - } + output_state = gst_video_decoder_get_output_state (decoder); + if ((output_state == NULL) + || GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width + || GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { + + /* Create the output state */ + gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT, + dimension.width, dimension.height, rsvg->input_state); + if (output_state) + gst_video_codec_state_unref (output_state); + output_state = gst_video_decoder_get_output_state (decoder); } - if ((ret = gst_pad_alloc_buffer_and_set_caps (rsvg->srcpad, - GST_BUFFER_OFFSET_NONE, - rsvg->width * rsvg->height * 4, - GST_PAD_CAPS (rsvg->srcpad), buffer)) != GST_FLOW_OK) { + ret = gst_video_decoder_allocate_output_frame (decoder, frame); + + if (ret != GST_FLOW_OK) { g_object_unref (handle); GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s", gst_flow_get_name (ret)); return ret; } - GST_LOG_OBJECT (rsvg, "render image at %d x %d", rsvg->height, rsvg->width); + GST_LOG_OBJECT (rsvg, "render image at %d x %d", + GST_VIDEO_INFO_HEIGHT (&output_state->info), + GST_VIDEO_INFO_WIDTH (&output_state->info)); + + if (!gst_video_frame_map (&vframe, + &gst_video_decoder_get_output_state (decoder)->info, + frame->output_buffer, GST_MAP_READWRITE)) { + GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); + return GST_FLOW_ERROR; + } surface = - cairo_image_surface_create_for_data (GST_BUFFER_DATA (*buffer), - CAIRO_FORMAT_ARGB32, rsvg->width, rsvg->height, rsvg->width * 4); + cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&vframe, + 0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (&vframe), + GST_VIDEO_FRAME_HEIGHT (&vframe), GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, + 0)); cr = cairo_create (surface); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); @@ -289,11 +242,15 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size, cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); scalex = scaley = 1.0; - if (rsvg->width != dimension.width) { - scalex = ((gdouble) rsvg->width) / ((gdouble) dimension.width); + if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) { + scalex = + ((gdouble) GST_VIDEO_INFO_WIDTH (&output_state->info)) / + ((gdouble) dimension.width); } - if (rsvg->height != dimension.height) { - scaley = ((gdouble) rsvg->height) / ((gdouble) dimension.height); + if (GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { + scaley = + ((gdouble) GST_VIDEO_INFO_HEIGHT (&output_state->info)) / + ((gdouble) dimension.height); } cairo_scale (cr, scalex, scaley); rsvg_handle_render_cairo (handle, cr); @@ -303,273 +260,127 @@ gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size, cairo_surface_destroy (surface); /* Now unpremultiply Cairo's ARGB to match GStreamer's */ - gst_rsvg_decode_unpremultiply (GST_BUFFER_DATA (*buffer), rsvg->width, - rsvg->height); + gst_rsvg_decode_unpremultiply (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0), + GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe)); + + gst_video_codec_state_unref (output_state); + gst_buffer_unmap (buffer, &minfo); + gst_video_frame_unmap (&vframe); return ret; } + +static gboolean +gst_rsvg_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state) +{ + GstRsvgDec *rsvg = GST_RSVG_DEC (decoder); + GstVideoInfo *info = &state->info; + + if (rsvg->input_state) + gst_video_codec_state_unref (rsvg->input_state); + rsvg->input_state = gst_video_codec_state_ref (state); + + /* Create the output state */ + gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT, + GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), + rsvg->input_state); + + return TRUE; +} + static GstFlowReturn -gst_rsvg_dec_chain (GstPad * pad, GstBuffer * buffer) +gst_rsvg_dec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame, + GstAdapter * adapter, gboolean at_eos) { - GstRsvgDec *rsvg = GST_RSVG_DEC (GST_PAD_PARENT (pad)); + GstRsvgDec *rsvg = GST_RSVG_DEC (decoder); gboolean completed = FALSE; const guint8 *data; guint size; - gboolean ret = GST_FLOW_OK; - - /* first_timestamp is used slightly differently where a framerate - is given or not. - If there is a frame rate, it will be used as a base. - If there is not, it will be used to keep track of the timestamp - of the first buffer, to be used as the timestamp of the output - buffer. When a buffer is output, first timestamp will resync to - the next buffer's timestamp. */ - if (rsvg->first_timestamp == GST_CLOCK_TIME_NONE) { - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) - rsvg->first_timestamp = GST_BUFFER_TIMESTAMP (buffer); - else if (rsvg->fps_n != 0) - rsvg->first_timestamp = 0; - } + guint i; - gst_adapter_push (rsvg->adapter, buffer); - - size = gst_adapter_available (rsvg->adapter); + GST_LOG_OBJECT (rsvg, "parse start"); + size = gst_adapter_available (adapter); /* "" */ - while (size >= 5 + 6 && ret == GST_FLOW_OK) { - guint i; - - data = gst_adapter_peek (rsvg->adapter, size); - for (i = size - 6; i >= 5; i--) { - if (memcmp (data + i, "", 6) == 0) { - completed = TRUE; - size = i + 6; - break; - } - } - - if (completed) { - GstBuffer *outbuf = NULL; - - GST_LOG_OBJECT (rsvg, "have complete svg of %u bytes", size); - - data = gst_adapter_peek (rsvg->adapter, size); - - ret = gst_rsvg_decode_image (rsvg, data, size, &outbuf); - if (ret != GST_FLOW_OK) - break; - - - if (rsvg->first_timestamp != GST_CLOCK_TIME_NONE) { - GST_BUFFER_TIMESTAMP (outbuf) = rsvg->first_timestamp; - GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - if (GST_BUFFER_DURATION_IS_VALID (buffer)) { - GstClockTime end = - GST_BUFFER_TIMESTAMP_IS_VALID (buffer) ? - GST_BUFFER_TIMESTAMP (buffer) : rsvg->first_timestamp; - end += GST_BUFFER_DURATION (buffer); - GST_BUFFER_DURATION (outbuf) = end - GST_BUFFER_TIMESTAMP (outbuf); - } - if (rsvg->fps_n == 0) { - rsvg->first_timestamp = GST_CLOCK_TIME_NONE; - } else { - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, - rsvg->fps_n * GST_SECOND); - } - } else if (rsvg->fps_n != 0) { - GST_BUFFER_TIMESTAMP (outbuf) = - rsvg->first_timestamp + gst_util_uint64_scale (rsvg->frame_count, - rsvg->fps_d, rsvg->fps_n * GST_SECOND); - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, - rsvg->fps_n * GST_SECOND); - } else { - GST_BUFFER_TIMESTAMP (outbuf) = rsvg->first_timestamp; - GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - } - rsvg->frame_count++; + if (size < 5 + 6) + return GST_VIDEO_DECODER_FLOW_NEED_DATA; - if (rsvg->need_newsegment) { - gst_pad_push_event (rsvg->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); - rsvg->need_newsegment = FALSE; - } - - if (rsvg->pending_events) { - GList *l; - - for (l = rsvg->pending_events; l; l = l->next) - gst_pad_push_event (rsvg->srcpad, l->data); - g_list_free (rsvg->pending_events); - rsvg->pending_events = NULL; + data = gst_adapter_map (adapter, size); + if (data == NULL) { + GST_ERROR_OBJECT (rsvg, "Unable to map memory"); + return GST_FLOW_ERROR; + } + for (i = 0; i < size - 4; i++) { + if (memcmp (data + i, "srcpad, outbuf); - if (ret != GST_FLOW_OK) - break; - - gst_adapter_flush (rsvg->adapter, size); - size = gst_adapter_available (rsvg->adapter); - continue; - } else { break; } } + /* If start wasn't found: */ + if (i == size - 4) { + gst_adapter_flush (adapter, size - 4); + return GST_VIDEO_DECODER_FLOW_NEED_DATA; + } - return GST_FLOW_OK; -} - -static gboolean -gst_rsvg_dec_sink_set_caps (GstPad * pad, GstCaps * caps) -{ - GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); - gboolean ret = TRUE; - GstStructure *s = gst_caps_get_structure (caps, 0); - - gst_structure_get_fraction (s, "framerate", &rsvg->fps_n, &rsvg->fps_d); - - gst_object_unref (rsvg); - - return ret; -} - -static gboolean -gst_rsvg_dec_sink_event (GstPad * pad, GstEvent * event) -{ - GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); - gboolean res = FALSE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - gdouble rate, arate; - gboolean update; - gint64 start, stop, position; - GstFormat fmt; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt, - &start, &stop, &position); - - gst_segment_set_newsegment_full (&rsvg->segment, update, rate, arate, - fmt, start, stop, position); - - if (fmt == GST_FORMAT_TIME) { - rsvg->need_newsegment = FALSE; - res = gst_pad_push_event (rsvg->srcpad, event); - } else { - gst_event_unref (event); - res = TRUE; - } + for (i = size - 6; i >= 5; i--) { + if (memcmp (data + i, "", 6) == 0) { + completed = TRUE; + size = i + 6; break; } - case GST_EVENT_EOS: - case GST_EVENT_FLUSH_STOP: - gst_adapter_clear (rsvg->adapter); - /* fall through */ - case GST_EVENT_FLUSH_START: - res = gst_pad_push_event (rsvg->srcpad, event); - break; - default: - if (GST_PAD_CAPS (rsvg->srcpad)) { - res = gst_pad_push_event (rsvg->srcpad, event); - } else { - res = TRUE; - rsvg->pending_events = g_list_append (rsvg->pending_events, event); - } - break; } - gst_object_unref (rsvg); + if (completed) { - return res; -} + GST_LOG_OBJECT (rsvg, "have complete svg of %u bytes", size); -static gboolean -gst_rsvg_dec_src_event (GstPad * pad, GstEvent * event) -{ - GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); - gboolean res = FALSE; - - switch (GST_EVENT_TYPE (event)) { - default: - res = gst_pad_push_event (rsvg->sinkpad, event); - break; + gst_video_decoder_add_to_frame (decoder, size); + return gst_video_decoder_have_frame (decoder); } - - gst_object_unref (rsvg); - - return res; + return GST_VIDEO_DECODER_FLOW_NEED_DATA; } -static const GstQueryType * -gst_rsvg_dec_src_query_type (GstPad * pad) -{ - static const GstQueryType query_types[] = { - (GstQueryType) 0 - }; - - return query_types; -} - -static gboolean -gst_rsvg_dec_src_query (GstPad * pad, GstQuery * query) +static GstFlowReturn +gst_rsvg_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame) { - GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); - gboolean res = TRUE; + GstRsvgDec *rsvg = GST_RSVG_DEC (decoder); + gboolean ret; - switch (GST_QUERY_TYPE (query)) { + ret = gst_rsvg_decode_image (rsvg, frame->input_buffer, frame); + switch (ret) { + case GST_FLOW_OK: + ret = gst_video_decoder_finish_frame (decoder, frame); + break; default: - res = gst_pad_query_default (pad, query); + gst_video_codec_frame_unref (frame); break; } - gst_object_unref (rsvg); - - return res; -} - -static gboolean -gst_rsvg_dec_src_set_caps (GstPad * pad, GstCaps * caps) -{ - GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); - gboolean ret = TRUE; - GstStructure *s = gst_caps_get_structure (caps, 0); - - ret &= gst_structure_get_int (s, "width", &rsvg->width); - ret &= gst_structure_get_int (s, "height", &rsvg->height); - - gst_object_unref (rsvg); - + GST_LOG_OBJECT (rsvg, "Handle frame done"); return ret; } -static GstStateChangeReturn -gst_rsvg_dec_change_state (GstElement * element, GstStateChange transition) +static gboolean +gst_rsvg_dec_stop (GstVideoDecoder * decoder) { - GstStateChangeReturn res; - GstRsvgDec *dec = GST_RSVG_DEC (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; + GstRsvgDec *rsvg = GST_RSVG_DEC (decoder); + if (rsvg->input_state) { + gst_video_codec_state_unref (rsvg->input_state); + rsvg->input_state = NULL; } - res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (res == GST_STATE_CHANGE_FAILURE) - return res; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_rsvg_dec_reset (dec); - break; - default: - break; - } + gst_rsvg_dec_reset (decoder, TRUE); - return res; + return TRUE; } diff --git a/ext/rsvg/gstrsvgdec.h b/ext/rsvg/gstrsvgdec.h index ab9dc33..8f35fee 100644 --- a/ext/rsvg/gstrsvgdec.h +++ b/ext/rsvg/gstrsvgdec.h @@ -47,19 +47,19 @@ typedef struct _GstRsvgDecClass GstRsvgDecClass; struct _GstRsvgDec { - GstElement element; + GstVideoDecoder decoder; GstPad *sinkpad; GstPad *srcpad; - gint width, height; - GList *pending_events; gint fps_n, fps_d; GstClockTime first_timestamp; guint64 frame_count; + GstVideoCodecState *input_state; + GstSegment segment; gboolean need_newsegment; @@ -68,7 +68,7 @@ struct _GstRsvgDec struct _GstRsvgDecClass { - GstElementClass parent_class; + GstVideoDecoderClass parent_class; }; GType gst_rsvg_dec_get_type (void); diff --git a/ext/rsvg/gstrsvgoverlay.c b/ext/rsvg/gstrsvgoverlay.c index 0881725..caf23bf 100644 --- a/ext/rsvg/gstrsvgoverlay.c +++ b/ext/rsvg/gstrsvgoverlay.c @@ -1,5 +1,7 @@ /* GStreamer * Copyright (C) 2010 Olivier Aubert + * Copyright (C) 2013 Collabora Ltda + * Author: Luciana Fujii Pontello * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -66,7 +68,6 @@ #include #include -#include enum { @@ -96,9 +97,9 @@ enum } G_STMT_END #if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_BGRA +#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_MAKE ("BGRA") #else -#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_ARGB +#define GST_RSVG_VIDEO_CAPS GST_VIDEO_CAPS_MAKE ("ARGB") #endif static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", @@ -120,8 +121,8 @@ static GstStaticPadTemplate data_sink_template = GST_PAD_ALWAYS, GST_STATIC_CAPS ("image/svg+xml; image/svg; text/plain")); -GST_BOILERPLATE (GstRsvgOverlay, gst_rsvg_overlay, GstVideoFilter, - GST_TYPE_VIDEO_FILTER); +#define gst_rsv_overlay_parent_class parent_class +G_DEFINE_TYPE (GstRsvgOverlay, gst_rsvg_overlay, GST_TYPE_VIDEO_FILTER); static void gst_rsvg_overlay_finalize (GObject * object); @@ -304,7 +305,8 @@ gst_rsvg_overlay_get_property (GObject * object, guint prop_id, GValue * value, } static GstFlowReturn -gst_rsvg_overlay_data_sink_chain (GstPad * pad, GstBuffer * buffer) +gst_rsvg_overlay_data_sink_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (GST_PAD_PARENT (pad)); @@ -313,7 +315,8 @@ gst_rsvg_overlay_data_sink_chain (GstPad * pad, GstBuffer * buffer) } static gboolean -gst_rsvg_overlay_data_sink_event (GstPad * pad, GstEvent * event) +gst_rsvg_overlay_data_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (GST_PAD_PARENT (pad)); @@ -351,20 +354,11 @@ gst_rsvg_overlay_data_sink_event (GstPad * pad, GstEvent * event) return TRUE; } -static gboolean -gst_rsvg_overlay_set_caps (GstBaseTransform * btrans, GstCaps * incaps, - GstCaps * outcaps) -{ - GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); - - return G_LIKELY (gst_video_format_parse_caps (incaps, - &overlay->caps_format, &overlay->caps_width, &overlay->caps_height)); -} - static GstFlowReturn -gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) +gst_rsvg_overlay_transform_frame_ip (GstVideoFilter * vfilter, + GstVideoFrame * frame) { - GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); + GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (vfilter); cairo_surface_t *surface; cairo_t *cr; double applied_x_offset = (double) overlay->x_offset; @@ -379,9 +373,9 @@ gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) } surface = - cairo_image_surface_create_for_data (GST_BUFFER_DATA (buf), - CAIRO_FORMAT_ARGB32, overlay->caps_width, overlay->caps_height, - overlay->caps_width * 4); + cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (frame, + 0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (frame), + GST_VIDEO_FRAME_HEIGHT (frame), GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0)); if (G_UNLIKELY (!surface)) return GST_FLOW_ERROR; @@ -393,16 +387,18 @@ gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) /* Compute relative dimensions if absolute dimensions are not set */ if (!applied_x_offset && overlay->x_relative) { - applied_x_offset = overlay->x_relative * overlay->caps_width; + applied_x_offset = overlay->x_relative * GST_VIDEO_FRAME_WIDTH (frame); } if (!applied_y_offset && overlay->y_relative) { - applied_y_offset = overlay->y_relative * overlay->caps_height; + applied_y_offset = overlay->y_relative * GST_VIDEO_FRAME_HEIGHT (frame); } if (!applied_width && overlay->width_relative) { - applied_width = (int) (overlay->width_relative * overlay->caps_width); + applied_width = + (int) (overlay->width_relative * GST_VIDEO_FRAME_WIDTH (frame)); } if (!applied_height && overlay->height_relative) { - applied_height = (int) (overlay->height_relative * overlay->caps_height); + applied_height = + (int) (overlay->height_relative * GST_VIDEO_FRAME_HEIGHT (frame)); } if (applied_x_offset || applied_y_offset) { @@ -447,8 +443,11 @@ gst_rsvg_overlay_stop (GstBaseTransform * btrans) } static void -gst_rsvg_overlay_base_init (gpointer klass) +gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass) { + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass); + GstVideoFilterClass *videofilter_class = GST_VIDEO_FILTER_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_add_pad_template (element_class, @@ -462,13 +461,6 @@ gst_rsvg_overlay_base_init (gpointer klass) "Filter/Editor/Video", "Overlays SVG graphics over a video stream", "Olivier Aubert "); -} - -static void -gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass); gobject_class->set_property = gst_rsvg_overlay_set_property; gobject_class->get_property = gst_rsvg_overlay_get_property; @@ -519,14 +511,13 @@ gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass) "Specify a height relative to the display size.", -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - basetransform_class->set_caps = gst_rsvg_overlay_set_caps; - basetransform_class->transform_ip = gst_rsvg_overlay_transform_ip; + videofilter_class->transform_frame_ip = gst_rsvg_overlay_transform_frame_ip; basetransform_class->stop = gst_rsvg_overlay_stop; basetransform_class->passthrough_on_same_caps = FALSE; } static void -gst_rsvg_overlay_init (GstRsvgOverlay * overlay, GstRsvgOverlayClass * klass) +gst_rsvg_overlay_init (GstRsvgOverlay * overlay) { overlay->x_offset = 0; overlay->y_offset = 0; @@ -556,5 +547,5 @@ gst_rsvg_overlay_finalize (GObject * object) g_object_unref (overlay->adapter); - G_OBJECT_CLASS (parent_class)->finalize (object); + G_OBJECT_CLASS (gst_rsvg_overlay_parent_class)->finalize (object); } diff --git a/ext/rsvg/gstrsvgoverlay.h b/ext/rsvg/gstrsvgoverlay.h index b853b5d..f553a1a 100644 --- a/ext/rsvg/gstrsvgoverlay.h +++ b/ext/rsvg/gstrsvgoverlay.h @@ -21,6 +21,7 @@ #define __GST_RSVG_OVERLAY_H__ #include +#include #include #include #include @@ -63,10 +64,6 @@ struct _GstRsvgOverlay float width_relative; float height_relative; - GstVideoFormat caps_format; - int caps_width; - int caps_height; - GstPad *data_sinkpad; GstAdapter *adapter; }; -- 2.7.4