#endif
#include <gst/gst.h>
#include <gst/video/video.h>
-#include <gst/controller/gstcontroller.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
enum
{
ARG_0,
- ARG_SILENT /* FIXME 0.11: remove */
};
static GstStaticPadTemplate gst_gdk_pixbuf_sink_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,
- const GValue * value, GParamSpec * pspec);
-static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
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) {
- filter->framerate_numerator = gst_value_get_fraction_numerator (framerate);
- filter->framerate_denominator =
- gst_value_get_fraction_denominator (framerate);
+ filter->in_fps_n = gst_value_get_fraction_numerator (framerate);
+ filter->in_fps_d = gst_value_get_fraction_denominator (framerate);
GST_DEBUG_OBJECT (filter, "got framerate of %d/%d fps => packetized mode",
- filter->framerate_numerator, filter->framerate_denominator);
+ filter->in_fps_n, filter->in_fps_d);
} else {
- filter->framerate_numerator = 0;
- filter->framerate_denominator = 1;
+ filter->in_fps_n = 0;
+ filter->in_fps_d = 1;
GST_DEBUG_OBJECT (filter, "no framerate, assuming single image");
}
}
static GstCaps *
-gst_gdk_pixbuf_get_capslist (void)
+gst_gdk_pixbuf_get_capslist (GstCaps * filter)
{
GSList *slist;
GSList *slist0;
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);
}
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;
-static void
-gst_gdk_pixbuf_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *filter, *caps;
- gst_element_class_add_static_pad_template (element_class,
- &gst_gdk_pixbuf_src_template);
- gst_element_class_add_static_pad_template (element_class,
- &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 <ds@schleef.org>, Renato Filho <renato.filho@indt.org.br>");
+ 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;
}
+
/* initialize the plugin's class */
static void
gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass)
{
- GObjectClass *gobject_class;
GstElementClass *gstelement_class;
- gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gobject_class->set_property = gst_gdk_pixbuf_set_property;
- gobject_class->get_property = gst_gdk_pixbuf_get_property;
-
- g_object_class_install_property (gobject_class, ARG_SILENT,
- g_param_spec_boolean ("silent", "Silent",
- "Produce verbose output ? (deprecated)", FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
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 <ds@schleef.org>, Renato Filho <renato.filho@indt.org.br>");
}
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,
filter->pixbuf_loader = NULL;
}
+static gboolean
+gst_gdk_pixbuf_setup_pool (GstGdkPixbuf * filter, GstVideoInfo * info)
+{
+ GstCaps *target;
+ GstQuery *query;
+ GstBufferPool *pool;
+ GstStructure *config;
+ guint size, min, max;
+
+ 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)) {
+ /* not a problem, we use the query defaults */
+ GST_DEBUG_OBJECT (filter, "ALLOCATION query failed");
+ }
+
+ if (gst_query_get_n_allocation_pools (query) > 0) {
+ /* we got configuration from our peer, parse them */
+ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+ } else {
+ pool = NULL;
+ size = info->size;
+ min = max = 0;
+ }
+
+ if (pool == NULL) {
+ /* we did not get a pool, make one ourselves then */
+ pool = gst_buffer_pool_new ();
+ }
+
+ /* and configure */
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config, target, size, min, max);
+ gst_buffer_pool_set_config (pool, config);
+
+ if (filter->pool) {
+ gst_buffer_pool_set_active (filter->pool, FALSE);
+ 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)
{
int y;
guint8 *out_pix;
guint8 *in_pix;
- int in_rowstride;
+ int in_rowstride, out_rowstride;
GstFlowReturn ret;
GstCaps *caps = NULL;
+ gint width, height;
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) {
- 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;
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) {
+ GstVideoInfo info;
+ GstVideoFormat fmt;
+
+ GST_DEBUG ("Set size to %dx%d", width, 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, width, height);
+ info.fps_n = filter->in_fps_n;
+ info.fps_d = filter->in_fps_d;
+ caps = gst_video_info_to_caps (&info);
+
+ filter->info = info;
+
gst_pad_set_caps (filter->srcpad, caps);
gst_caps_unref (caps);
- }
- ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad,
- GST_BUFFER_OFFSET_NONE,
- filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf);
+ gst_gdk_pixbuf_setup_pool (filter, &info);
+ }
+ ret = gst_buffer_pool_acquire_buffer (filter->pool, &outbuf, NULL);
if (ret != GST_FLOW_OK)
goto no_buffer;
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 */
- for (y = 0; y < filter->height; y++) {
- memcpy (out_pix, in_pix, filter->rowstride);
+ gst_video_frame_map (&frame, &filter->info, outbuf, GST_MAP_WRITE);
+ out_pix = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+ out_rowstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
+
+ for (y = 0; y < height; y++) {
+ memcpy (out_pix, in_pix, width * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, 0));
in_pix += in_rowstride;
- out_pix += filter->rowstride;
+ out_pix += out_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)
}
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;
+ gboolean ret = TRUE, forward = 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);
+ ret = gst_gdk_pixbuf_sink_setcaps (pixbuf, caps);
+ forward = FALSE;
+ break;
+ }
case GST_EVENT_EOS:
if (pixbuf->pixbuf_loader != NULL) {
gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
/* as long as we don't have flow returns for event functions we need
* to post an error here, or the application might never know that
* things failed */
- if (res != GST_FLOW_OK && res != GST_FLOW_WRONG_STATE) {
+ if (res != GST_FLOW_OK && res != GST_FLOW_FLUSHING) {
GST_ELEMENT_ERROR (pixbuf, STREAM, FAILED, (NULL),
("Flow: %s", gst_flow_get_name (res)));
+ forward = FALSE;
+ ret = FALSE;
}
}
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);
default:
break;
}
-
- if (res == GST_FLOW_OK) {
- ret = gst_pad_event_default (pad, event);
+ if (forward) {
+ ret = gst_pad_event_default (pad, parent, event);
} else {
- ret = FALSE;
+ gst_event_unref (event);
}
-
- 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);
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? */
- if (filter->framerate_numerator != 0) {
+ if (filter->in_fps_n != 0) {
gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL);
ret = gst_gdk_pixbuf_flush (filter);
g_object_unref (filter->pixbuf_loader);
filter->pixbuf_loader = NULL;
}
+ gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
- gst_object_unref (filter);
return ret;
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;
}
}
-static void
-gst_gdk_pixbuf_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- switch (prop_id) {
- case ARG_SILENT:
- /* filter->silent = g_value_get_boolean (value); */
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gdk_pixbuf_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- switch (prop_id) {
- case ARG_SILENT:
- /* g_value_set_boolean (value, filter->silent); */
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
static GstStateChangeReturn
gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition)
{
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
/* default to single image mode, setcaps function might not be called */
- dec->framerate_numerator = 0;
- dec->framerate_denominator = 1;
+ dec->in_fps_n = 0;
+ dec->in_fps_d = 1;
+ gst_video_info_init (&dec->info);
break;
default:
break;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
- dec->framerate_numerator = 0;
- dec->framerate_denominator = 0;
+ dec->in_fps_n = 0;
+ dec->in_fps_d = 0;
+ if (dec->pool) {
+ gst_buffer_pool_set_active (dec->pool, FALSE);
+ gst_object_replace ((GstObject **) & dec->pool, NULL);
+ }
break;
default:
break;
if (!pixbufscale_init (plugin))
return FALSE;
- gst_controller_init (NULL, NULL);
-
/* plugin initialisation succeeded */
return TRUE;
}