Way, way, way too many files: Remove crack comment from the 2000 era.
[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 #include <string.h>
26 /*#define DEBUG_ENABLED */
27 #include "gstvideofilter.h"
28
29
30
31 /* GstVideofilter signals and args */
32 enum
33 {
34   /* FILL ME */
35   LAST_SIGNAL
36 };
37
38 enum
39 {
40   ARG_0,
41   ARG_METHOD
42       /* FILL ME */
43 };
44
45 static void gst_videofilter_base_init (gpointer g_class);
46 static void gst_videofilter_class_init (gpointer g_class, gpointer class_data);
47 static void gst_videofilter_init (GTypeInstance * instance, gpointer g_class);
48
49 static void gst_videofilter_set_property (GObject * object, guint prop_id,
50     const GValue * value, GParamSpec * pspec);
51 static void gst_videofilter_get_property (GObject * object, guint prop_id,
52     GValue * value, GParamSpec * pspec);
53
54 static GstFlowReturn gst_videofilter_chain (GstPad * pad, GstBuffer * buffer);
55 GstCaps *gst_videofilter_class_get_capslist (GstVideofilterClass * klass);
56 static void gst_videofilter_setup (GstVideofilter * videofilter);
57
58 static GstElementClass *parent_class = NULL;
59
60 GType
61 gst_videofilter_get_type (void)
62 {
63   static GType videofilter_type = 0;
64
65   if (!videofilter_type) {
66     static const GTypeInfo videofilter_info = {
67       sizeof (GstVideofilterClass),
68       gst_videofilter_base_init,
69       NULL,
70       gst_videofilter_class_init,
71       NULL,
72       NULL,
73       sizeof (GstVideofilter),
74       0,
75       gst_videofilter_init,
76     };
77
78     videofilter_type = g_type_register_static (GST_TYPE_ELEMENT,
79         "GstVideofilter", &videofilter_info, G_TYPE_FLAG_ABSTRACT);
80   }
81   return videofilter_type;
82 }
83
84 static void
85 gst_videofilter_base_init (gpointer g_class)
86 {
87   static GstElementDetails videofilter_details = {
88     "Video scaler",
89     "Filter/Effect/Video",
90     "Resizes video",
91     "David Schleef <ds@schleef.org>"
92   };
93   GstVideofilterClass *klass = (GstVideofilterClass *) g_class;
94   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
95
96   klass->formats = g_ptr_array_new ();
97
98   gst_element_class_set_details (element_class, &videofilter_details);
99 }
100
101 static void
102 gst_videofilter_class_init (gpointer g_class, gpointer class_data)
103 {
104   GObjectClass *gobject_class;
105   GstElementClass *gstelement_class;
106   GstVideofilterClass *klass;
107
108   klass = (GstVideofilterClass *) g_class;
109   gobject_class = (GObjectClass *) klass;
110   gstelement_class = (GstElementClass *) klass;
111
112   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
113
114   gobject_class->set_property = gst_videofilter_set_property;
115   gobject_class->get_property = gst_videofilter_get_property;
116 }
117
118 static GstStructure *
119 gst_videofilter_format_get_structure (GstVideofilterFormat * format)
120 {
121   unsigned int fourcc;
122   GstStructure *structure;
123
124   if (format->filter_func == NULL)
125     return NULL;
126
127   fourcc =
128       GST_MAKE_FOURCC (format->fourcc[0], format->fourcc[1], format->fourcc[2],
129       format->fourcc[3]);
130
131   if (format->depth) {
132     structure = gst_structure_new ("video/x-raw-rgb",
133         "depth", G_TYPE_INT, format->depth,
134         "bpp", G_TYPE_INT, format->bpp,
135         "endianness", G_TYPE_INT, format->endianness,
136         "red_mask", G_TYPE_INT, format->red_mask,
137         "green_mask", G_TYPE_INT, format->green_mask,
138         "blue_mask", G_TYPE_INT, format->blue_mask, NULL);
139   } else {
140     structure = gst_structure_new ("video/x-raw-yuv",
141         "format", GST_TYPE_FOURCC, fourcc, NULL);
142   }
143
144   gst_structure_set (structure,
145       "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
146       "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
147       "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
148
149   return structure;
150 }
151
152 GstCaps *
153 gst_videofilter_class_get_capslist (GstVideofilterClass * klass)
154 {
155   GstCaps *caps;
156   GstStructure *structure;
157   int i;
158
159   caps = gst_caps_new_empty ();
160   for (i = 0; i < klass->formats->len; i++) {
161     structure =
162         gst_videofilter_format_get_structure (g_ptr_array_index (klass->formats,
163             i));
164     gst_caps_append_structure (caps, structure);
165   }
166
167   return caps;
168 }
169
170 static GstCaps *
171 gst_videofilter_getcaps (GstPad * pad)
172 {
173   GstVideofilter *videofilter;
174   GstVideofilterClass *klass;
175   GstCaps *caps;
176   GstPad *peer;
177   int i;
178
179   GST_DEBUG ("gst_videofilter_getcaps");
180   videofilter = GST_VIDEOFILTER (GST_PAD_PARENT (pad));
181
182   klass = GST_VIDEOFILTER_CLASS (G_OBJECT_GET_CLASS (videofilter));
183
184   /* we can handle anything that was registered */
185   caps = gst_caps_new_empty ();
186   for (i = 0; i < klass->formats->len; i++) {
187     GstCaps *fromcaps;
188
189     fromcaps =
190         gst_caps_new_full (gst_videofilter_format_get_structure
191         (g_ptr_array_index (klass->formats, i)), NULL);
192
193     gst_caps_append (caps, fromcaps);
194   }
195
196   peer = gst_pad_get_peer (pad);
197   if (peer) {
198     GstCaps *peercaps;
199
200     peercaps = gst_pad_get_caps (peer);
201     if (peercaps) {
202       GstCaps *icaps;
203
204       icaps = gst_caps_intersect (peercaps, caps);
205       gst_caps_unref (peercaps);
206       gst_caps_unref (caps);
207       caps = icaps;
208     }
209     //gst_object_unref (peer);
210   }
211
212   return caps;
213 }
214
215 static gboolean
216 gst_videofilter_setcaps (GstPad * pad, GstCaps * caps)
217 {
218   GstVideofilter *videofilter;
219   GstStructure *structure;
220   int width, height;
221   double framerate;
222   int ret;
223
224   videofilter = GST_VIDEOFILTER (GST_PAD_PARENT (pad));
225
226   structure = gst_caps_get_structure (caps, 0);
227
228   videofilter->format =
229       gst_videofilter_find_format_by_structure (videofilter, structure);
230   g_return_val_if_fail (videofilter->format, GST_PAD_LINK_REFUSED);
231
232   ret = gst_structure_get_int (structure, "width", &width);
233   ret &= gst_structure_get_int (structure, "height", &height);
234   ret &= gst_structure_get_double (structure, "framerate", &framerate);
235
236   if (!ret)
237     return FALSE;
238
239   gst_pad_set_caps (videofilter->srcpad, caps);
240
241   GST_DEBUG ("width %d height %d", width, height);
242
243 #if 0
244   if (pad == videofilter->srcpad) {
245     videofilter->to_width = width;
246     videofilter->to_height = height;
247   } else {
248     videofilter->from_width = width;
249     videofilter->from_height = height;
250   }
251 #endif
252   videofilter->to_width = width;
253   videofilter->to_height = height;
254   videofilter->from_width = width;
255   videofilter->from_height = height;
256   videofilter->framerate = framerate;
257
258   gst_videofilter_setup (videofilter);
259
260   return TRUE;
261 }
262
263 static void
264 gst_videofilter_init (GTypeInstance * instance, gpointer g_class)
265 {
266   GstVideofilter *videofilter = GST_VIDEOFILTER (instance);
267   GstPadTemplate *pad_template;
268
269   GST_DEBUG ("gst_videofilter_init");
270
271   pad_template =
272       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
273   g_return_if_fail (pad_template != NULL);
274   videofilter->sinkpad = gst_pad_new_from_template (pad_template, "sink");
275   gst_element_add_pad (GST_ELEMENT (videofilter), videofilter->sinkpad);
276   gst_pad_set_chain_function (videofilter->sinkpad, gst_videofilter_chain);
277   gst_pad_set_setcaps_function (videofilter->sinkpad, gst_videofilter_setcaps);
278   gst_pad_set_getcaps_function (videofilter->sinkpad, gst_videofilter_getcaps);
279
280   pad_template =
281       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
282   g_return_if_fail (pad_template != NULL);
283   videofilter->srcpad = gst_pad_new_from_template (pad_template, "src");
284   gst_element_add_pad (GST_ELEMENT (videofilter), videofilter->srcpad);
285   gst_pad_set_getcaps_function (videofilter->srcpad, gst_videofilter_getcaps);
286
287   videofilter->inited = FALSE;
288 }
289
290 static GstFlowReturn
291 gst_videofilter_chain (GstPad * pad, GstBuffer * buf)
292 {
293   GstVideofilter *videofilter;
294   guchar *data;
295   gulong size;
296   GstBuffer *outbuf;
297   GstFlowReturn ret;
298
299   GST_DEBUG ("gst_videofilter_chain");
300
301   videofilter = GST_VIDEOFILTER (GST_PAD_PARENT (pad));
302
303   if (videofilter->passthru) {
304     return gst_pad_push (videofilter->srcpad, buf);
305   }
306
307   if (GST_PAD_CAPS (pad) == NULL) {
308     return GST_FLOW_NOT_NEGOTIATED;
309   }
310
311   data = GST_BUFFER_DATA (buf);
312   size = GST_BUFFER_SIZE (buf);
313
314   GST_DEBUG ("gst_videofilter_chain: got buffer of %ld bytes in '%s'", size,
315       GST_OBJECT_NAME (videofilter));
316
317   GST_DEBUG
318       ("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
319       size, videofilter->from_width, videofilter->from_height,
320       videofilter->to_width, videofilter->to_height, size,
321       videofilter->from_buf_size, videofilter->to_buf_size);
322
323
324   if (size > videofilter->from_buf_size) {
325     GST_INFO ("buffer size %ld larger than expected (%d)",
326         size, videofilter->from_buf_size);
327     return GST_FLOW_ERROR;
328   }
329
330   ret = gst_pad_alloc_buffer (videofilter->srcpad, GST_BUFFER_OFFSET_NONE,
331       videofilter->to_buf_size, GST_PAD_CAPS (videofilter->srcpad), &outbuf);
332   if (ret != GST_FLOW_OK)
333     goto no_buffer;
334
335   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
336   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
337
338   g_return_val_if_fail (videofilter->format, GST_FLOW_ERROR);
339   GST_DEBUG ("format %s", videofilter->format->fourcc);
340
341   videofilter->in_buf = buf;
342   videofilter->out_buf = outbuf;
343
344   videofilter->format->filter_func (videofilter, GST_BUFFER_DATA (outbuf),
345       data);
346   gst_buffer_unref (buf);
347
348   GST_DEBUG ("gst_videofilter_chain: pushing buffer of %d bytes in '%s'",
349       GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (videofilter));
350
351   ret = gst_pad_push (videofilter->srcpad, outbuf);
352
353   return ret;
354
355 no_buffer:
356   {
357     return ret;
358   }
359 }
360
361 static void
362 gst_videofilter_set_property (GObject * object, guint prop_id,
363     const GValue * value, GParamSpec * pspec)
364 {
365   GstVideofilter *src;
366
367   g_return_if_fail (GST_IS_VIDEOFILTER (object));
368   src = GST_VIDEOFILTER (object);
369
370   GST_DEBUG ("gst_videofilter_set_property");
371   switch (prop_id) {
372     default:
373       break;
374   }
375 }
376
377 static void
378 gst_videofilter_get_property (GObject * object, guint prop_id, GValue * value,
379     GParamSpec * pspec)
380 {
381   GstVideofilter *src;
382
383   g_return_if_fail (GST_IS_VIDEOFILTER (object));
384   src = GST_VIDEOFILTER (object);
385
386   switch (prop_id) {
387     default:
388       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
389       break;
390   }
391 }
392
393 int
394 gst_videofilter_get_input_width (GstVideofilter * videofilter)
395 {
396   g_return_val_if_fail (GST_IS_VIDEOFILTER (videofilter), 0);
397
398   return videofilter->from_width;
399 }
400
401 int
402 gst_videofilter_get_input_height (GstVideofilter * videofilter)
403 {
404   g_return_val_if_fail (GST_IS_VIDEOFILTER (videofilter), 0);
405
406   return videofilter->from_height;
407 }
408
409 void
410 gst_videofilter_set_output_size (GstVideofilter * videofilter,
411     int width, int height)
412 {
413   GstCaps *srccaps;
414   GstStructure *structure;
415
416   g_return_if_fail (GST_IS_VIDEOFILTER (videofilter));
417
418   videofilter->to_width = width;
419   videofilter->to_height = height;
420
421   videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height
422       * videofilter->format->bpp) / 8;
423
424   //srccaps = gst_caps_copy (gst_pad_get_negotiated_caps (videofilter->srcpad));
425   srccaps = gst_caps_copy (GST_PAD_CAPS (videofilter->srcpad));
426   structure = gst_caps_get_structure (srccaps, 0);
427
428   gst_structure_set (structure, "width", G_TYPE_INT, width,
429       "height", G_TYPE_INT, height, NULL);
430
431   gst_pad_set_caps (videofilter->srcpad, srccaps);
432 }
433
434 static void
435 gst_videofilter_setup (GstVideofilter * videofilter)
436 {
437   GstVideofilterClass *klass;
438
439   klass = GST_VIDEOFILTER_CLASS (G_OBJECT_GET_CLASS (videofilter));
440
441   if (klass->setup) {
442     klass->setup (videofilter);
443   }
444
445   if (videofilter->to_width == 0) {
446     videofilter->to_width = videofilter->from_width;
447   }
448   if (videofilter->to_height == 0) {
449     videofilter->to_height = videofilter->from_height;
450   }
451
452   g_return_if_fail (videofilter->format != NULL);
453   g_return_if_fail (videofilter->from_width > 0);
454   g_return_if_fail (videofilter->from_height > 0);
455   g_return_if_fail (videofilter->to_width > 0);
456   g_return_if_fail (videofilter->to_height > 0);
457
458   videofilter->from_buf_size =
459       (videofilter->from_width * videofilter->from_height *
460       videofilter->format->bpp) / 8;
461   videofilter->to_buf_size =
462       (videofilter->to_width * videofilter->to_height *
463       videofilter->format->bpp) / 8;
464
465   videofilter->inited = TRUE;
466 }
467
468 GstVideofilterFormat *
469 gst_videofilter_find_format_by_structure (GstVideofilter * videofilter,
470     const GstStructure * structure)
471 {
472   int i;
473   GstVideofilterClass *klass;
474   GstVideofilterFormat *format;
475   gboolean ret;
476
477   klass = GST_VIDEOFILTER_CLASS (G_OBJECT_GET_CLASS (videofilter));
478
479   g_return_val_if_fail (structure != NULL, NULL);
480
481   if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) {
482     guint32 fourcc;
483
484     ret = gst_structure_get_fourcc (structure, "format", &fourcc);
485     if (!ret)
486       return NULL;
487     for (i = 0; i < klass->formats->len; i++) {
488       guint32 format_fourcc;
489
490       format = g_ptr_array_index (klass->formats, i);
491       format_fourcc = GST_STR_FOURCC (format->fourcc);
492       if (format->depth == 0 && format_fourcc == fourcc) {
493         return format;
494       }
495     }
496   } else if (strcmp (gst_structure_get_name (structure), "video/x-raw-rgb")
497       == 0) {
498     int bpp;
499     int depth;
500     int endianness;
501     int red_mask;
502     int green_mask;
503     int blue_mask;
504
505     ret = gst_structure_get_int (structure, "bpp", &bpp);
506     ret &= gst_structure_get_int (structure, "depth", &depth);
507     ret &= gst_structure_get_int (structure, "endianness", &endianness);
508     ret &= gst_structure_get_int (structure, "red_mask", &red_mask);
509     ret &= gst_structure_get_int (structure, "green_mask", &green_mask);
510     ret &= gst_structure_get_int (structure, "blue_mask", &blue_mask);
511     if (!ret)
512       return NULL;
513     for (i = 0; i < klass->formats->len; i++) {
514       format = g_ptr_array_index (klass->formats, i);
515       if (format->bpp == bpp && format->depth == depth &&
516           format->endianness == endianness && format->red_mask == red_mask &&
517           format->green_mask == green_mask && format->blue_mask == blue_mask) {
518         return format;
519       }
520     }
521   }
522
523   return NULL;
524 }
525
526 void
527 gst_videofilter_class_add_format (GstVideofilterClass * videofilterclass,
528     GstVideofilterFormat * format)
529 {
530   g_ptr_array_add (videofilterclass->formats, format);
531 }
532
533 void
534 gst_videofilter_class_add_pad_templates (GstVideofilterClass *
535     videofilter_class)
536 {
537   GstElementClass *element_class = GST_ELEMENT_CLASS (videofilter_class);
538
539   gst_element_class_add_pad_template (element_class,
540       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
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_videofilter_class_get_capslist (videofilter_class)));
546 }
547
548 static gboolean
549 plugin_init (GstPlugin * plugin)
550 {
551   return TRUE;
552 }
553
554 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
555     GST_VERSION_MINOR,
556     "gstvideofilter",
557     "Video filter parent class",
558     plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)