updating some plugin categories
[platform/upstream/gst-plugins-good.git] / ext / gdk_pixbuf / gstgdkpixbuf.c
1 /*
2  * gstgdkpixbuf.c
3  * GStreamer
4  * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
5  * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <gst/gst.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 #include <string.h>
29
30 #include "gstgdkpixbuf.h"
31
32 static GstElementDetails plugin_details = {
33   "GdkPixbuf image decoder",
34   "Codec/Image",
35   "LGPL",
36   "Decodes images in a video stream using GdkPixbuf",
37   VERSION,
38   "David A. Schleef <ds@schleef.org>",
39   "(C) 2002, 2003"
40 };
41
42 /* Filter signals and args */
43 enum {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum {
49   ARG_0,
50   ARG_SILENT
51 };
52
53 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_sink_factory,
54   "sink",
55   GST_PAD_SINK,
56   GST_PAD_ALWAYS,
57   GST_CAPS_NEW("gdk_pixbuf_sink", "image/png", NULL),
58   GST_CAPS_NEW("gdk_pixbuf_sink", "image/jpeg", NULL),
59   GST_CAPS_NEW("gdk_pixbuf_sink", "image/gif", NULL),
60   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-icon", NULL),
61   GST_CAPS_NEW("gdk_pixbuf_sink", "application/x-navi-animation", NULL),
62   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-cmu-raster", NULL),
63   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-sun-raster", NULL),
64   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-pixmap", NULL),
65   GST_CAPS_NEW("gdk_pixbuf_sink", "image/tiff", NULL),
66   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-anymap", NULL),
67   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-bitmap", NULL),
68   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-graymap", NULL),
69   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-pixmap", NULL),
70   GST_CAPS_NEW("gdk_pixbuf_sink", "image/bmp", NULL),
71   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bmp", NULL),
72   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-MS-bmp", NULL),
73   GST_CAPS_NEW("gdk_pixbuf_sink", "image/vnd.wap.wbmp", NULL),
74   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bitmap", NULL),
75   GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-tga", NULL)
76 );
77
78 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_src_factory,
79   "src",
80   GST_PAD_SRC,
81   GST_PAD_ALWAYS,
82   GST_CAPS_NEW(
83     "gdk_pixbuf_src",
84     "video/x-raw-rgb",
85       "width", GST_PROPS_INT_RANGE(1,INT_MAX),
86       "height", GST_PROPS_INT_RANGE(1,INT_MAX),
87       /* well, it's needed for connectivity but this
88        * doesn't really make sense... */
89       "framerate", GST_PROPS_FLOAT_RANGE(0, G_MAXFLOAT),
90       "bpp", GST_PROPS_INT(32),
91       "depth", GST_PROPS_INT(24),
92       "endianness", GST_PROPS_INT(G_BIG_ENDIAN),
93       "red_mask", GST_PROPS_INT(0x00ff0000),
94       "green_mask", GST_PROPS_INT(0x0000ff00),
95       "blue_mask", GST_PROPS_INT(0x000000ff)
96   )
97 );
98
99 static void     gst_gdk_pixbuf_class_init       (GstGdkPixbufClass *klass);
100 static void     gst_gdk_pixbuf_init     (GstGdkPixbuf *filter);
101
102 static void     gst_gdk_pixbuf_set_property(GObject *object, guint prop_id,
103                                                  const GValue *value,
104                                                  GParamSpec *pspec);
105 static void     gst_gdk_pixbuf_get_property(GObject *object, guint prop_id,
106                                                  GValue *value,
107                                                  GParamSpec *pspec);
108
109 static void     gst_gdk_pixbuf_chain    (GstPad *pad, GstBuffer *buf);
110
111 static GstElementClass *parent_class = NULL;
112
113 static GstPadLinkReturn
114 gst_gdk_pixbuf_sink_link (GstPad *pad, GstCaps *caps)
115 {
116   GstGdkPixbuf *filter;
117
118   filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
119   g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
120   g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter),
121                         GST_PAD_LINK_REFUSED);
122
123   if (GST_CAPS_IS_FIXED (caps))
124   {
125     return GST_PAD_LINK_OK;
126   }
127
128   return GST_PAD_LINK_DELAYED;
129 }
130
131 #if GDK_PIXBUF_MAJOR == 2 && GDK_PIXBUF_MINOR < 2
132 /* gdk-pixbuf prior to 2.2 didn't have gdk_pixbuf_get_formats().
133  * These are just the formats that gdk-pixbuf is known to support.
134  * But maybe not -- it may have been compiled without an external
135  * library. */
136 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
137 {
138   GstCaps *capslist;
139
140   capslist = gst_caps_chain(
141     GST_CAPS_NEW("gdk_pixbuf_sink", "image/png", NULL),
142     GST_CAPS_NEW("gdk_pixbuf_sink", "image/jpeg", NULL),
143     GST_CAPS_NEW("gdk_pixbuf_sink", "image/gif", NULL),
144     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-icon", NULL),
145     GST_CAPS_NEW("gdk_pixbuf_sink", "application/x-navi-animation", NULL),
146     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-cmu-raster", NULL),
147     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-sun-raster", NULL),
148     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-pixmap", NULL),
149     GST_CAPS_NEW("gdk_pixbuf_sink", "image/tiff", NULL),
150     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-anymap", NULL),
151     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-bitmap", NULL),
152     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-graymap", NULL),
153     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-portable-pixmap", NULL),
154     GST_CAPS_NEW("gdk_pixbuf_sink", "image/bmp", NULL),
155     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bmp", NULL),
156     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-MS-bmp", NULL),
157     GST_CAPS_NEW("gdk_pixbuf_sink", "image/vnd.wap.wbmp", NULL),
158     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-bitmap", NULL),
159     GST_CAPS_NEW("gdk_pixbuf_sink", "image/x-tga", NULL),
160     NULL);
161
162   return capslist;
163 }
164 #else
165 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
166 {
167   GSList *slist;
168   GSList *slist0;
169   GdkPixbufFormat *pixbuf_format;
170   char **mimetypes;
171   char **mimetype;
172   static GstCaps *capslist = NULL;
173
174   if(capslist==NULL){
175     slist0 = gdk_pixbuf_get_formats();
176
177     for(slist = slist0;slist;slist=g_slist_next(slist)){
178       pixbuf_format = slist->data;
179       mimetypes = gdk_pixbuf_format_get_mime_types(pixbuf_format);
180       for(mimetype = mimetypes; *mimetype; mimetype++){
181         capslist = gst_caps_append(capslist, gst_caps_new("ack",*mimetype,NULL));
182       }
183       g_free(mimetypes);
184     }
185     gst_caps_ref(capslist);
186     gst_caps_sink(capslist);
187     g_slist_free(slist0);
188
189     g_print("%s\n",gst_caps_to_string(capslist));
190   }
191
192   return capslist;
193 }
194 #endif
195
196 static GstCaps *gst_gdk_pixbuf_sink_getcaps(GstPad *pad, GstCaps *caps)
197 {
198   GstGdkPixbuf *filter;
199
200   filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
201   g_return_val_if_fail (filter != NULL, NULL);
202   g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter), NULL);
203
204   return gst_gdk_pixbuf_get_capslist();
205 }
206
207 GType
208 gst_gdk_pixbuf_get_type (void)
209 {
210   static GType plugin_type = 0;
211
212   if (!plugin_type)
213   {
214     static const GTypeInfo plugin_info =
215     {
216       sizeof (GstGdkPixbufClass),
217       NULL,
218       NULL,
219       (GClassInitFunc) gst_gdk_pixbuf_class_init,
220       NULL,
221       NULL,
222       sizeof (GstGdkPixbuf),
223       0,
224       (GInstanceInitFunc) gst_gdk_pixbuf_init,
225     };
226     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
227                                           "GstGdkPixbuf",
228                                           &plugin_info, 0);
229   }
230   return plugin_type;
231 }
232
233 /* initialize the plugin's class */
234 static void
235 gst_gdk_pixbuf_class_init (GstGdkPixbufClass *klass)
236 {
237   GObjectClass *gobject_class;
238   GstElementClass *gstelement_class;
239
240   gobject_class = (GObjectClass*) klass;
241   gstelement_class = (GstElementClass*) klass;
242
243   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
244
245   g_object_class_install_property (gobject_class, ARG_SILENT,
246     g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
247                           FALSE, G_PARAM_READWRITE));
248
249   gobject_class->set_property = gst_gdk_pixbuf_set_property;
250   gobject_class->get_property = gst_gdk_pixbuf_get_property;
251 }
252
253 static void
254 gst_gdk_pixbuf_init (GstGdkPixbuf *filter)
255 {
256   filter->sinkpad = gst_pad_new_from_template (gst_gdk_pixbuf_sink_factory (),
257                                                "sink");
258   gst_pad_set_link_function (filter->sinkpad, gst_gdk_pixbuf_sink_link);
259   gst_pad_set_getcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_getcaps);
260   filter->srcpad = gst_pad_new_from_template (gst_gdk_pixbuf_src_factory (),
261                                               "src");
262
263   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
264   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
265   gst_pad_set_chain_function (filter->sinkpad, gst_gdk_pixbuf_chain);
266
267 }
268
269 static void
270 gst_gdk_pixbuf_chain (GstPad *pad, GstBuffer *buf)
271 {
272   GstGdkPixbuf *filter;
273   GdkPixbufLoader *pixbuf_loader;
274   GdkPixbuf *pixbuf;
275   GstBuffer *outbuf;
276   GError *error = NULL;
277
278   g_print("gst_gdk_pixbuf_chain\n");
279
280   g_return_if_fail (GST_IS_PAD (pad));
281   g_return_if_fail (buf != NULL);
282
283   filter = GST_GDK_PIXBUF (GST_OBJECT_PARENT (pad));
284   g_return_if_fail (GST_IS_GDK_PIXBUF (filter));
285
286   pixbuf_loader = gdk_pixbuf_loader_new();
287   //pixbuf_loader = gdk_pixbuf_loader_new_with_type("gif");
288   
289   gdk_pixbuf_loader_write(pixbuf_loader, GST_BUFFER_DATA(buf),
290       GST_BUFFER_SIZE(buf), &error);
291   gdk_pixbuf_loader_close(pixbuf_loader, &error);
292   pixbuf = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader);
293
294   g_print("width=%d height=%d\n", gdk_pixbuf_get_width(pixbuf),
295       gdk_pixbuf_get_height(pixbuf));
296
297   if(filter->image_size == 0){
298     GstCaps *caps;
299
300     filter->width = gdk_pixbuf_get_width(pixbuf);
301     filter->height = gdk_pixbuf_get_height(pixbuf);
302     filter->rowstride = gdk_pixbuf_get_rowstride(pixbuf);
303     filter->image_size = filter->rowstride * filter->height;
304
305     caps = gst_pad_get_caps(filter->srcpad);
306     gst_caps_set(caps, "width", GST_PROPS_INT(filter->width));
307     gst_caps_set(caps, "height", GST_PROPS_INT(filter->height));
308     gst_caps_set(caps, "framerate", GST_PROPS_FLOAT(0.));
309
310     gst_pad_try_set_caps(filter->srcpad, caps);
311   }
312
313   outbuf = gst_buffer_new();
314   GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
315   GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf);
316   
317   GST_BUFFER_SIZE(outbuf) = filter->image_size;
318   GST_BUFFER_DATA(outbuf) = g_malloc(filter->image_size);
319
320   memcpy(GST_BUFFER_DATA(outbuf), gdk_pixbuf_get_pixels(pixbuf),
321       filter->image_size);
322
323   g_object_unref(G_OBJECT(pixbuf_loader));
324
325   gst_pad_push (filter->srcpad, outbuf);
326 }
327
328 static void
329 gst_gdk_pixbuf_set_property (GObject *object, guint prop_id,
330                                   const GValue *value, GParamSpec *pspec)
331 {
332   GstGdkPixbuf *filter;
333
334   g_return_if_fail (GST_IS_GDK_PIXBUF (object));
335   filter = GST_GDK_PIXBUF (object);
336
337   switch (prop_id)
338   {
339   case ARG_SILENT:
340     //filter->silent = g_value_get_boolean (value);
341     break;
342   default:
343     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
344     break;
345   }
346 }
347
348 static void
349 gst_gdk_pixbuf_get_property (GObject *object, guint prop_id,
350                                   GValue *value, GParamSpec *pspec)
351 {
352   GstGdkPixbuf *filter;
353
354   g_return_if_fail (GST_IS_GDK_PIXBUF (object));
355   filter = GST_GDK_PIXBUF (object);
356
357   switch (prop_id) {
358   case ARG_SILENT:
359     //g_value_set_boolean (value, filter->silent);
360     break;
361   default:
362     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363     break;
364   }
365 }
366
367 /* entry point to initialize the plug-in
368  * initialize the plug-in itself
369  * register the element factories and pad templates
370  * register the features
371  */
372 static gboolean
373 plugin_init (GModule *module, GstPlugin *plugin)
374 {
375   GstElementFactory *factory;
376
377   factory = gst_element_factory_new ("gdkpixbufdec", GST_TYPE_GDK_PIXBUF,
378                                      &plugin_details);
379   g_return_val_if_fail (factory != NULL, FALSE);
380
381   gst_element_factory_add_pad_template (factory,
382                                         gst_gdk_pixbuf_src_factory ());
383   gst_element_factory_add_pad_template (factory,
384                                         gst_gdk_pixbuf_sink_factory ());
385
386   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
387
388   /* plugin initialisation succeeded */
389   return TRUE;
390 }
391
392 /* this is the structure that gst-register looks for
393  * so keep the name plugin_desc, or you cannot get your plug-in registered */
394 GstPluginDesc plugin_desc = {
395   GST_VERSION_MAJOR,
396   GST_VERSION_MINOR,
397   "gdkpixbuf",
398   plugin_init
399 };