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