diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index a65d2e8632..bac7df2032 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -67,7 +67,8 @@ static GstStaticPadTemplate gst_gdk_pixbuf_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_RGBA) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB") "; " + GST_VIDEO_CAPS_MAKE ("RGBA")) ); static void gst_gdk_pixbuf_set_property (GObject * object, guint prop_id, @@ -77,23 +78,24 @@ static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id, static GstStateChangeReturn gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition); -static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer); +static gboolean gst_gdk_pixbuf_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); #ifdef enable_typefind static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore); #endif -GST_BOILERPLATE (GstGdkPixbuf, gst_gdk_pixbuf, GstElement, GST_TYPE_ELEMENT); +#define gst_gdk_pixbuf_parent_class parent_class +G_DEFINE_TYPE (GstGdkPixbuf, gst_gdk_pixbuf, GST_TYPE_ELEMENT); static gboolean -gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_gdk_pixbuf_sink_setcaps (GstGdkPixbuf * filter, GstCaps * caps) { - GstGdkPixbuf *filter; const GValue *framerate; GstStructure *s; - filter = GST_GDK_PIXBUF (GST_PAD_PARENT (pad)); s = gst_caps_get_structure (caps, 0); if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) { @@ -112,7 +114,7 @@ gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps) } static GstCaps * -gst_gdk_pixbuf_get_capslist (void) +gst_gdk_pixbuf_get_capslist (GstCaps * filter) { GSList *slist; GSList *slist0; @@ -132,7 +134,7 @@ gst_gdk_pixbuf_get_capslist (void) mimetypes = gdk_pixbuf_format_get_mime_types (pixbuf_format); for (mimetype = mimetypes; *mimetype; mimetype++) { - gst_caps_append_structure (capslist, gst_structure_new (*mimetype, NULL)); + gst_caps_append_structure (capslist, gst_structure_new_empty (*mimetype)); } g_strfreev (mimetypes); } @@ -143,29 +145,43 @@ gst_gdk_pixbuf_get_capslist (void) gst_caps_unref (tmpl_caps); gst_caps_unref (capslist); + + if (filter && return_caps) { + GstCaps *temp; + + temp = gst_caps_intersect (return_caps, filter); + gst_caps_unref (return_caps); + return_caps = temp; + } + return return_caps; } -static GstCaps * -gst_gdk_pixbuf_sink_getcaps (GstPad * pad) +static gboolean +gst_gdk_pixbuf_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { - return gst_gdk_pixbuf_get_capslist (); + gboolean res; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + { + GstCaps *filter, *caps; + + gst_query_parse_caps (query, &filter); + caps = gst_gdk_pixbuf_get_capslist (filter); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + + res = TRUE; + break; + } + default: + res = gst_pad_query_default (pad, parent, query); + break; + } + return res; } -static void -gst_gdk_pixbuf_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_gdk_pixbuf_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gdk_pixbuf_sink_template)); - gst_element_class_set_details_simple (element_class, - "GdkPixbuf image decoder", "Codec/Decoder/Image", - "Decodes images in a video stream using GdkPixbuf", - "David A. Schleef , Renato Filho "); -} /* initialize the plugin's class */ static void @@ -187,17 +203,24 @@ gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_change_state); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_gdk_pixbuf_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_gdk_pixbuf_sink_template)); + gst_element_class_set_details_simple (gstelement_class, + "GdkPixbuf image decoder", "Codec/Decoder/Image", + "Decodes images in a video stream using GdkPixbuf", + "David A. Schleef , Renato Filho "); } static void -gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass) +gst_gdk_pixbuf_init (GstGdkPixbuf * filter) { filter->sinkpad = gst_pad_new_from_static_template (&gst_gdk_pixbuf_sink_template, "sink"); - gst_pad_set_setcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_setcaps)); - gst_pad_set_getcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_getcaps)); + gst_pad_set_query_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_query)); gst_pad_set_chain_function (filter->sinkpad, GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_chain)); gst_pad_set_event_function (filter->sinkpad, @@ -213,6 +236,55 @@ gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass) filter->pixbuf_loader = NULL; } +static gboolean +gst_gdk_pixbuf_setup_pool (GstGdkPixbuf * filter, GstVideoInfo * info) +{ + GstCaps *target; + GstQuery *query; + GstBufferPool *pool = NULL; + guint size, min, max, prefix, alignment; + + target = gst_pad_get_current_caps (filter->srcpad); + + /* try to get a bufferpool now */ + /* find a pool for the negotiated caps now */ + query = gst_query_new_allocation (target, TRUE); + + if (gst_pad_peer_query (filter->srcpad, query)) { + /* we got configuration from our peer, parse them */ + gst_query_parse_allocation_params (query, &size, &min, &max, &prefix, + &alignment, &pool); + } else { + size = info->size; + min = max = 0; + prefix = 0; + alignment = 0; + } + + if (pool == NULL) { + GstStructure *config; + + /* 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, target, size, min, max, prefix, + alignment); + gst_buffer_pool_set_config (pool, config); + } + + if (filter->pool) + gst_object_unref (filter->pool); + filter->pool = pool; + + /* and activate */ + gst_buffer_pool_set_active (filter->pool, TRUE); + + gst_caps_unref (target); + + return TRUE; +} + static GstFlowReturn gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) { @@ -225,44 +297,50 @@ gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) GstFlowReturn ret; GstCaps *caps = NULL; gint n_channels; + GstVideoFrame frame; pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader); if (pixbuf == NULL) goto no_pixbuf; - if (filter->image_size == 0) { + if (filter->width == 0) { + GstVideoInfo info; + GstVideoFormat fmt; + filter->width = gdk_pixbuf_get_width (pixbuf); filter->height = gdk_pixbuf_get_height (pixbuf); - filter->rowstride = gdk_pixbuf_get_rowstride (pixbuf); - filter->image_size = filter->rowstride * filter->height; + GST_DEBUG ("Set size to %dx%d", filter->width, filter->height); n_channels = gdk_pixbuf_get_n_channels (pixbuf); switch (n_channels) { case 3: - caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB); + fmt = GST_VIDEO_FORMAT_RGB; break; case 4: - caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA); + fmt = GST_VIDEO_FORMAT_RGBA; break; default: goto channels_not_supported; } - gst_caps_set_simple (caps, - "width", G_TYPE_INT, filter->width, - "height", G_TYPE_INT, filter->height, - "framerate", GST_TYPE_FRACTION, filter->framerate_numerator, - filter->framerate_denominator, NULL); - GST_DEBUG ("Set size to %dx%d", filter->width, filter->height); + gst_video_info_init (&info); + gst_video_info_set_format (&info, fmt, filter->width, filter->height); + info.fps_n = filter->framerate_numerator; + info.fps_d = filter->framerate_denominator; + caps = gst_video_info_to_caps (&info); + + filter->channels = n_channels; + filter->rowstride = GST_VIDEO_INFO_COMP_STRIDE (&info, 0); + filter->info = info; + gst_pad_set_caps (filter->srcpad, caps); gst_caps_unref (caps); + + gst_gdk_pixbuf_setup_pool (filter, &info); } - ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad, - GST_BUFFER_OFFSET_NONE, - filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf); - + ret = gst_buffer_pool_acquire_buffer (filter->pool, &outbuf, NULL); if (ret != GST_FLOW_OK) goto no_buffer; @@ -271,16 +349,19 @@ gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) in_pix = gdk_pixbuf_get_pixels (pixbuf); in_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - out_pix = GST_BUFFER_DATA (outbuf); - /* FIXME, last line might not have rowstride pixels */ + gst_video_frame_map (&frame, &filter->info, outbuf, GST_MAP_WRITE); + out_pix = GST_VIDEO_FRAME_COMP_DATA (&frame, 0); + for (y = 0; y < filter->height; y++) { - memcpy (out_pix, in_pix, filter->rowstride); + memcpy (out_pix, in_pix, filter->width * filter->channels); in_pix += in_rowstride; out_pix += filter->rowstride; } - GST_DEBUG ("pushing... %d bytes", GST_BUFFER_SIZE (outbuf)); + gst_video_frame_unmap (&frame); + + GST_DEBUG ("pushing... %d bytes", gst_buffer_get_size (outbuf)); ret = gst_pad_push (filter->srcpad, outbuf); if (ret != GST_FLOW_OK) @@ -308,15 +389,24 @@ no_buffer: } static gboolean -gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) +gst_gdk_pixbuf_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstFlowReturn res = GST_FLOW_OK; gboolean ret = TRUE; GstGdkPixbuf *pixbuf; - pixbuf = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); + pixbuf = GST_GDK_PIXBUF (parent); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + res = gst_gdk_pixbuf_sink_setcaps (pixbuf, caps); + gst_event_unref (event); + break; + } case GST_EVENT_EOS: if (pixbuf->pixbuf_loader != NULL) { gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); @@ -332,7 +422,7 @@ gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) } } break; - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: case GST_EVENT_FLUSH_STOP: if (pixbuf->pixbuf_loader != NULL) { gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); @@ -345,27 +435,24 @@ gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) } if (res == GST_FLOW_OK) { - ret = gst_pad_event_default (pad, event); + ret = gst_pad_event_default (pad, parent, event); } else { ret = FALSE; } - gst_object_unref (pixbuf); - return ret; } static GstFlowReturn -gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) +gst_gdk_pixbuf_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstGdkPixbuf *filter; GstFlowReturn ret = GST_FLOW_OK; GError *error = NULL; GstClockTime timestamp; - guint8 *data; - guint size; + GstMapInfo map; - filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); + filter = GST_GDK_PIXBUF (parent); timestamp = GST_BUFFER_TIMESTAMP (buf); @@ -378,11 +465,11 @@ gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) if (filter->pixbuf_loader == NULL) filter->pixbuf_loader = gdk_pixbuf_loader_new (); - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); + gst_buffer_map (buf, &map, GST_MAP_READ); - GST_LOG_OBJECT (filter, "Writing buffer size %d", size); - if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, data, size, &error)) + GST_LOG_OBJECT (filter, "Writing buffer size %d", (gint) map.size); + if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, map.data, map.size, + &error)) goto error; /* packetised mode? */ @@ -393,8 +480,8 @@ gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) filter->pixbuf_loader = NULL; } + gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); - gst_object_unref (filter); return ret; @@ -404,8 +491,8 @@ error: GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL), ("gdk_pixbuf_loader_write error: %s", error->message)); g_error_free (error); + gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); - gst_object_unref (filter); return GST_FLOW_ERROR; } } @@ -462,6 +549,10 @@ gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: dec->framerate_numerator = 0; dec->framerate_denominator = 0; + if (dec->pool) { + gst_buffer_pool_set_active (dec->pool, FALSE); + gst_object_replace ((GstObject **) & dec->pool, NULL); + } break; default: break; diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.h b/ext/gdk_pixbuf/gstgdkpixbuf.h index a4c6ee557c..a64b7239cd 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.h +++ b/ext/gdk_pixbuf/gstgdkpixbuf.h @@ -52,7 +52,10 @@ struct _GstGdkPixbuf int width; int height; int rowstride; - unsigned int image_size; + int channels; + + GstVideoInfo info; + GstBufferPool *pool; gint framerate_numerator; gint framerate_denominator;