remove copyright field from plugins
[platform/upstream/gst-plugins-good.git] / gst / videofilter / gstvideofilter.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 /*#define DEBUG_ENABLED */
26 #include <gstvideofilter.h>
27
28
29
30 /* GstVideofilter signals and args */
31 enum {
32   /* FILL ME */
33   LAST_SIGNAL
34 };
35
36 enum {
37   ARG_0,
38   ARG_METHOD,
39   /* FILL ME */
40 };
41
42 static void     gst_videofilter_base_init       (gpointer g_class);
43 static void     gst_videofilter_class_init      (gpointer g_class, gpointer class_data);
44 static void     gst_videofilter_init            (GTypeInstance *instance, gpointer g_class);
45
46 static void     gst_videofilter_set_property            (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
47 static void     gst_videofilter_get_property            (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
48
49 static void     gst_videofilter_chain           (GstPad *pad, GstData *_data);
50 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass);
51 static void gst_videofilter_setup(GstVideofilter *videofilter);
52
53 static GstElementClass *parent_class = NULL;
54
55 GType
56 gst_videofilter_get_type (void)
57 {
58   static GType videofilter_type = 0;
59
60   if (!videofilter_type) {
61     static const GTypeInfo videofilter_info = {
62       sizeof(GstVideofilterClass),
63       gst_videofilter_base_init,
64       NULL,
65       gst_videofilter_class_init,
66       NULL,
67       NULL,
68       sizeof(GstVideofilter),
69       0,
70       gst_videofilter_init,
71     };
72     videofilter_type = g_type_register_static(GST_TYPE_ELEMENT,
73         "GstVideofilter", &videofilter_info, G_TYPE_FLAG_ABSTRACT);
74   }
75   return videofilter_type;
76 }
77
78 static void gst_videofilter_base_init (gpointer g_class)
79 {
80   static GstElementDetails videofilter_details = {
81     "Video scaler",
82     "Filter/Effect/Video",
83     "Resizes video",
84     "David Schleef <ds@schleef.org>"
85   };
86   GstVideofilterClass *klass = (GstVideofilterClass *) g_class;
87   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
88
89   klass->formats = g_ptr_array_new();
90
91   gst_element_class_set_details (element_class, &videofilter_details);
92 }
93
94 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data)
95 {
96   GObjectClass *gobject_class;
97   GstElementClass *gstelement_class;
98   GstVideofilterClass *klass;
99
100   klass = (GstVideofilterClass *)g_class;
101   gobject_class = (GObjectClass*)klass;
102   gstelement_class = (GstElementClass*)klass;
103
104   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
105
106   gobject_class->set_property = gst_videofilter_set_property;
107   gobject_class->get_property = gst_videofilter_get_property;
108 }
109
110 static GstCaps *gst_videofilter_format_get_caps(GstVideofilterFormat *format)
111 {
112   unsigned int fourcc;
113   GstCaps *caps;
114
115   if(format->filter_func==NULL)
116     return NULL;
117
118   fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
119
120   if(format->bpp){
121     caps = GST_CAPS_NEW ("videofilter", "video/x-raw-rgb",
122                 "format", GST_PROPS_FOURCC (fourcc),
123                 "depth", GST_PROPS_INT(format->bpp),
124                 "bpp", GST_PROPS_INT(format->depth),
125                 "endianness", GST_PROPS_INT(format->endianness),
126                 "red_mask", GST_PROPS_INT(format->red_mask),
127                 "green_mask", GST_PROPS_INT(format->green_mask),
128                 "blue_mask", GST_PROPS_INT(format->blue_mask));
129   }else{
130     caps = GST_CAPS_NEW ("videoflip", "video/x-raw-yuv",
131                 "format", GST_PROPS_FOURCC (fourcc),
132                 "height", GST_PROPS_INT_RANGE (1,G_MAXINT),
133                 "width", GST_PROPS_INT_RANGE (1,G_MAXINT),
134                 "framerate", GST_PROPS_FLOAT_RANGE (0,G_MAXFLOAT)
135                 );
136   }
137
138   return caps;
139 }
140
141 GstCaps * gst_videofilter_class_get_capslist(GstVideofilterClass *klass)
142 {
143   static GstCaps *capslist = NULL;
144   GstCaps *caps;
145   int i;
146
147   if (capslist){
148     gst_caps_ref(capslist);
149     return capslist;
150   }
151
152   for(i=0;i<klass->formats->len;i++){
153     caps = gst_videofilter_format_get_caps(g_ptr_array_index(klass->formats,i));
154     capslist = gst_caps_append(capslist, caps);
155   }
156
157   gst_caps_ref(capslist);
158   return capslist;
159 }
160
161 static GstCaps *
162 gst_videofilter_sink_getcaps (GstPad *pad, GstCaps *caps)
163 {
164   GstVideofilter *videofilter;
165   GstVideofilterClass *klass;
166   GstCaps *capslist = NULL;
167   GstCaps *peercaps;
168   GstCaps *sizecaps;
169   int i;
170
171   GST_DEBUG("gst_videofilter_sink_getcaps");
172   videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
173   
174   klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
175
176   /* get list of peer's caps */
177   peercaps = gst_pad_get_allowed_caps (videofilter->srcpad);
178
179   /* FIXME videofilter doesn't allow passthru of video formats it
180    * doesn't understand. */
181   /* Look through our list of caps and find those that match with
182    * the peer's formats.  Create a list of them. */
183   /* FIXME optimize if peercaps == NULL */
184   for(i=0;i<klass->formats->len;i++){
185     GstCaps *icaps;
186     GstCaps *fromcaps = gst_videofilter_format_get_caps(g_ptr_array_index(
187           klass->formats,i));
188
189     icaps = gst_caps_intersect(fromcaps, peercaps);
190     //if(gst_caps_is_always_compatible(fromcaps, peercaps)){
191     if(icaps != NULL){
192       capslist = gst_caps_append(capslist, fromcaps);
193     }
194     //gst_caps_unref (fromcaps);
195     if(icaps) gst_caps_unref (icaps);
196   }
197   gst_caps_unref (peercaps);
198
199   sizecaps = GST_CAPS_NEW("videofilter_size","video/x-raw-yuv",
200                 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
201                 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
202                 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
203
204   caps = gst_caps_intersect(capslist, sizecaps);
205   gst_caps_unref (sizecaps);
206
207   return caps;
208 }
209
210 static GstPadLinkReturn
211 gst_videofilter_src_link (GstPad *pad, GstCaps *caps)
212 {
213   GstVideofilter *videofilter;
214   GstPadLinkReturn ret;
215   GstCaps *peercaps;
216
217   GST_DEBUG("gst_videofilter_src_link");
218   videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
219
220   if (!GST_CAPS_IS_FIXED (caps)) {
221     return GST_PAD_LINK_DELAYED;
222   }
223
224   gst_caps_debug(caps,"ack");
225
226   videofilter->format = gst_videofilter_find_format_by_caps (videofilter,caps);
227   g_return_val_if_fail(videofilter->format, GST_PAD_LINK_REFUSED);
228
229   gst_caps_get_int (caps, "width", &videofilter->to_width);
230   gst_caps_get_int (caps, "height", &videofilter->to_height);
231
232   GST_DEBUG("width %d height %d",videofilter->to_width,videofilter->to_height);
233
234   peercaps = gst_caps_copy(caps);
235
236   gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT));
237   gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
238
239   ret = gst_pad_try_set_caps (videofilter->srcpad, peercaps);
240
241   gst_caps_unref(peercaps);
242
243   if(ret==GST_PAD_LINK_OK){
244     caps = gst_pad_get_caps (videofilter->srcpad);
245
246     gst_caps_get_int (caps, "width", &videofilter->from_width);
247     gst_caps_get_int (caps, "height", &videofilter->from_height);
248     //gst_videofilter_setup(videofilter);
249   }
250
251   return ret;
252 }
253
254 static GstPadLinkReturn
255 gst_videofilter_sink_link (GstPad *pad, GstCaps *caps)
256 {
257   GstVideofilter *videofilter;
258   GstPadLinkReturn ret;
259   GstCaps *peercaps;
260
261   GST_DEBUG("gst_videofilter_sink_link");
262   videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
263
264   if (!GST_CAPS_IS_FIXED (caps)) {
265     return GST_PAD_LINK_DELAYED;
266   }
267
268   videofilter->format = gst_videofilter_find_format_by_caps (videofilter,caps);
269   GST_DEBUG("sink_link: %s\n",gst_caps_to_string(caps));
270   g_return_val_if_fail(videofilter->format, GST_PAD_LINK_REFUSED);
271
272   gst_caps_get_int (caps, "width", &videofilter->from_width);
273   gst_caps_get_int (caps, "height", &videofilter->from_height);
274   gst_caps_get_float (caps, "framerate", &videofilter->framerate);
275
276   gst_videofilter_setup(videofilter);
277
278   peercaps = gst_caps_copy(caps);
279
280   gst_caps_set(peercaps, "width", GST_PROPS_INT (videofilter->to_width));
281   gst_caps_set(peercaps, "height", GST_PROPS_INT (videofilter->to_height));
282   gst_caps_set(peercaps, "framerate", GST_PROPS_FLOAT (videofilter->framerate));
283
284   GST_DEBUG("setting %s\n",gst_caps_to_string(peercaps));
285
286   ret = gst_pad_try_set_caps (videofilter->srcpad, peercaps);
287
288   //gst_caps_unref(peercaps);
289
290   if(ret==GST_PAD_LINK_OK || ret==GST_PAD_LINK_DONE){
291     caps = gst_pad_get_caps (videofilter->srcpad);
292
293     //gst_caps_get_int (caps, "width", &videofilter->to_width);
294     //gst_caps_get_int (caps, "height", &videofilter->to_height);
295     //gst_videofilter_setup(videofilter);
296   }
297
298   return ret;
299 }
300
301 static void
302 gst_videofilter_init (GTypeInstance *instance, gpointer g_class)
303 {
304   GstVideofilter *videofilter = GST_VIDEOFILTER (instance);
305   GstPadTemplate *pad_template;
306
307   GST_DEBUG("gst_videofilter_init");
308
309   pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
310       "sink");
311   g_return_if_fail(pad_template != NULL);
312   videofilter->sinkpad = gst_pad_new_from_template(pad_template, "sink");
313   gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->sinkpad);
314   gst_pad_set_chain_function(videofilter->sinkpad,gst_videofilter_chain);
315   gst_pad_set_link_function(videofilter->sinkpad,gst_videofilter_sink_link);
316   gst_pad_set_getcaps_function(videofilter->sinkpad,gst_videofilter_sink_getcaps);
317
318   pad_template = gst_element_class_get_pad_template(GST_ELEMENT_CLASS(g_class),
319       "src");
320   g_return_if_fail(pad_template != NULL);
321   videofilter->srcpad = gst_pad_new_from_template(pad_template, "src");
322   gst_element_add_pad(GST_ELEMENT(videofilter),videofilter->srcpad);
323   gst_pad_set_link_function(videofilter->srcpad,gst_videofilter_src_link);
324   //gst_pad_set_getcaps_function(videofilter->srcpad,gst_videofilter_src_getcaps);
325
326   videofilter->inited = FALSE;
327 }
328
329 static void
330 gst_videofilter_chain (GstPad *pad, GstData *_data)
331 {
332   GstBuffer *buf = GST_BUFFER (_data);
333   GstVideofilter *videofilter;
334   guchar *data;
335   gulong size;
336   GstBuffer *outbuf;
337
338   GST_DEBUG ("gst_videofilter_chain");
339
340   g_return_if_fail (pad != NULL);
341   g_return_if_fail (GST_IS_PAD (pad));
342   g_return_if_fail (buf != NULL);
343
344   videofilter = GST_VIDEOFILTER (gst_pad_get_parent (pad));
345   //g_return_if_fail (videofilter->inited);
346
347   data = GST_BUFFER_DATA(buf);
348   size = GST_BUFFER_SIZE(buf);
349
350   if(videofilter->passthru){
351     gst_pad_push(videofilter->srcpad, GST_DATA (buf));
352     return;
353   }
354
355   GST_DEBUG ("gst_videofilter_chain: got buffer of %ld bytes in '%s'",size,
356                               GST_OBJECT_NAME (videofilter));
357  
358   GST_DEBUG("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
359         size,
360         videofilter->from_width, videofilter->from_height,
361         videofilter->to_width, videofilter->to_height,
362         size, videofilter->from_buf_size,
363         videofilter->to_buf_size);
364
365   g_return_if_fail (size == videofilter->from_buf_size);
366
367   outbuf = gst_buffer_new();
368   /* FIXME: handle bufferpools */
369   GST_BUFFER_SIZE(outbuf) = videofilter->to_buf_size;
370   GST_BUFFER_DATA(outbuf) = g_malloc (videofilter->to_buf_size);
371   GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
372
373   g_return_if_fail(videofilter->format);
374   GST_DEBUG ("format %s",videofilter->format->fourcc);
375
376   videofilter->in_buf = buf;
377   videofilter->out_buf = outbuf;
378
379   videofilter->format->filter_func(videofilter, GST_BUFFER_DATA(outbuf), data);
380
381   GST_DEBUG ("gst_videofilter_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
382                       GST_OBJECT_NAME (videofilter));
383
384   gst_pad_push(videofilter->srcpad, GST_DATA (outbuf));
385
386   gst_buffer_unref(buf);
387 }
388
389 static void
390 gst_videofilter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
391 {
392   GstVideofilter *src;
393
394   /* it's not null if we got it, but it might not be ours */
395   g_return_if_fail(GST_IS_VIDEOFILTER(object));
396   src = GST_VIDEOFILTER(object);
397
398   GST_DEBUG("gst_videofilter_set_property");
399   switch (prop_id) {
400     default:
401       break;
402   }
403 }
404
405 static void
406 gst_videofilter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
407 {
408   GstVideofilter *src;
409
410   /* it's not null if we got it, but it might not be ours */
411   g_return_if_fail(GST_IS_VIDEOFILTER(object));
412   src = GST_VIDEOFILTER(object);
413
414   switch (prop_id) {
415     default:
416       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
417       break;
418   }
419 }
420
421 int gst_videofilter_get_input_width(GstVideofilter *videofilter)
422 {
423   g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
424
425   return videofilter->from_width;
426 }
427
428 int gst_videofilter_get_input_height(GstVideofilter *videofilter)
429 {
430   g_return_val_if_fail(GST_IS_VIDEOFILTER(videofilter),0);
431
432   return videofilter->from_height;
433 }
434
435 void gst_videofilter_set_output_size(GstVideofilter *videofilter,
436     int width, int height)
437 {
438   int ret;
439   GstCaps *srccaps;
440
441   g_return_if_fail(GST_IS_VIDEOFILTER(videofilter));
442
443   videofilter->to_width = width;
444   videofilter->to_height = height;
445
446   videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height
447       * videofilter->format->depth)/8;
448
449   srccaps = gst_caps_copy(gst_pad_get_caps(videofilter->srcpad));
450
451   if(!GST_CAPS_IS_FIXED(srccaps)){
452     return;
453   }
454
455   gst_caps_set(srccaps, "width", GST_PROPS_INT (videofilter->to_width));
456   gst_caps_set(srccaps, "height", GST_PROPS_INT (videofilter->to_height));
457
458   ret = gst_pad_try_set_caps (videofilter->srcpad, srccaps);
459
460   g_return_if_fail(ret<0);
461 }
462
463 static void gst_videofilter_setup(GstVideofilter *videofilter)
464 {
465   GstVideofilterClass *klass;
466
467   klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
468
469   if(klass->setup){
470     klass->setup(videofilter);
471   }
472
473   if(videofilter->to_width == 0){
474     videofilter->to_width = videofilter->from_width;
475   }
476   if(videofilter->to_height == 0){
477     videofilter->to_height = videofilter->from_height;
478   }
479
480   g_return_if_fail(videofilter->format != NULL);
481   g_return_if_fail(videofilter->from_width > 0);
482   g_return_if_fail(videofilter->from_height > 0);
483   g_return_if_fail(videofilter->to_width > 0);
484   g_return_if_fail(videofilter->to_height > 0);
485
486   videofilter->from_buf_size = (videofilter->from_width * videofilter->from_height *
487       videofilter->format->depth) / 8;
488   videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height *
489       videofilter->format->depth) / 8;
490
491   videofilter->inited = TRUE;
492 }
493
494 GstVideofilterFormat *gst_videofilter_find_format_by_caps(GstVideofilter *videofilter,
495     GstCaps *caps)
496 {
497   int i;
498   GstCaps *c;
499   GstVideofilterClass *klass;
500   GstVideofilterFormat *format;
501
502   klass = GST_VIDEOFILTER_CLASS(G_OBJECT_GET_CLASS(videofilter));
503
504   g_return_val_if_fail(caps != NULL, NULL);
505
506   for(i=0;i<klass->formats->len;i++){
507     format = g_ptr_array_index(klass->formats,i);
508     c = gst_videofilter_format_get_caps(format);
509
510     if(c){
511       if(gst_caps_is_always_compatible(caps, c)){
512         gst_caps_unref(c);
513         return format;
514       }
515     }
516     gst_caps_unref(c);
517   }
518
519   return NULL;
520 }
521
522 void gst_videofilter_class_add_format(GstVideofilterClass *videofilterclass,
523     GstVideofilterFormat *format)
524 {
525   g_ptr_array_add(videofilterclass->formats, format);
526 }
527
528 void gst_videofilter_class_add_pad_templates (GstVideofilterClass *videofilter_class)
529 {
530   GstCaps *caps;
531   GstElementClass *element_class = GST_ELEMENT_CLASS (videofilter_class);
532
533   caps = GST_CAPS_NEW("src","video/x-raw-yuv",
534                 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
535                 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
536                 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
537
538   gst_element_class_add_pad_template (element_class,
539       GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS, 
540         gst_caps_intersect(caps,
541           gst_videofilter_class_get_capslist (videofilter_class))));
542
543   gst_element_class_add_pad_template (element_class,
544       GST_PAD_TEMPLATE_NEW("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
545         gst_caps_intersect(caps,
546           gst_videofilter_class_get_capslist (videofilter_class))));
547 }
548
549 static gboolean
550 plugin_init (GstPlugin *plugin)
551 {
552   return TRUE;
553 }
554
555 GST_PLUGIN_DEFINE (
556   GST_VERSION_MAJOR,
557   GST_VERSION_MINOR,
558   "gstvideofilter",
559   "Video filter parent class",
560   plugin_init,
561   VERSION,
562   "LGPL",
563   GST_PACKAGE,
564   GST_ORIGIN
565 )