4 * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
5 * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include <gdk-pixbuf/gdk-pixbuf.h>
30 #include "gstgdkpixbuf.h"
32 static GstElementDetails plugin_details = {
33 "GdkPixbuf image decoder",
34 "Codec/Decoder/Image",
35 "Decodes images in a video stream using GdkPixbuf",
36 "David A. Schleef <ds@schleef.org>",
39 /* Filter signals and args */
50 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_sink_factory,
54 GST_CAPS_NEW("gdk_pixbuf_sink", "image/png", NULL),
55 GST_CAPS_NEW("gdk_pixbuf_sink", "image/jpeg", NULL),
56 GST_CAPS_NEW("gdk_pixbuf_sink", "image/gif", NULL),
57 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-icon", NULL),
58 GST_CAPS_NEW("gdk_pixbuf_sink", "application/x-navi-animation", NULL),
59 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-cmu-raster", NULL),
60 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-sun-raster", NULL),
61 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-pixmap", NULL),
62 GST_CAPS_NEW("gdk_pixbuf_sink", "image/tiff", NULL),
63 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-anymap", NULL),
64 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-bitmap", NULL),
65 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-graymap", NULL),
66 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-pixmap", NULL),
67 GST_CAPS_NEW("gdk_pixbuf_sink", "image/bmp", NULL),
68 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bmp", NULL),
69 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-MS-bmp", NULL),
70 GST_CAPS_NEW("gdk_pixbuf_sink", "image/vnd.wap.wbmp", NULL),
71 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bitmap", NULL),
72 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-tga", NULL)
75 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_src_factory,
82 "width", GST_PROPS_INT_RANGE(1,INT_MAX),
83 "height", GST_PROPS_INT_RANGE(1,INT_MAX),
84 /* well, it's needed for connectivity but this
85 * doesn't really make sense... */
86 "framerate", GST_PROPS_FLOAT_RANGE(0, G_MAXFLOAT),
87 "bpp", GST_PROPS_INT(32),
88 "depth", GST_PROPS_INT(24),
89 "endianness", GST_PROPS_INT(G_BIG_ENDIAN),
90 "red_mask", GST_PROPS_INT(0x00ff0000),
91 "green_mask", GST_PROPS_INT(0x0000ff00),
92 "blue_mask", GST_PROPS_INT(0x000000ff)
96 static void gst_gdk_pixbuf_base_init (gpointer g_class);
97 static void gst_gdk_pixbuf_class_init (GstGdkPixbufClass *klass);
98 static void gst_gdk_pixbuf_init (GstGdkPixbuf *filter);
100 static void gst_gdk_pixbuf_set_property(GObject *object, guint prop_id,
103 static void gst_gdk_pixbuf_get_property(GObject *object, guint prop_id,
107 static void gst_gdk_pixbuf_chain (GstPad *pad, GstData *_data);
108 static void gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore);
110 static GstElementClass *parent_class = NULL;
112 static GstPadLinkReturn
113 gst_gdk_pixbuf_sink_link (GstPad *pad, GstCaps *caps)
115 GstGdkPixbuf *filter;
117 filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
118 g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
119 g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter),
120 GST_PAD_LINK_REFUSED);
122 if (GST_CAPS_IS_FIXED (caps))
124 return GST_PAD_LINK_OK;
127 return GST_PAD_LINK_DELAYED;
130 #if GDK_PIXBUF_MAJOR == 2 && GDK_PIXBUF_MINOR < 2
131 /* gdk-pixbuf prior to 2.2 didn't have gdk_pixbuf_get_formats().
132 * These are just the formats that gdk-pixbuf is known to support.
133 * But maybe not -- it may have been compiled without an external
135 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
139 capslist = gst_caps_chain(
140 GST_CAPS_NEW("gdk_pixbuf_sink", "image/png", NULL),
141 GST_CAPS_NEW("gdk_pixbuf_sink", "image/jpeg", NULL),
142 GST_CAPS_NEW("gdk_pixbuf_sink", "image/gif", NULL),
143 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-icon", NULL),
144 GST_CAPS_NEW("gdk_pixbuf_sink", "application/x-navi-animation", NULL),
145 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-cmu-raster", NULL),
146 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-sun-raster", NULL),
147 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-pixmap", NULL),
148 GST_CAPS_NEW("gdk_pixbuf_sink", "image/tiff", NULL),
149 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-anymap", NULL),
150 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-bitmap", NULL),
151 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-graymap", NULL),
152 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-pixmap", NULL),
153 GST_CAPS_NEW("gdk_pixbuf_sink", "image/bmp", NULL),
154 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bmp", NULL),
155 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-MS-bmp", NULL),
156 GST_CAPS_NEW("gdk_pixbuf_sink", "image/vnd.wap.wbmp", NULL),
157 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bitmap", NULL),
158 GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-tga", NULL),
164 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
168 GdkPixbufFormat *pixbuf_format;
171 static GstCaps *capslist = NULL;
174 slist0 = gdk_pixbuf_get_formats();
176 for(slist = slist0;slist;slist=g_slist_next(slist)){
177 pixbuf_format = slist->data;
178 mimetypes = gdk_pixbuf_format_get_mime_types(pixbuf_format);
179 for(mimetype = mimetypes; *mimetype; mimetype++){
180 capslist = gst_caps_append(capslist, gst_caps_new("ack",*mimetype,NULL));
184 gst_caps_ref(capslist);
185 gst_caps_sink(capslist);
186 g_slist_free(slist0);
188 g_print("%s\n",gst_caps_to_string(capslist));
195 static GstCaps *gst_gdk_pixbuf_sink_getcaps(GstPad *pad, GstCaps *caps)
197 GstGdkPixbuf *filter;
199 filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
200 g_return_val_if_fail (filter != NULL, NULL);
201 g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter), NULL);
203 return gst_gdk_pixbuf_get_capslist();
207 gst_gdk_pixbuf_get_type (void)
209 static GType plugin_type = 0;
213 static const GTypeInfo plugin_info =
215 sizeof (GstGdkPixbufClass),
216 gst_gdk_pixbuf_base_init,
218 (GClassInitFunc) gst_gdk_pixbuf_class_init,
221 sizeof (GstGdkPixbuf),
223 (GInstanceInitFunc) gst_gdk_pixbuf_init,
225 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
233 gst_gdk_pixbuf_base_init (gpointer g_class)
235 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
237 gst_element_class_add_pad_template (element_class, gst_gdk_pixbuf_src_factory ());
238 gst_element_class_add_pad_template (element_class, gst_gdk_pixbuf_sink_factory ());
239 gst_element_class_set_details (element_class, &plugin_details);
242 /* initialize the plugin's class */
244 gst_gdk_pixbuf_class_init (GstGdkPixbufClass *klass)
246 GObjectClass *gobject_class;
247 GstElementClass *gstelement_class;
249 gobject_class = (GObjectClass*) klass;
250 gstelement_class = (GstElementClass*) klass;
252 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
254 g_object_class_install_property (gobject_class, ARG_SILENT,
255 g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
256 FALSE, G_PARAM_READWRITE));
258 gobject_class->set_property = gst_gdk_pixbuf_set_property;
259 gobject_class->get_property = gst_gdk_pixbuf_get_property;
263 gst_gdk_pixbuf_init (GstGdkPixbuf *filter)
265 filter->sinkpad = gst_pad_new_from_template (gst_gdk_pixbuf_sink_factory (),
267 gst_pad_set_link_function (filter->sinkpad, gst_gdk_pixbuf_sink_link);
268 gst_pad_set_getcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_getcaps);
269 filter->srcpad = gst_pad_new_from_template (gst_gdk_pixbuf_src_factory (),
272 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
273 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
274 gst_pad_set_chain_function (filter->sinkpad, gst_gdk_pixbuf_chain);
279 gst_gdk_pixbuf_chain (GstPad *pad, GstData *_data)
281 GstBuffer *buf = GST_BUFFER (_data);
282 GstGdkPixbuf *filter;
283 GdkPixbufLoader *pixbuf_loader;
286 GError *error = NULL;
288 g_print("gst_gdk_pixbuf_chain\n");
290 g_return_if_fail (GST_IS_PAD (pad));
291 g_return_if_fail (buf != NULL);
293 filter = GST_GDK_PIXBUF (GST_OBJECT_PARENT (pad));
294 g_return_if_fail (GST_IS_GDK_PIXBUF (filter));
296 pixbuf_loader = gdk_pixbuf_loader_new();
297 //pixbuf_loader = gdk_pixbuf_loader_new_with_type("gif");
299 gdk_pixbuf_loader_write(pixbuf_loader, GST_BUFFER_DATA(buf),
300 GST_BUFFER_SIZE(buf), &error);
301 gdk_pixbuf_loader_close(pixbuf_loader, &error);
302 pixbuf = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader);
304 g_print("width=%d height=%d\n", gdk_pixbuf_get_width(pixbuf),
305 gdk_pixbuf_get_height(pixbuf));
307 if(filter->image_size == 0){
310 filter->width = gdk_pixbuf_get_width(pixbuf);
311 filter->height = gdk_pixbuf_get_height(pixbuf);
312 filter->rowstride = gdk_pixbuf_get_rowstride(pixbuf);
313 filter->image_size = filter->rowstride * filter->height;
315 caps = gst_pad_get_caps(filter->srcpad);
316 gst_caps_set(caps, "width", GST_PROPS_INT(filter->width));
317 gst_caps_set(caps, "height", GST_PROPS_INT(filter->height));
318 gst_caps_set(caps, "framerate", GST_PROPS_FLOAT(0.));
320 gst_pad_try_set_caps(filter->srcpad, caps);
323 outbuf = gst_buffer_new();
324 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
325 GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf);
327 GST_BUFFER_SIZE(outbuf) = filter->image_size;
328 GST_BUFFER_DATA(outbuf) = g_malloc(filter->image_size);
330 memcpy(GST_BUFFER_DATA(outbuf), gdk_pixbuf_get_pixels(pixbuf),
333 g_object_unref(G_OBJECT(pixbuf_loader));
335 gst_pad_push (filter->srcpad, GST_DATA (outbuf));
339 gst_gdk_pixbuf_set_property (GObject *object, guint prop_id,
340 const GValue *value, GParamSpec *pspec)
342 GstGdkPixbuf *filter;
344 g_return_if_fail (GST_IS_GDK_PIXBUF (object));
345 filter = GST_GDK_PIXBUF (object);
350 //filter->silent = g_value_get_boolean (value);
353 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359 gst_gdk_pixbuf_get_property (GObject *object, guint prop_id,
360 GValue *value, GParamSpec *pspec)
362 GstGdkPixbuf *filter;
364 g_return_if_fail (GST_IS_GDK_PIXBUF (object));
365 filter = GST_GDK_PIXBUF (object);
369 //g_value_set_boolean (value, filter->silent);
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
377 #define GST_GDK_PIXBUF_TYPE_FIND_SIZE 1024
380 gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore)
383 GdkPixbufLoader *pixbuf_loader;
384 GdkPixbufFormat *format;
386 data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
387 if (data == NULL) return;
389 GST_DEBUG ("gst_gdk_pixbuf_type_find");
391 pixbuf_loader = gdk_pixbuf_loader_new();
393 gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
396 format = gdk_pixbuf_loader_get_format (pixbuf_loader);
398 if (format != NULL) {
399 gchar **mlist = gdk_pixbuf_format_get_mime_types(format);
401 gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM,
402 gst_caps_new ("gdk_pixbuf_type_find", mlist[0], NULL));
405 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
406 g_object_unref (G_OBJECT (pixbuf_loader));
409 /* entry point to initialize the plug-in
410 * initialize the plug-in itself
411 * register the element factories and pad templates
412 * register the features
415 plugin_init (GstPlugin *plugin)
417 if (!gst_element_register (plugin, "gdkpixbufdec", GST_RANK_NONE, GST_TYPE_GDK_PIXBUF))
420 gst_type_find_register (plugin, "image/*", GST_RANK_MARGINAL,
421 gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL);
423 /* plugin initialisation succeeded */
427 /* this is the structure that gst-register looks for
428 * so keep the name plugin_desc, or you cannot get your plug-in registered */
433 "GDK Pixbuf decoder",