VideoFilter inherits from
[platform/upstream/gstreamer.git] / gst / videofilter / gstvideoflip.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 /*
22  * This file was (probably) generated from gstvideoflip.c,
23  * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "gstvideoflip.h"
31
32 #include <gst/video/video.h>
33
34 /* GstVideoflip signals and args */
35 enum
36 {
37   ARG_0,
38   ARG_METHOD
39       /* FILL ME */
40 };
41
42 GST_DEBUG_CATEGORY (videoflip_debug);
43 #define GST_CAT_DEFAULT videoflip_debug
44
45 static GstElementDetails videoflip_details =
46 GST_ELEMENT_DETAILS ("Video Flipper",
47     "Filter/Effect/Video",
48     "Flips and rotates video",
49     "David Schleef <ds@schleef.org>");
50
51 static GstStaticPadTemplate gst_videoflip_src_template =
52 GST_STATIC_PAD_TEMPLATE ("src",
53     GST_PAD_SRC,
54     GST_PAD_ALWAYS,
55     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
56     );
57
58 static GstStaticPadTemplate gst_videoflip_sink_template =
59 GST_STATIC_PAD_TEMPLATE ("sink",
60     GST_PAD_SINK,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
63     );
64
65 static GstVideofilterClass *parent_class = NULL;
66
67 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
68
69 static GType
70 gst_videoflip_method_get_type (void)
71 {
72   static GType videoflip_method_type = 0;
73   static GEnumValue videoflip_methods[] = {
74     {GST_VIDEOFLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
75     {GST_VIDEOFLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
76     {GST_VIDEOFLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
77     {GST_VIDEOFLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
78         "counterclockwise"},
79     {GST_VIDEOFLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
80     {GST_VIDEOFLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
81     {GST_VIDEOFLIP_METHOD_TRANS,
82         "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
83     {GST_VIDEOFLIP_METHOD_OTHER,
84         "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
85     {0, NULL, NULL},
86   };
87
88   if (!videoflip_method_type) {
89     videoflip_method_type = g_enum_register_static ("GstVideoflipMethod",
90         videoflip_methods);
91   }
92   return videoflip_method_type;
93 }
94
95 static gboolean
96 gst_videoflip_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
97     GstCaps * outcaps)
98 {
99   GstVideoflip *vf;
100   GstStructure *in_s, *out_s;
101   gboolean ret = FALSE;
102
103   vf = GST_VIDEOFLIP (btrans);
104
105   in_s = gst_caps_get_structure (incaps, 0);
106   out_s = gst_caps_get_structure (outcaps, 0);
107
108   if (gst_structure_get_int (in_s, "width", &vf->from_width) &&
109       gst_structure_get_int (in_s, "height", &vf->from_height) &&
110       gst_structure_get_int (out_s, "width", &vf->to_width) &&
111       gst_structure_get_int (out_s, "height", &vf->to_height)) {
112     /* Check that they are correct */
113     switch (vf->method) {
114       case GST_VIDEOFLIP_METHOD_90R:
115       case GST_VIDEOFLIP_METHOD_90L:
116       case GST_VIDEOFLIP_METHOD_TRANS:
117       case GST_VIDEOFLIP_METHOD_OTHER:
118         if ((vf->from_width != vf->to_height) ||
119             (vf->from_height != vf->to_width)) {
120           GST_DEBUG_OBJECT (vf, "we are inverting width and height but caps "
121               "are not correct : %dx%d to %dx%d", vf->from_width,
122               vf->from_height, vf->to_width, vf->to_height);
123           goto beach;
124         }
125         break;
126       case GST_VIDEOFLIP_METHOD_IDENTITY:
127
128         break;
129       case GST_VIDEOFLIP_METHOD_180:
130       case GST_VIDEOFLIP_METHOD_HORIZ:
131       case GST_VIDEOFLIP_METHOD_VERT:
132         if ((vf->from_width != vf->to_width) ||
133             (vf->from_height != vf->to_height)) {
134           GST_DEBUG_OBJECT (vf, "we are keeping width and height but caps "
135               "are not correct : %dx%d to %dx%d", vf->from_width,
136               vf->from_height, vf->to_width, vf->to_height);
137           goto beach;
138         }
139         break;
140       default:
141         g_assert_not_reached ();
142         break;
143     }
144   }
145
146   ret = TRUE;
147
148 beach:
149   return ret;
150 }
151
152 static GstCaps *
153 gst_videoflip_transform_caps (GstBaseTransform * trans,
154     GstPadDirection direction, GstCaps * caps)
155 {
156   GstVideoflip *videoflip;
157   GstCaps *ret;
158   gint width, height, i;
159
160   videoflip = GST_VIDEOFLIP (trans);
161
162   ret = gst_caps_copy (caps);
163
164   for (i = 0; i < gst_caps_get_size (ret); i++) {
165     GstStructure *structure = gst_caps_get_structure (ret, i);
166
167     if (gst_structure_get_int (structure, "width", &width) &&
168         gst_structure_get_int (structure, "height", &height)) {
169
170       switch (videoflip->method) {
171         case GST_VIDEOFLIP_METHOD_90R:
172         case GST_VIDEOFLIP_METHOD_90L:
173         case GST_VIDEOFLIP_METHOD_TRANS:
174         case GST_VIDEOFLIP_METHOD_OTHER:
175           gst_structure_set (structure, "width", G_TYPE_INT, height,
176               "height", G_TYPE_INT, width, NULL);
177           break;
178         case GST_VIDEOFLIP_METHOD_IDENTITY:
179         case GST_VIDEOFLIP_METHOD_180:
180         case GST_VIDEOFLIP_METHOD_HORIZ:
181         case GST_VIDEOFLIP_METHOD_VERT:
182           gst_structure_set (structure, "width", G_TYPE_INT, width,
183               "height", G_TYPE_INT, height, NULL);
184           break;
185         default:
186           g_assert_not_reached ();
187           break;
188       }
189     }
190   }
191
192   GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
193       GST_PTR_FORMAT, caps, ret);
194
195   return ret;
196 }
197
198 /* Useful macros */
199 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
200 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
201 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
202
203 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
204 #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
205 #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
206
207 #define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
208
209 static gboolean
210 gst_videoflip_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
211     guint * size)
212 {
213   GstVideoflip *videoflip;
214   GstStructure *structure;
215   gboolean ret = FALSE;
216   gint width, height;
217
218   videoflip = GST_VIDEOFLIP (btrans);
219
220   structure = gst_caps_get_structure (caps, 0);
221
222   if (gst_structure_get_int (structure, "width", &width) &&
223       gst_structure_get_int (structure, "height", &height)) {
224     *size = GST_VIDEO_I420_SIZE (width, height);
225     ret = TRUE;
226     GST_DEBUG_OBJECT (videoflip, "our frame size is %d bytes (%dx%d)", *size,
227         width, height);
228   }
229
230   return ret;
231 }
232
233 static GstFlowReturn
234 gst_videoflip_flip (GstVideoflip * videoflip, unsigned char *dest,
235     unsigned char *src, int sw, int sh, int dw, int dh)
236 {
237   GstFlowReturn ret = GST_FLOW_OK;
238   int x, y;
239
240   switch (videoflip->method) {
241     case GST_VIDEOFLIP_METHOD_90R:
242       for (y = 0; y < dh; y++) {
243         for (x = 0; x < dw; x++) {
244           dest[y * dw + x] = src[(sh - 1 - x) * sw + y];
245         }
246       }
247       break;
248     case GST_VIDEOFLIP_METHOD_90L:
249       for (y = 0; y < dh; y++) {
250         for (x = 0; x < dw; x++) {
251           dest[y * dw + x] = src[x * sw + (sw - 1 - y)];
252         }
253       }
254       break;
255     case GST_VIDEOFLIP_METHOD_180:
256       for (y = 0; y < dh; y++) {
257         for (x = 0; x < dw; x++) {
258           dest[y * dw + x] = src[(sh - 1 - y) * sw + (sw - 1 - x)];
259         }
260       }
261       break;
262     case GST_VIDEOFLIP_METHOD_HORIZ:
263       for (y = 0; y < dh; y++) {
264         for (x = 0; x < dw; x++) {
265           dest[y * dw + x] = src[y * sw + (sw - 1 - x)];
266         }
267       }
268       break;
269     case GST_VIDEOFLIP_METHOD_VERT:
270       for (y = 0; y < dh; y++) {
271         for (x = 0; x < dw; x++) {
272           dest[y * dw + x] = src[(sh - 1 - y) * sw + x];
273         }
274       }
275       break;
276     case GST_VIDEOFLIP_METHOD_TRANS:
277       for (y = 0; y < dh; y++) {
278         for (x = 0; x < dw; x++) {
279           dest[y * dw + x] = src[x * sw + y];
280         }
281       }
282       break;
283     case GST_VIDEOFLIP_METHOD_OTHER:
284       for (y = 0; y < dh; y++) {
285         for (x = 0; x < dw; x++) {
286           dest[y * dw + x] = src[(sh - 1 - x) * sw + (sw - 1 - y)];
287         }
288       }
289       break;
290     default:
291       ret = GST_FLOW_ERROR;
292       break;
293   }
294
295   return ret;
296 }
297
298 static GstFlowReturn
299 gst_videoflip_transform (GstBaseTransform * trans, GstBuffer * in,
300     GstBuffer * out)
301 {
302   GstVideoflip *videoflip;
303   gpointer dest, src;
304   int sw, sh, dw, dh;
305   GstFlowReturn ret = GST_FLOW_OK;
306
307   videoflip = GST_VIDEOFLIP (trans);
308
309   gst_buffer_stamp (out, in);
310
311   src = GST_BUFFER_DATA (in);
312   dest = GST_BUFFER_DATA (out);
313   sw = videoflip->from_width;
314   sh = videoflip->from_height;
315   dw = videoflip->to_width;
316   dh = videoflip->to_height;
317
318   GST_LOG_OBJECT (videoflip, "videoflip: scaling planar 4:1:1 %dx%d to %dx%d",
319       sw, sh, dw, dh);
320
321   ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
322   if (ret != GST_FLOW_OK)
323     goto beach;
324
325   src += sw * sh;
326   dest += dw * dh;
327
328   dh = dh >> 1;
329   dw = dw >> 1;
330   sh = sh >> 1;
331   sw = sw >> 1;
332
333   ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
334   if (ret != GST_FLOW_OK)
335     goto beach;
336
337   src += sw * sh;
338   dest += dw * dh;
339
340   ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
341
342 beach:
343   return ret;
344 }
345
346 static gboolean
347 gst_videoflip_handle_src_event (GstPad * pad, GstEvent * event)
348 {
349   GstVideoflip *vf;
350   gboolean ret;
351   gdouble x, y;
352   GstStructure *structure;
353
354   vf = GST_VIDEOFLIP (gst_pad_get_parent (pad));
355
356   GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
357
358   switch (GST_EVENT_TYPE (event)) {
359     case GST_EVENT_NAVIGATION:
360       event =
361           GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
362
363       structure = (GstStructure *) gst_event_get_structure (event);
364       if (gst_structure_get_double (structure, "pointer_x", &x) &&
365           gst_structure_get_double (structure, "pointer_y", &y)) {
366         switch (vf->method) {
367           case GST_VIDEOFLIP_METHOD_90R:
368           case GST_VIDEOFLIP_METHOD_OTHER:
369             x = y;
370             y = vf->to_width - x;
371             break;
372           case GST_VIDEOFLIP_METHOD_90L:
373           case GST_VIDEOFLIP_METHOD_TRANS:
374             x = vf->to_height - y;
375             y = x;
376             break;
377           case GST_VIDEOFLIP_METHOD_180:
378             x = vf->to_width - x;
379             y = vf->to_height - y;
380             break;
381           case GST_VIDEOFLIP_METHOD_HORIZ:
382             x = vf->to_width - x;
383             y = y;
384             break;
385           case GST_VIDEOFLIP_METHOD_VERT:
386             x = x;
387             y = vf->to_height - y;
388             break;
389           default:
390             x = x;
391             y = y;
392             break;
393         }
394         gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x,
395             "pointer_y", G_TYPE_DOUBLE, y, NULL);
396       }
397       break;
398     default:
399       break;
400   }
401
402   ret = gst_pad_event_default (pad, event);
403
404   gst_object_unref (vf);
405
406   return ret;
407 }
408
409 static void
410 gst_videoflip_set_property (GObject * object, guint prop_id,
411     const GValue * value, GParamSpec * pspec)
412 {
413   GstVideoflip *videoflip;
414   GstVideofilter *videofilter;
415
416   g_return_if_fail (GST_IS_VIDEOFLIP (object));
417   videoflip = GST_VIDEOFLIP (object);
418   videofilter = GST_VIDEOFILTER (object);
419
420   switch (prop_id) {
421     case ARG_METHOD:
422     {
423       GstVideoflipMethod method;
424
425       method = g_value_get_enum (value);
426       if (method != videoflip->method) {
427         GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
428
429         g_mutex_lock (btrans->transform_lock);
430         gst_pad_set_caps (btrans->sinkpad, NULL);
431         gst_pad_set_caps (btrans->srcpad, NULL);
432         g_mutex_unlock (btrans->transform_lock);
433         videoflip->method = method;
434       }
435     }
436       break;
437     default:
438       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
439       break;
440   }
441 }
442
443 static void
444 gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
445     GParamSpec * pspec)
446 {
447   GstVideoflip *videoflip;
448
449   g_return_if_fail (GST_IS_VIDEOFLIP (object));
450   videoflip = GST_VIDEOFLIP (object);
451
452   switch (prop_id) {
453     case ARG_METHOD:
454       g_value_set_enum (value, videoflip->method);
455       break;
456     default:
457       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
458       break;
459   }
460 }
461
462 static void
463 gst_videoflip_base_init (gpointer g_class)
464 {
465   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
466
467   gst_element_class_set_details (element_class, &videoflip_details);
468
469   gst_element_class_add_pad_template (element_class,
470       gst_static_pad_template_get (&gst_videoflip_sink_template));
471   gst_element_class_add_pad_template (element_class,
472       gst_static_pad_template_get (&gst_videoflip_src_template));
473 }
474
475 static void
476 gst_videoflip_class_init (gpointer klass, gpointer class_data)
477 {
478   GObjectClass *gobject_class;
479   GstBaseTransformClass *trans_class;
480
481   gobject_class = (GObjectClass *) klass;
482   trans_class = (GstBaseTransformClass *) klass;
483
484   parent_class = g_type_class_peek_parent (klass);
485
486   gobject_class->set_property = gst_videoflip_set_property;
487   gobject_class->get_property = gst_videoflip_get_property;
488
489   g_object_class_install_property (gobject_class, ARG_METHOD,
490       g_param_spec_enum ("method", "method", "method",
491           GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
492           G_PARAM_READWRITE));
493
494   trans_class->transform_caps =
495       GST_DEBUG_FUNCPTR (gst_videoflip_transform_caps);
496   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_videoflip_set_caps);
497   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_videoflip_get_unit_size);
498   trans_class->transform = GST_DEBUG_FUNCPTR (gst_videoflip_transform);
499 }
500
501 static void
502 gst_videoflip_init (GTypeInstance * instance, gpointer g_class)
503 {
504   GstVideoflip *videoflip = GST_VIDEOFLIP (instance);
505   GstBaseTransform *btrans = GST_BASE_TRANSFORM (instance);
506
507   GST_DEBUG_OBJECT (videoflip, "gst_videoflip_init");
508
509   videoflip->method = GST_VIDEOFLIP_METHOD_90R;
510
511   gst_pad_set_event_function (btrans->srcpad,
512       GST_DEBUG_FUNCPTR (gst_videoflip_handle_src_event));
513 }
514
515 static gboolean
516 plugin_init (GstPlugin * plugin)
517 {
518   GST_DEBUG_CATEGORY_INIT (videoflip_debug, "videoflip", 0, "videoflip");
519
520   return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
521       GST_TYPE_VIDEOFLIP);
522 }
523
524 GType
525 gst_videoflip_get_type (void)
526 {
527   static GType videoflip_type = 0;
528
529   if (!videoflip_type) {
530     static const GTypeInfo videoflip_info = {
531       sizeof (GstVideoflipClass),
532       gst_videoflip_base_init,
533       NULL,
534       gst_videoflip_class_init,
535       NULL,
536       NULL,
537       sizeof (GstVideoflip),
538       0,
539       gst_videoflip_init,
540     };
541
542     videoflip_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
543         "GstVideoflip", &videoflip_info, 0);
544   }
545   return videoflip_type;
546 }
547
548 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
549     GST_VERSION_MINOR,
550     "videoflip",
551     "Flips and rotates video",
552     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);