remove copyright field from plugins
[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/Decoder/Image",
35   "Decodes images in a video stream using GdkPixbuf",
36   "David A. Schleef <ds@schleef.org>",
37 };
38
39 /* Filter signals and args */
40 enum {
41   /* FILL ME */
42   LAST_SIGNAL
43 };
44
45 enum {
46   ARG_0,
47   ARG_SILENT
48 };
49
50 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_sink_factory,
51   "sink",
52   GST_PAD_SINK,
53   GST_PAD_ALWAYS,
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)
73 );
74
75 GST_PAD_TEMPLATE_FACTORY (gst_gdk_pixbuf_src_factory,
76   "src",
77   GST_PAD_SRC,
78   GST_PAD_ALWAYS,
79   GST_CAPS_NEW(
80     "gdk_pixbuf_src",
81     "video/x-raw-rgb",
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)
93   )
94 );
95
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);
99
100 static void     gst_gdk_pixbuf_set_property(GObject *object, guint prop_id,
101                                                  const GValue *value,
102                                                  GParamSpec *pspec);
103 static void     gst_gdk_pixbuf_get_property(GObject *object, guint prop_id,
104                                                  GValue *value,
105                                                  GParamSpec *pspec);
106
107 static void     gst_gdk_pixbuf_chain    (GstPad *pad, GstData *_data);
108 static void     gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore);
109
110 static GstElementClass *parent_class = NULL;
111
112 static GstPadLinkReturn
113 gst_gdk_pixbuf_sink_link (GstPad *pad, GstCaps *caps)
114 {
115   GstGdkPixbuf *filter;
116
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);
121
122   if (GST_CAPS_IS_FIXED (caps))
123   {
124     return GST_PAD_LINK_OK;
125   }
126
127   return GST_PAD_LINK_DELAYED;
128 }
129
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
134  * library. */
135 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
136 {
137   GstCaps *capslist;
138
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),
159     NULL);
160
161   return capslist;
162 }
163 #else
164 static GstCaps *gst_gdk_pixbuf_get_capslist(void)
165 {
166   GSList *slist;
167   GSList *slist0;
168   GdkPixbufFormat *pixbuf_format;
169   char **mimetypes;
170   char **mimetype;
171   static GstCaps *capslist = NULL;
172
173   if(capslist==NULL){
174     slist0 = gdk_pixbuf_get_formats();
175
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));
181       }
182       g_free(mimetypes);
183     }
184     gst_caps_ref(capslist);
185     gst_caps_sink(capslist);
186     g_slist_free(slist0);
187
188     g_print("%s\n",gst_caps_to_string(capslist));
189   }
190
191   return capslist;
192 }
193 #endif
194
195 static GstCaps *gst_gdk_pixbuf_sink_getcaps(GstPad *pad, GstCaps *caps)
196 {
197   GstGdkPixbuf *filter;
198
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);
202
203   return gst_gdk_pixbuf_get_capslist();
204 }
205
206 GType
207 gst_gdk_pixbuf_get_type (void)
208 {
209   static GType plugin_type = 0;
210
211   if (!plugin_type)
212   {
213     static const GTypeInfo plugin_info =
214     {
215       sizeof (GstGdkPixbufClass),
216       gst_gdk_pixbuf_base_init,
217       NULL,
218       (GClassInitFunc) gst_gdk_pixbuf_class_init,
219       NULL,
220       NULL,
221       sizeof (GstGdkPixbuf),
222       0,
223       (GInstanceInitFunc) gst_gdk_pixbuf_init,
224     };
225     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
226                                           "GstGdkPixbuf",
227                                           &plugin_info, 0);
228   }
229   return plugin_type;
230 }
231
232 static void
233 gst_gdk_pixbuf_base_init (gpointer g_class)
234 {
235   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
236
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);
240 }
241
242 /* initialize the plugin's class */
243 static void
244 gst_gdk_pixbuf_class_init (GstGdkPixbufClass *klass)
245 {
246   GObjectClass *gobject_class;
247   GstElementClass *gstelement_class;
248
249   gobject_class = (GObjectClass*) klass;
250   gstelement_class = (GstElementClass*) klass;
251
252   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
253
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));
257
258   gobject_class->set_property = gst_gdk_pixbuf_set_property;
259   gobject_class->get_property = gst_gdk_pixbuf_get_property;
260 }
261
262 static void
263 gst_gdk_pixbuf_init (GstGdkPixbuf *filter)
264 {
265   filter->sinkpad = gst_pad_new_from_template (gst_gdk_pixbuf_sink_factory (),
266                                                "sink");
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 (),
270                                               "src");
271
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);
275
276 }
277
278 static void
279 gst_gdk_pixbuf_chain (GstPad *pad, GstData *_data)
280 {
281   GstBuffer *buf = GST_BUFFER (_data);
282   GstGdkPixbuf *filter;
283   GdkPixbufLoader *pixbuf_loader;
284   GdkPixbuf *pixbuf;
285   GstBuffer *outbuf;
286   GError *error = NULL;
287
288   g_print("gst_gdk_pixbuf_chain\n");
289
290   g_return_if_fail (GST_IS_PAD (pad));
291   g_return_if_fail (buf != NULL);
292
293   filter = GST_GDK_PIXBUF (GST_OBJECT_PARENT (pad));
294   g_return_if_fail (GST_IS_GDK_PIXBUF (filter));
295
296   pixbuf_loader = gdk_pixbuf_loader_new();
297   //pixbuf_loader = gdk_pixbuf_loader_new_with_type("gif");
298   
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);
303
304   g_print("width=%d height=%d\n", gdk_pixbuf_get_width(pixbuf),
305       gdk_pixbuf_get_height(pixbuf));
306
307   if(filter->image_size == 0){
308     GstCaps *caps;
309
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;
314
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.));
319
320     gst_pad_try_set_caps(filter->srcpad, caps);
321   }
322
323   outbuf = gst_buffer_new();
324   GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
325   GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf);
326   
327   GST_BUFFER_SIZE(outbuf) = filter->image_size;
328   GST_BUFFER_DATA(outbuf) = g_malloc(filter->image_size);
329
330   memcpy(GST_BUFFER_DATA(outbuf), gdk_pixbuf_get_pixels(pixbuf),
331       filter->image_size);
332
333   g_object_unref(G_OBJECT(pixbuf_loader));
334
335   gst_pad_push (filter->srcpad, GST_DATA (outbuf));
336 }
337
338 static void
339 gst_gdk_pixbuf_set_property (GObject *object, guint prop_id,
340                                   const GValue *value, GParamSpec *pspec)
341 {
342   GstGdkPixbuf *filter;
343
344   g_return_if_fail (GST_IS_GDK_PIXBUF (object));
345   filter = GST_GDK_PIXBUF (object);
346
347   switch (prop_id)
348   {
349   case ARG_SILENT:
350     //filter->silent = g_value_get_boolean (value);
351     break;
352   default:
353     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
354     break;
355   }
356 }
357
358 static void
359 gst_gdk_pixbuf_get_property (GObject *object, guint prop_id,
360                                   GValue *value, GParamSpec *pspec)
361 {
362   GstGdkPixbuf *filter;
363
364   g_return_if_fail (GST_IS_GDK_PIXBUF (object));
365   filter = GST_GDK_PIXBUF (object);
366
367   switch (prop_id) {
368   case ARG_SILENT:
369     //g_value_set_boolean (value, filter->silent);
370     break;
371   default:
372     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373     break;
374   }
375 }
376
377 #define GST_GDK_PIXBUF_TYPE_FIND_SIZE 1024
378
379 static void
380 gst_gdk_pixbuf_type_find (GstTypeFind *tf, gpointer ignore)
381 {
382   guint8 *data;
383   GdkPixbufLoader *pixbuf_loader;
384   GdkPixbufFormat *format;
385
386   data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
387   if (data == NULL) return;
388
389   GST_DEBUG ("gst_gdk_pixbuf_type_find");
390
391   pixbuf_loader = gdk_pixbuf_loader_new();
392   
393   gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
394       NULL);
395   
396   format = gdk_pixbuf_loader_get_format (pixbuf_loader);
397
398   if (format != NULL) {
399     gchar **mlist = gdk_pixbuf_format_get_mime_types(format);
400
401     gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM,
402         gst_caps_new ("gdk_pixbuf_type_find", mlist[0], NULL));
403   }
404
405   gdk_pixbuf_loader_close (pixbuf_loader, NULL);
406   g_object_unref (G_OBJECT (pixbuf_loader));
407 }
408
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
413  */
414 static gboolean
415 plugin_init (GstPlugin *plugin)
416 {
417   if (!gst_element_register (plugin, "gdkpixbufdec", GST_RANK_NONE, GST_TYPE_GDK_PIXBUF))
418     return FALSE;
419
420   gst_type_find_register (plugin, "image/*", GST_RANK_MARGINAL,
421                           gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL);
422
423   /* plugin initialisation succeeded */
424   return TRUE;
425 }
426
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 */
429 GST_PLUGIN_DEFINE (
430   GST_VERSION_MAJOR,
431   GST_VERSION_MINOR,
432   "gdkpixbuf",
433   "GDK Pixbuf decoder",
434   plugin_init,
435   VERSION,
436   "LGPL",
437   GST_PACKAGE,
438   GST_ORIGIN)