Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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  * Copyright (C) <2010> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  * Copyright (C) <2011> Youness Alaoui <youness.alaoui@collabora.co.uk>
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 /*
24  * This file was (probably) generated from gstvideoflip.c,
25  * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
26  */
27 /**
28  * SECTION:element-videoflip
29  *
30  * Flips and rotates video.
31  *
32  * <refsect2>
33  * <title>Example launch line</title>
34  * |[
35  * gst-launch videotestsrc ! videoflip method=clockwise ! ffmpegcolorspace ! ximagesink
36  * ]| This pipeline flips the test image 90 degrees clockwise.
37  * </refsect2>
38  *
39  * Last reviewed on 2010-04-18 (0.10.22)
40  */
41
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include "gstvideoflip.h"
48
49 #include <string.h>
50 #include <gst/gst.h>
51 #include <gst/controller/gstcontroller.h>
52 #include <gst/video/video.h>
53
54 /* GstVideoFlip properties */
55 enum
56 {
57   PROP_0,
58   PROP_METHOD
59       /* FILL ME */
60 };
61
62 #define PROP_METHOD_DEFAULT GST_VIDEO_FLIP_METHOD_IDENTITY
63
64 GST_DEBUG_CATEGORY_STATIC (video_flip_debug);
65 #define GST_CAT_DEFAULT video_flip_debug
66
67 static GstStaticPadTemplate gst_video_flip_src_template =
68     GST_STATIC_PAD_TEMPLATE ("src",
69     GST_PAD_SRC,
70     GST_PAD_ALWAYS,
71     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
72         GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
73         GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
74         GST_VIDEO_CAPS_YUV ("Y444") ";"
75         GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
76         GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
77         GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
78         GST_VIDEO_CAPS_YUV ("I420") ";"
79         GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";"
80         GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";"
81         GST_VIDEO_CAPS_YUV ("YVYU")
82
83     )
84     );
85
86 static GstStaticPadTemplate gst_video_flip_sink_template =
87     GST_STATIC_PAD_TEMPLATE ("sink",
88     GST_PAD_SINK,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
91         GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
92         GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
93         GST_VIDEO_CAPS_YUV ("Y444") ";"
94         GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
95         GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
96         GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
97         GST_VIDEO_CAPS_YUV ("I420") ";"
98         GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";"
99         GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";"
100         GST_VIDEO_CAPS_YUV ("YVYU")
101     )
102     );
103
104 #define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
105
106 static const GEnumValue video_flip_methods[] = {
107   {GST_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
108   {GST_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
109   {GST_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
110   {GST_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
111       "counterclockwise"},
112   {GST_VIDEO_FLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
113   {GST_VIDEO_FLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
114   {GST_VIDEO_FLIP_METHOD_TRANS,
115       "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
116   {GST_VIDEO_FLIP_METHOD_OTHER,
117       "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
118   {0, NULL, NULL},
119 };
120
121 static GType
122 gst_video_flip_method_get_type (void)
123 {
124   static GType video_flip_method_type = 0;
125
126   if (!video_flip_method_type) {
127     video_flip_method_type = g_enum_register_static ("GstVideoFlipMethod",
128         video_flip_methods);
129   }
130   return video_flip_method_type;
131 }
132
133 GST_BOILERPLATE (GstVideoFlip, gst_video_flip, GstVideoFilter,
134     GST_TYPE_VIDEO_FILTER);
135
136 static GstCaps *
137 gst_video_flip_transform_caps (GstBaseTransform * trans,
138     GstPadDirection direction, GstCaps * caps)
139 {
140   GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
141   GstCaps *ret;
142   gint width, height, i;
143
144   ret = gst_caps_copy (caps);
145
146   for (i = 0; i < gst_caps_get_size (ret); i++) {
147     GstStructure *structure = gst_caps_get_structure (ret, i);
148     gint par_n, par_d;
149
150     if (gst_structure_get_int (structure, "width", &width) &&
151         gst_structure_get_int (structure, "height", &height)) {
152
153       switch (videoflip->method) {
154         case GST_VIDEO_FLIP_METHOD_90R:
155         case GST_VIDEO_FLIP_METHOD_90L:
156         case GST_VIDEO_FLIP_METHOD_TRANS:
157         case GST_VIDEO_FLIP_METHOD_OTHER:
158           gst_structure_set (structure, "width", G_TYPE_INT, height,
159               "height", G_TYPE_INT, width, NULL);
160           if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
161                   &par_n, &par_d)) {
162             if (par_n != 1 || par_d != 1) {
163               GValue val = { 0, };
164
165               g_value_init (&val, GST_TYPE_FRACTION);
166               gst_value_set_fraction (&val, par_d, par_n);
167               gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
168               g_value_unset (&val);
169             }
170           }
171           break;
172         case GST_VIDEO_FLIP_METHOD_IDENTITY:
173         case GST_VIDEO_FLIP_METHOD_180:
174         case GST_VIDEO_FLIP_METHOD_HORIZ:
175         case GST_VIDEO_FLIP_METHOD_VERT:
176           gst_structure_set (structure, "width", G_TYPE_INT, width,
177               "height", G_TYPE_INT, height, NULL);
178           break;
179         default:
180           g_assert_not_reached ();
181           break;
182       }
183     }
184   }
185
186   GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
187       GST_PTR_FORMAT, caps, ret);
188
189   return ret;
190 }
191
192 static gboolean
193 gst_video_flip_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
194     guint * size)
195 {
196   GstVideoFormat format;
197   gint width, height;
198
199   if (!gst_video_format_parse_caps (caps, &format, &width, &height))
200     return FALSE;
201
202   *size = gst_video_format_get_size (format, width, height);
203
204   GST_DEBUG_OBJECT (btrans, "our frame size is %d bytes (%dx%d)", *size,
205       width, height);
206
207   return TRUE;
208 }
209
210 static void
211 gst_video_flip_planar_yuv (GstVideoFlip * videoflip, guint8 * dest,
212     const guint8 * src)
213 {
214   gint x, y;
215   guint8 const *s;
216   guint8 *d;
217   GstVideoFormat format = videoflip->format;
218   gint sw = videoflip->from_width;
219   gint sh = videoflip->from_height;
220   gint dw = videoflip->to_width;
221   gint dh = videoflip->to_height;
222   gint src_y_stride, src_u_stride, src_v_stride;
223   gint src_y_offset, src_u_offset, src_v_offset;
224   gint src_y_height, src_u_height, src_v_height;
225   gint src_y_width, src_u_width, src_v_width;
226   gint dest_y_stride, dest_u_stride, dest_v_stride;
227   gint dest_y_offset, dest_u_offset, dest_v_offset;
228   gint dest_y_height, dest_u_height, dest_v_height;
229   gint dest_y_width, dest_u_width, dest_v_width;
230
231   src_y_stride = gst_video_format_get_row_stride (format, 0, sw);
232   src_u_stride = gst_video_format_get_row_stride (format, 1, sw);
233   src_v_stride = gst_video_format_get_row_stride (format, 2, sw);
234
235   dest_y_stride = gst_video_format_get_row_stride (format, 0, dw);
236   dest_u_stride = gst_video_format_get_row_stride (format, 1, dw);
237   dest_v_stride = gst_video_format_get_row_stride (format, 2, dw);
238
239   src_y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
240   src_u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
241   src_v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);
242
243   dest_y_offset = gst_video_format_get_component_offset (format, 0, dw, dh);
244   dest_u_offset = gst_video_format_get_component_offset (format, 1, dw, dh);
245   dest_v_offset = gst_video_format_get_component_offset (format, 2, dw, dh);
246
247   src_y_width = gst_video_format_get_component_width (format, 0, sw);
248   src_u_width = gst_video_format_get_component_width (format, 1, sw);
249   src_v_width = gst_video_format_get_component_width (format, 2, sw);
250
251   dest_y_width = gst_video_format_get_component_width (format, 0, dw);
252   dest_u_width = gst_video_format_get_component_width (format, 1, dw);
253   dest_v_width = gst_video_format_get_component_width (format, 2, dw);
254
255   src_y_height = gst_video_format_get_component_height (format, 0, sh);
256   src_u_height = gst_video_format_get_component_height (format, 1, sh);
257   src_v_height = gst_video_format_get_component_height (format, 2, sh);
258
259   dest_y_height = gst_video_format_get_component_height (format, 0, dh);
260   dest_u_height = gst_video_format_get_component_height (format, 1, dh);
261   dest_v_height = gst_video_format_get_component_height (format, 2, dh);
262
263   switch (videoflip->method) {
264     case GST_VIDEO_FLIP_METHOD_90R:
265       /* Flip Y */
266       s = src + src_y_offset;
267       d = dest + dest_y_offset;
268       for (y = 0; y < dest_y_height; y++) {
269         for (x = 0; x < dest_y_width; x++) {
270           d[y * dest_y_stride + x] =
271               s[(src_y_height - 1 - x) * src_y_stride + y];
272         }
273       }
274       /* Flip U */
275       s = src + src_u_offset;
276       d = dest + dest_u_offset;
277       for (y = 0; y < dest_u_height; y++) {
278         for (x = 0; x < dest_u_width; x++) {
279           d[y * dest_u_stride + x] =
280               s[(src_u_height - 1 - x) * src_u_stride + y];
281         }
282       }
283       /* Flip V */
284       s = src + src_v_offset;
285       d = dest + dest_v_offset;
286       for (y = 0; y < dest_v_height; y++) {
287         for (x = 0; x < dest_v_width; x++) {
288           d[y * dest_v_stride + x] =
289               s[(src_v_height - 1 - x) * src_v_stride + y];
290         }
291       }
292       break;
293     case GST_VIDEO_FLIP_METHOD_90L:
294       /* Flip Y */
295       s = src + src_y_offset;
296       d = dest + dest_y_offset;
297       for (y = 0; y < dest_y_height; y++) {
298         for (x = 0; x < dest_y_width; x++) {
299           d[y * dest_y_stride + x] =
300               s[x * src_y_stride + (src_y_width - 1 - y)];
301         }
302       }
303       /* Flip U */
304       s = src + src_u_offset;
305       d = dest + dest_u_offset;
306       for (y = 0; y < dest_u_height; y++) {
307         for (x = 0; x < dest_u_width; x++) {
308           d[y * dest_u_stride + x] =
309               s[x * src_u_stride + (src_u_width - 1 - y)];
310         }
311       }
312       /* Flip V */
313       s = src + src_v_offset;
314       d = dest + dest_v_offset;
315       for (y = 0; y < dest_v_height; y++) {
316         for (x = 0; x < dest_v_width; x++) {
317           d[y * dest_v_stride + x] =
318               s[x * src_v_stride + (src_v_width - 1 - y)];
319         }
320       }
321       break;
322     case GST_VIDEO_FLIP_METHOD_180:
323       /* Flip Y */
324       s = src + src_y_offset;
325       d = dest + dest_y_offset;
326       for (y = 0; y < dest_y_height; y++) {
327         for (x = 0; x < dest_y_width; x++) {
328           d[y * dest_y_stride + x] =
329               s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
330         }
331       }
332       /* Flip U */
333       s = src + src_u_offset;
334       d = dest + dest_u_offset;
335       for (y = 0; y < dest_u_height; y++) {
336         for (x = 0; x < dest_u_width; x++) {
337           d[y * dest_u_stride + x] =
338               s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
339         }
340       }
341       /* Flip V */
342       s = src + src_v_offset;
343       d = dest + dest_v_offset;
344       for (y = 0; y < dest_v_height; y++) {
345         for (x = 0; x < dest_v_width; x++) {
346           d[y * dest_v_stride + x] =
347               s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
348         }
349       }
350       break;
351     case GST_VIDEO_FLIP_METHOD_HORIZ:
352       /* Flip Y */
353       s = src + src_y_offset;
354       d = dest + dest_y_offset;
355       for (y = 0; y < dest_y_height; y++) {
356         for (x = 0; x < dest_y_width; x++) {
357           d[y * dest_y_stride + x] =
358               s[y * src_y_stride + (src_y_width - 1 - x)];
359         }
360       }
361       /* Flip U */
362       s = src + src_u_offset;
363       d = dest + dest_u_offset;
364       for (y = 0; y < dest_u_height; y++) {
365         for (x = 0; x < dest_u_width; x++) {
366           d[y * dest_u_stride + x] =
367               s[y * src_u_stride + (src_u_width - 1 - x)];
368         }
369       }
370       /* Flip V */
371       s = src + src_v_offset;
372       d = dest + dest_v_offset;
373       for (y = 0; y < dest_v_height; y++) {
374         for (x = 0; x < dest_v_width; x++) {
375           d[y * dest_v_stride + x] =
376               s[y * src_v_stride + (src_v_width - 1 - x)];
377         }
378       }
379       break;
380     case GST_VIDEO_FLIP_METHOD_VERT:
381       /* Flip Y */
382       s = src + src_y_offset;
383       d = dest + dest_y_offset;
384       for (y = 0; y < dest_y_height; y++) {
385         for (x = 0; x < dest_y_width; x++) {
386           d[y * dest_y_stride + x] =
387               s[(src_y_height - 1 - y) * src_y_stride + x];
388         }
389       }
390       /* Flip U */
391       s = src + src_u_offset;
392       d = dest + dest_u_offset;
393       for (y = 0; y < dest_u_height; y++) {
394         for (x = 0; x < dest_u_width; x++) {
395           d[y * dest_u_stride + x] =
396               s[(src_u_height - 1 - y) * src_u_stride + x];
397         }
398       }
399       /* Flip V */
400       s = src + src_v_offset;
401       d = dest + dest_v_offset;
402       for (y = 0; y < dest_v_height; y++) {
403         for (x = 0; x < dest_v_width; x++) {
404           d[y * dest_v_stride + x] =
405               s[(src_v_height - 1 - y) * src_v_stride + x];
406         }
407       }
408       break;
409     case GST_VIDEO_FLIP_METHOD_TRANS:
410       /* Flip Y */
411       s = src + src_y_offset;
412       d = dest + dest_y_offset;
413       for (y = 0; y < dest_y_height; y++) {
414         for (x = 0; x < dest_y_width; x++) {
415           d[y * dest_y_stride + x] = s[x * src_y_stride + y];
416         }
417       }
418       /* Flip U */
419       s = src + src_u_offset;
420       d = dest + dest_u_offset;
421       for (y = 0; y < dest_u_height; y++) {
422         for (x = 0; x < dest_u_width; x++) {
423           d[y * dest_u_stride + x] = s[x * src_u_stride + y];
424         }
425       }
426       /* Flip V */
427       s = src + src_v_offset;
428       d = dest + dest_v_offset;
429       for (y = 0; y < dest_u_height; y++) {
430         for (x = 0; x < dest_u_width; x++) {
431           d[y * dest_v_stride + x] = s[x * src_v_stride + y];
432         }
433       }
434       break;
435     case GST_VIDEO_FLIP_METHOD_OTHER:
436       /* Flip Y */
437       s = src + src_y_offset;
438       d = dest + dest_y_offset;
439       for (y = 0; y < dest_y_height; y++) {
440         for (x = 0; x < dest_y_width; x++) {
441           d[y * dest_y_stride + x] =
442               s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
443         }
444       }
445       /* Flip U */
446       s = src + src_u_offset;
447       d = dest + dest_u_offset;
448       for (y = 0; y < dest_u_height; y++) {
449         for (x = 0; x < dest_u_width; x++) {
450           d[y * dest_u_stride + x] =
451               s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
452         }
453       }
454       /* Flip V */
455       s = src + src_v_offset;
456       d = dest + dest_v_offset;
457       for (y = 0; y < dest_v_height; y++) {
458         for (x = 0; x < dest_v_width; x++) {
459           d[y * dest_v_stride + x] =
460               s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
461         }
462       }
463       break;
464     case GST_VIDEO_FLIP_METHOD_IDENTITY:
465       g_assert_not_reached ();
466       break;
467     default:
468       g_assert_not_reached ();
469       break;
470   }
471 }
472
473 static void
474 gst_video_flip_packed_simple (GstVideoFlip * videoflip, guint8 * dest,
475     const guint8 * src)
476 {
477   gint x, y, z;
478   guint8 const *s = src;
479   guint8 *d = dest;
480   GstVideoFormat format = videoflip->format;
481   gint sw = videoflip->from_width;
482   gint sh = videoflip->from_height;
483   gint dw = videoflip->to_width;
484   gint dh = videoflip->to_height;
485   gint src_stride, dest_stride;
486   gint bpp;
487
488   src_stride = gst_video_format_get_row_stride (format, 0, sw);
489   dest_stride = gst_video_format_get_row_stride (format, 0, dw);
490   /* This is only true for non-subsampled formats! */
491   bpp = gst_video_format_get_pixel_stride (format, 0);
492
493   switch (videoflip->method) {
494     case GST_VIDEO_FLIP_METHOD_90R:
495       for (y = 0; y < dh; y++) {
496         for (x = 0; x < dw; x++) {
497           for (z = 0; z < bpp; z++) {
498             d[y * dest_stride + x * bpp + z] =
499                 s[(sh - 1 - x) * src_stride + y * bpp + z];
500           }
501         }
502       }
503       break;
504     case GST_VIDEO_FLIP_METHOD_90L:
505       for (y = 0; y < dh; y++) {
506         for (x = 0; x < dw; x++) {
507           for (z = 0; z < bpp; z++) {
508             d[y * dest_stride + x * bpp + z] =
509                 s[x * src_stride + (sw - 1 - y) * bpp + z];
510           }
511         }
512       }
513       break;
514     case GST_VIDEO_FLIP_METHOD_180:
515       for (y = 0; y < dh; y++) {
516         for (x = 0; x < dw; x++) {
517           for (z = 0; z < bpp; z++) {
518             d[y * dest_stride + x * bpp + z] =
519                 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + z];
520           }
521         }
522       }
523       break;
524     case GST_VIDEO_FLIP_METHOD_HORIZ:
525       for (y = 0; y < dh; y++) {
526         for (x = 0; x < dw; x++) {
527           for (z = 0; z < bpp; z++) {
528             d[y * dest_stride + x * bpp + z] =
529                 s[y * src_stride + (sw - 1 - x) * bpp + z];
530           }
531         }
532       }
533       break;
534     case GST_VIDEO_FLIP_METHOD_VERT:
535       for (y = 0; y < dh; y++) {
536         for (x = 0; x < dw; x++) {
537           for (z = 0; z < bpp; z++) {
538             d[y * dest_stride + x * bpp + z] =
539                 s[(sh - 1 - y) * src_stride + x * bpp + z];
540           }
541         }
542       }
543       break;
544     case GST_VIDEO_FLIP_METHOD_TRANS:
545       for (y = 0; y < dh; y++) {
546         for (x = 0; x < dw; x++) {
547           for (z = 0; z < bpp; z++) {
548             d[y * dest_stride + x * bpp + z] = s[x * src_stride + y * bpp + z];
549           }
550         }
551       }
552       break;
553     case GST_VIDEO_FLIP_METHOD_OTHER:
554       for (y = 0; y < dh; y++) {
555         for (x = 0; x < dw; x++) {
556           for (z = 0; z < bpp; z++) {
557             d[y * dest_stride + x * bpp + z] =
558                 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + z];
559           }
560         }
561       }
562       break;
563     case GST_VIDEO_FLIP_METHOD_IDENTITY:
564       g_assert_not_reached ();
565       break;
566     default:
567       g_assert_not_reached ();
568       break;
569   }
570 }
571
572
573 static void
574 gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest,
575     const guint8 * src)
576 {
577   gint x, y;
578   guint8 const *s = src;
579   guint8 *d = dest;
580   GstVideoFormat format = videoflip->format;
581   gint sw = videoflip->from_width;
582   gint sh = videoflip->from_height;
583   gint dw = videoflip->to_width;
584   gint dh = videoflip->to_height;
585   gint src_stride, dest_stride;
586   gint bpp;
587   gint y_offset;
588   gint u_offset;
589   gint v_offset;
590   gint y_stride;
591
592   src_stride = gst_video_format_get_row_stride (format, 0, sw);
593   dest_stride = gst_video_format_get_row_stride (format, 0, dw);
594
595   y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
596   u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
597   v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);
598   y_stride = gst_video_format_get_pixel_stride (format, 0);
599   bpp = y_stride;
600
601   switch (videoflip->method) {
602     case GST_VIDEO_FLIP_METHOD_90R:
603       for (y = 0; y < dh; y++) {
604         for (x = 0; x < dw; x += 2) {
605           guint8 u;
606           guint8 v;
607           /* u/v must be calculated using the offset of the even column */
608           gint even_y = (y & ~1);
609
610           u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
611           if (x + 1 < dw)
612             u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
613                 + u) >> 1;
614           v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
615           if (x + 1 < dw)
616             v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
617                 + v) >> 1;
618
619           d[y * dest_stride + x * bpp + u_offset] = u;
620           d[y * dest_stride + x * bpp + v_offset] = v;
621           d[y * dest_stride + x * bpp + y_offset] =
622               s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
623           if (x + 1 < dw)
624             d[y * dest_stride + (x + 1) * bpp + y_offset] =
625                 s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
626         }
627       }
628       break;
629     case GST_VIDEO_FLIP_METHOD_90L:
630       for (y = 0; y < dh; y++) {
631         for (x = 0; x < dw; x += 2) {
632           guint8 u;
633           guint8 v;
634           /* u/v must be calculated using the offset of the even column */
635           gint even_y = ((sw - 1 - y) & ~1);
636
637           u = s[x * src_stride + even_y * bpp + u_offset];
638           if (x + 1 < dw)
639             u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
640           v = s[x * src_stride + even_y * bpp + v_offset];
641           if (x + 1 < dw)
642             v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
643
644           d[y * dest_stride + x * bpp + u_offset] = u;
645           d[y * dest_stride + x * bpp + v_offset] = v;
646           d[y * dest_stride + x * bpp + y_offset] =
647               s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
648           if (x + 1 < dw)
649             d[y * dest_stride + (x + 1) * bpp + y_offset] =
650                 s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
651         }
652       }
653       break;
654     case GST_VIDEO_FLIP_METHOD_180:
655       for (y = 0; y < dh; y++) {
656         for (x = 0; x < dw; x += 2) {
657           guint8 u;
658           guint8 v;
659           /* u/v must be calculated using the offset of the even column */
660           gint even_x = ((sw - 1 - x) & ~1);
661
662           u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
663               s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
664           v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
665               s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
666
667           d[y * dest_stride + x * bpp + u_offset] = u;
668           d[y * dest_stride + x * bpp + v_offset] = v;
669           d[y * dest_stride + x * bpp + y_offset] =
670               s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
671           if (x + 1 < dw)
672             d[y * dest_stride + (x + 1) * bpp + y_offset] =
673                 s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
674                 y_offset];
675         }
676       }
677       break;
678     case GST_VIDEO_FLIP_METHOD_HORIZ:
679       for (y = 0; y < dh; y++) {
680         for (x = 0; x < dw; x += 2) {
681           guint8 u;
682           guint8 v;
683           /* u/v must be calculated using the offset of the even column */
684           gint even_x = ((sw - 1 - x) & ~1);
685
686           u = (s[y * src_stride + even_x * bpp + u_offset] +
687               s[y * src_stride + even_x * bpp + u_offset]) / 2;
688           v = (s[y * src_stride + even_x * bpp + v_offset] +
689               s[y * src_stride + even_x * bpp + v_offset]) / 2;
690
691           d[y * dest_stride + x * bpp + u_offset] = u;
692           d[y * dest_stride + x * bpp + v_offset] = v;
693           d[y * dest_stride + x * bpp + y_offset] =
694               s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
695           if (x + 1 < dw)
696             d[y * dest_stride + (x + 1) * bpp + y_offset] =
697                 s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
698         }
699       }
700       break;
701     case GST_VIDEO_FLIP_METHOD_VERT:
702       for (y = 0; y < dh; y++) {
703         for (x = 0; x < dw; x += 2) {
704           guint8 u;
705           guint8 v;
706           /* u/v must be calculated using the offset of the even column */
707           gint even_x = (x & ~1);
708
709           u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
710               s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
711           v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
712               s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
713
714           d[y * dest_stride + x * bpp + u_offset] = u;
715           d[y * dest_stride + x * bpp + v_offset] = v;
716           d[y * dest_stride + x * bpp + y_offset] =
717               s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
718           if (x + 1 < dw)
719             d[y * dest_stride + (x + 1) * bpp + y_offset] =
720                 s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
721         }
722       }
723       break;
724     case GST_VIDEO_FLIP_METHOD_TRANS:
725       for (y = 0; y < dh; y++) {
726         for (x = 0; x < dw; x += 2) {
727           guint8 u;
728           guint8 v;
729           /* u/v must be calculated using the offset of the even column */
730           gint even_y = (y & ~1);
731
732           u = s[x * src_stride + even_y * bpp + u_offset];
733           if (x + 1 < dw)
734             u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
735           v = s[x * src_stride + even_y * bpp + v_offset];
736           if (x + 1 < dw)
737             v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
738
739           d[y * dest_stride + x * bpp + u_offset] = u;
740           d[y * dest_stride + x * bpp + v_offset] = v;
741           d[y * dest_stride + x * bpp + y_offset] =
742               s[x * src_stride + y * bpp + y_offset];
743           if (x + 1 < dw)
744             d[y * dest_stride + (x + 1) * bpp + y_offset] =
745                 s[(x + 1) * src_stride + y * bpp + y_offset];
746         }
747       }
748       break;
749     case GST_VIDEO_FLIP_METHOD_OTHER:
750       for (y = 0; y < dh; y++) {
751         for (x = 0; x < dw; x += 2) {
752           guint8 u;
753           guint8 v;
754           /* u/v must be calculated using the offset of the even column */
755           gint even_y = ((sw - 1 - y) & ~1);
756
757           u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
758           if (x + 1 < dw)
759             u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
760                 + u) >> 1;
761           v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
762           if (x + 1 < dw)
763             v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
764                 + v) >> 1;
765
766           d[y * dest_stride + x * bpp + u_offset] = u;
767           d[y * dest_stride + x * bpp + v_offset] = v;
768           d[y * dest_stride + x * bpp + y_offset] =
769               s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
770           if (x + 1 < dw)
771             d[y * dest_stride + (x + 1) * bpp + y_offset] =
772                 s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
773                 y_offset];
774         }
775       }
776       break;
777     case GST_VIDEO_FLIP_METHOD_IDENTITY:
778       g_assert_not_reached ();
779       break;
780     default:
781       g_assert_not_reached ();
782       break;
783   }
784 }
785
786
787 static gboolean
788 gst_video_flip_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
789     GstCaps * outcaps)
790 {
791   GstVideoFlip *vf = GST_VIDEO_FLIP (btrans);
792   GstVideoFormat in_format, out_format;
793   gboolean ret = FALSE;
794
795   vf->process = NULL;
796
797   if (!gst_video_format_parse_caps (incaps, &in_format, &vf->from_width,
798           &vf->from_height)
799       || !gst_video_format_parse_caps (outcaps, &out_format, &vf->to_width,
800           &vf->to_height))
801     goto invalid_caps;
802
803   if (in_format != out_format)
804     goto invalid_caps;
805   vf->format = in_format;
806
807   /* Check that they are correct */
808   switch (vf->method) {
809     case GST_VIDEO_FLIP_METHOD_90R:
810     case GST_VIDEO_FLIP_METHOD_90L:
811     case GST_VIDEO_FLIP_METHOD_TRANS:
812     case GST_VIDEO_FLIP_METHOD_OTHER:
813       if ((vf->from_width != vf->to_height) ||
814           (vf->from_height != vf->to_width)) {
815         GST_ERROR_OBJECT (vf, "we are inverting width and height but caps "
816             "are not correct : %dx%d to %dx%d", vf->from_width,
817             vf->from_height, vf->to_width, vf->to_height);
818         goto beach;
819       }
820       break;
821     case GST_VIDEO_FLIP_METHOD_IDENTITY:
822
823       break;
824     case GST_VIDEO_FLIP_METHOD_180:
825     case GST_VIDEO_FLIP_METHOD_HORIZ:
826     case GST_VIDEO_FLIP_METHOD_VERT:
827       if ((vf->from_width != vf->to_width) ||
828           (vf->from_height != vf->to_height)) {
829         GST_ERROR_OBJECT (vf, "we are keeping width and height but caps "
830             "are not correct : %dx%d to %dx%d", vf->from_width,
831             vf->from_height, vf->to_width, vf->to_height);
832         goto beach;
833       }
834       break;
835     default:
836       g_assert_not_reached ();
837       break;
838   }
839
840   ret = TRUE;
841
842   switch (vf->format) {
843     case GST_VIDEO_FORMAT_I420:
844     case GST_VIDEO_FORMAT_YV12:
845     case GST_VIDEO_FORMAT_Y444:
846       vf->process = gst_video_flip_planar_yuv;
847       break;
848     case GST_VIDEO_FORMAT_YUY2:
849     case GST_VIDEO_FORMAT_UYVY:
850     case GST_VIDEO_FORMAT_YVYU:
851       vf->process = gst_video_flip_y422;
852       break;
853     case GST_VIDEO_FORMAT_AYUV:
854     case GST_VIDEO_FORMAT_ARGB:
855     case GST_VIDEO_FORMAT_ABGR:
856     case GST_VIDEO_FORMAT_RGBA:
857     case GST_VIDEO_FORMAT_BGRA:
858     case GST_VIDEO_FORMAT_xRGB:
859     case GST_VIDEO_FORMAT_xBGR:
860     case GST_VIDEO_FORMAT_RGBx:
861     case GST_VIDEO_FORMAT_BGRx:
862     case GST_VIDEO_FORMAT_RGB:
863     case GST_VIDEO_FORMAT_BGR:
864       vf->process = gst_video_flip_packed_simple;
865       break;
866     default:
867       break;
868   }
869
870 beach:
871   return ret && (vf->process != NULL);
872
873 invalid_caps:
874   GST_ERROR_OBJECT (vf, "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT,
875       incaps, outcaps);
876   return FALSE;
877 }
878
879 static void
880 gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
881 {
882   GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
883   GstClockTime timestamp, stream_time;
884
885   timestamp = GST_BUFFER_TIMESTAMP (in);
886   stream_time =
887       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
888
889   GST_DEBUG_OBJECT (videoflip, "sync to %" GST_TIME_FORMAT,
890       GST_TIME_ARGS (timestamp));
891
892   if (GST_CLOCK_TIME_IS_VALID (stream_time))
893     gst_object_sync_values (G_OBJECT (videoflip), stream_time);
894 }
895
896 static GstFlowReturn
897 gst_video_flip_transform (GstBaseTransform * trans, GstBuffer * in,
898     GstBuffer * out)
899 {
900   GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
901   guint8 *dest;
902   const guint8 *src;
903
904   if (G_UNLIKELY (videoflip->process == NULL))
905     goto not_negotiated;
906
907   src = GST_BUFFER_DATA (in);
908   dest = GST_BUFFER_DATA (out);
909
910   GST_LOG_OBJECT (videoflip, "videoflip: flipping %dx%d to %dx%d (%s)",
911       videoflip->from_width, videoflip->from_height, videoflip->to_width,
912       videoflip->to_height, video_flip_methods[videoflip->method].value_nick);
913
914   GST_OBJECT_LOCK (videoflip);
915   videoflip->process (videoflip, dest, src);
916   GST_OBJECT_UNLOCK (videoflip);
917
918   return GST_FLOW_OK;
919
920 not_negotiated:
921   GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
922   return GST_FLOW_NOT_NEGOTIATED;
923 }
924
925 static gboolean
926 gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
927 {
928   GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
929   gdouble new_x, new_y, x, y;
930   GstStructure *structure;
931   gboolean ret;
932
933   GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
934
935   switch (GST_EVENT_TYPE (event)) {
936     case GST_EVENT_NAVIGATION:
937       event =
938           GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
939
940       structure = (GstStructure *) gst_event_get_structure (event);
941       if (gst_structure_get_double (structure, "pointer_x", &x) &&
942           gst_structure_get_double (structure, "pointer_y", &y)) {
943         GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
944         switch (vf->method) {
945           case GST_VIDEO_FLIP_METHOD_90R:
946             new_x = y;
947             new_y = vf->to_width - x;
948             break;
949           case GST_VIDEO_FLIP_METHOD_90L:
950             new_x = vf->to_height - y;
951             new_y = x;
952             break;
953           case GST_VIDEO_FLIP_METHOD_OTHER:
954             new_x = vf->to_height - y;
955             new_y = vf->to_width - x;
956             break;
957           case GST_VIDEO_FLIP_METHOD_TRANS:
958             new_x = y;
959             new_y = x;
960             break;
961           case GST_VIDEO_FLIP_METHOD_180:
962             new_x = vf->to_width - x;
963             new_y = vf->to_height - y;
964             break;
965           case GST_VIDEO_FLIP_METHOD_HORIZ:
966             new_x = vf->to_width - x;
967             new_y = y;
968             break;
969           case GST_VIDEO_FLIP_METHOD_VERT:
970             new_x = x;
971             new_y = vf->to_height - y;
972             break;
973           default:
974             new_x = x;
975             new_y = y;
976             break;
977         }
978         GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
979         gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
980             "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
981       }
982       break;
983     default:
984       break;
985   }
986
987   ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
988
989   return ret;
990 }
991
992 static void
993 gst_video_flip_set_property (GObject * object, guint prop_id,
994     const GValue * value, GParamSpec * pspec)
995 {
996   GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
997
998   switch (prop_id) {
999     case PROP_METHOD:
1000     {
1001       GstVideoFlipMethod method;
1002
1003       method = g_value_get_enum (value);
1004       GST_OBJECT_LOCK (videoflip);
1005       if (method != videoflip->method) {
1006         GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
1007
1008         GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
1009             video_flip_methods[videoflip->method].value_nick,
1010             video_flip_methods[method].value_nick);
1011
1012         videoflip->method = method;
1013         GST_OBJECT_UNLOCK (videoflip);
1014
1015         gst_base_transform_set_passthrough (btrans,
1016             method == GST_VIDEO_FLIP_METHOD_IDENTITY);
1017         gst_base_transform_reconfigure (btrans);
1018       } else {
1019         GST_OBJECT_UNLOCK (videoflip);
1020       }
1021     }
1022       break;
1023     default:
1024       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1025       break;
1026   }
1027 }
1028
1029 static void
1030 gst_video_flip_get_property (GObject * object, guint prop_id, GValue * value,
1031     GParamSpec * pspec)
1032 {
1033   GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
1034
1035   switch (prop_id) {
1036     case PROP_METHOD:
1037       g_value_set_enum (value, videoflip->method);
1038       break;
1039     default:
1040       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1041       break;
1042   }
1043 }
1044
1045 static void
1046 gst_video_flip_base_init (gpointer g_class)
1047 {
1048   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1049
1050   gst_element_class_set_details_simple (element_class, "Video flipper",
1051       "Filter/Effect/Video",
1052       "Flips and rotates video", "David Schleef <ds@schleef.org>");
1053
1054   gst_element_class_add_static_pad_template (element_class,
1055       &gst_video_flip_sink_template);
1056   gst_element_class_add_static_pad_template (element_class,
1057       &gst_video_flip_src_template);
1058 }
1059
1060 static void
1061 gst_video_flip_class_init (GstVideoFlipClass * klass)
1062 {
1063   GObjectClass *gobject_class = (GObjectClass *) klass;
1064   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
1065
1066   GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
1067
1068   gobject_class->set_property = gst_video_flip_set_property;
1069   gobject_class->get_property = gst_video_flip_get_property;
1070
1071   g_object_class_install_property (gobject_class, PROP_METHOD,
1072       g_param_spec_enum ("method", "method", "method",
1073           GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
1074           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1075
1076   trans_class->transform_caps =
1077       GST_DEBUG_FUNCPTR (gst_video_flip_transform_caps);
1078   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_flip_set_caps);
1079   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_flip_get_unit_size);
1080   trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_flip_transform);
1081   trans_class->before_transform =
1082       GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
1083   trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
1084 }
1085
1086 static void
1087 gst_video_flip_init (GstVideoFlip * videoflip, GstVideoFlipClass * klass)
1088 {
1089   videoflip->method = PROP_METHOD_DEFAULT;
1090   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip), TRUE);
1091 }