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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, 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-1.0 videotestsrc ! videoflip method=clockwise ! videoconvert ! ximagesink
36  * ]| This pipeline flips the test image 90 degrees clockwise.
37  * </refsect2>
38  */
39 
40 
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44 
45 #include "gstvideoflip.h"
46 
47 #include <string.h>
48 #include <gst/gst.h>
49 #include <gst/video/video.h>
50 
51 /* GstVideoFlip properties */
52 enum
53 {
54   PROP_0,
55   PROP_METHOD,
56   PROP_VIDEO_DIRECTION
57       /* FILL ME */
58 };
59 
60 #define PROP_METHOD_DEFAULT GST_VIDEO_FLIP_METHOD_IDENTITY
61 
62 GST_DEBUG_CATEGORY_STATIC (video_flip_debug);
63 #define GST_CAT_DEFAULT video_flip_debug
64 
65 static GstStaticPadTemplate gst_video_flip_src_template =
66 GST_STATIC_PAD_TEMPLATE ("src",
67     GST_PAD_SRC,
68     GST_PAD_ALWAYS,
69     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
70             "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, "
71             "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, "
72             "GRAY8, GRAY16_BE, GRAY16_LE }"))
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, NV12, NV21, "
82             "GRAY8, GRAY16_BE, GRAY16_LE }"))
83     );
84 
85 #define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
86 
87 static const GEnumValue video_flip_methods[] = {
88   {GST_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
89   {GST_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
90   {GST_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
91   {GST_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
92       "counterclockwise"},
93   {GST_VIDEO_FLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
94   {GST_VIDEO_FLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
95   {GST_VIDEO_FLIP_METHOD_TRANS,
96       "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
97   {GST_VIDEO_FLIP_METHOD_OTHER,
98       "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
99   {GST_VIDEO_FLIP_METHOD_AUTO,
100       "Select flip method based on image-orientation tag", "automatic"},
101   {0, NULL, NULL},
102 };
103 
104 static GType
gst_video_flip_method_get_type(void)105 gst_video_flip_method_get_type (void)
106 {
107   static GType video_flip_method_type = 0;
108 
109   if (!video_flip_method_type) {
110     video_flip_method_type = g_enum_register_static ("GstVideoFlipMethod",
111         video_flip_methods);
112   }
113   return video_flip_method_type;
114 }
115 
116 static void
gst_video_flip_video_direction_interface_init(GstVideoDirectionInterface * iface)117 gst_video_flip_video_direction_interface_init (GstVideoDirectionInterface *
118     iface)
119 {
120   /* We implement the video-direction property */
121 }
122 
123 #define gst_video_flip_parent_class parent_class
124 G_DEFINE_TYPE_WITH_CODE (GstVideoFlip, gst_video_flip, GST_TYPE_VIDEO_FILTER,
125     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_DIRECTION,
126         gst_video_flip_video_direction_interface_init));
127 
128 static GstCaps *
gst_video_flip_transform_caps(GstBaseTransform * trans,GstPadDirection direction,GstCaps * caps,GstCaps * filter)129 gst_video_flip_transform_caps (GstBaseTransform * trans,
130     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
131 {
132   GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
133   GstCaps *ret;
134   gint width, height, i;
135 
136   ret = gst_caps_copy (caps);
137 
138   for (i = 0; i < gst_caps_get_size (ret); i++) {
139     GstStructure *structure = gst_caps_get_structure (ret, i);
140     gint par_n, par_d;
141 
142     if (gst_structure_get_int (structure, "width", &width) &&
143         gst_structure_get_int (structure, "height", &height)) {
144 
145       switch (videoflip->active_method) {
146         case GST_VIDEO_ORIENTATION_90R:
147         case GST_VIDEO_ORIENTATION_90L:
148         case GST_VIDEO_ORIENTATION_UL_LR:
149         case GST_VIDEO_ORIENTATION_UR_LL:
150           gst_structure_set (structure, "width", G_TYPE_INT, height,
151               "height", G_TYPE_INT, width, NULL);
152           if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
153                   &par_n, &par_d)) {
154             if (par_n != 1 || par_d != 1) {
155               GValue val = { 0, };
156 
157               g_value_init (&val, GST_TYPE_FRACTION);
158               gst_value_set_fraction (&val, par_d, par_n);
159               gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
160               g_value_unset (&val);
161             }
162           }
163           break;
164         case GST_VIDEO_ORIENTATION_IDENTITY:
165         case GST_VIDEO_ORIENTATION_180:
166         case GST_VIDEO_ORIENTATION_HORIZ:
167         case GST_VIDEO_ORIENTATION_VERT:
168           gst_structure_set (structure, "width", G_TYPE_INT, width,
169               "height", G_TYPE_INT, height, NULL);
170           break;
171         case GST_VIDEO_ORIENTATION_CUSTOM:
172           GST_WARNING_OBJECT (videoflip, "unsuported custom orientation");
173           break;
174         default:
175           g_assert_not_reached ();
176           break;
177       }
178     }
179   }
180 
181   GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
182       GST_PTR_FORMAT, caps, ret);
183 
184   if (filter) {
185     GstCaps *intersection;
186 
187     GST_DEBUG_OBJECT (videoflip, "Using filter caps %" GST_PTR_FORMAT, filter);
188     intersection =
189         gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
190     gst_caps_unref (ret);
191     ret = intersection;
192     GST_DEBUG_OBJECT (videoflip, "Intersection %" GST_PTR_FORMAT, ret);
193   }
194 
195   return ret;
196 }
197 
198 static void
gst_video_flip_planar_yuv(GstVideoFlip * videoflip,GstVideoFrame * dest,const GstVideoFrame * src)199 gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
200     const GstVideoFrame * src)
201 {
202   gint x, y;
203   guint8 const *s;
204   guint8 *d;
205   gint src_y_stride, src_u_stride, src_v_stride;
206   gint src_y_height, src_u_height, src_v_height;
207   gint src_y_width, src_u_width, src_v_width;
208   gint dest_y_stride, dest_u_stride, dest_v_stride;
209   gint dest_y_height, dest_u_height, dest_v_height;
210   gint dest_y_width, dest_u_width, dest_v_width;
211 
212   src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
213   src_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1);
214   src_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 2);
215 
216   dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
217   dest_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1);
218   dest_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 2);
219 
220   src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
221   src_u_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
222   src_v_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 2);
223 
224   dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
225   dest_u_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
226   dest_v_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 2);
227 
228   src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
229   src_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
230   src_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 2);
231 
232   dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
233   dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
234   dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
235 
236   switch (videoflip->active_method) {
237     case GST_VIDEO_ORIENTATION_90R:
238       /* Flip Y */
239       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
240       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
241       for (y = 0; y < dest_y_height; y++) {
242         for (x = 0; x < dest_y_width; x++) {
243           d[y * dest_y_stride + x] =
244               s[(src_y_height - 1 - x) * src_y_stride + y];
245         }
246       }
247       /* Flip U */
248       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
249       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
250       for (y = 0; y < dest_u_height; y++) {
251         for (x = 0; x < dest_u_width; x++) {
252           d[y * dest_u_stride + x] =
253               s[(src_u_height - 1 - x) * src_u_stride + y];
254         }
255       }
256       /* Flip V */
257       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
258       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
259       for (y = 0; y < dest_v_height; y++) {
260         for (x = 0; x < dest_v_width; x++) {
261           d[y * dest_v_stride + x] =
262               s[(src_v_height - 1 - x) * src_v_stride + y];
263         }
264       }
265       break;
266     case GST_VIDEO_ORIENTATION_90L:
267       /* Flip Y */
268       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
269       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
270       for (y = 0; y < dest_y_height; y++) {
271         for (x = 0; x < dest_y_width; x++) {
272           d[y * dest_y_stride + x] =
273               s[x * src_y_stride + (src_y_width - 1 - y)];
274         }
275       }
276       /* Flip U */
277       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
278       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
279       for (y = 0; y < dest_u_height; y++) {
280         for (x = 0; x < dest_u_width; x++) {
281           d[y * dest_u_stride + x] =
282               s[x * src_u_stride + (src_u_width - 1 - y)];
283         }
284       }
285       /* Flip V */
286       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
287       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
288       for (y = 0; y < dest_v_height; y++) {
289         for (x = 0; x < dest_v_width; x++) {
290           d[y * dest_v_stride + x] =
291               s[x * src_v_stride + (src_v_width - 1 - y)];
292         }
293       }
294       break;
295     case GST_VIDEO_ORIENTATION_180:
296       /* Flip Y */
297       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
298       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
299       for (y = 0; y < dest_y_height; y++) {
300         for (x = 0; x < dest_y_width; x++) {
301           d[y * dest_y_stride + x] =
302               s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
303         }
304       }
305       /* Flip U */
306       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
307       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
308       for (y = 0; y < dest_u_height; y++) {
309         for (x = 0; x < dest_u_width; x++) {
310           d[y * dest_u_stride + x] =
311               s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
312         }
313       }
314       /* Flip V */
315       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
316       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
317       for (y = 0; y < dest_v_height; y++) {
318         for (x = 0; x < dest_v_width; x++) {
319           d[y * dest_v_stride + x] =
320               s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
321         }
322       }
323       break;
324     case GST_VIDEO_ORIENTATION_HORIZ:
325       /* Flip Y */
326       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
327       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
328       for (y = 0; y < dest_y_height; y++) {
329         for (x = 0; x < dest_y_width; x++) {
330           d[y * dest_y_stride + x] =
331               s[y * src_y_stride + (src_y_width - 1 - x)];
332         }
333       }
334       /* Flip U */
335       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
336       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
337       for (y = 0; y < dest_u_height; y++) {
338         for (x = 0; x < dest_u_width; x++) {
339           d[y * dest_u_stride + x] =
340               s[y * src_u_stride + (src_u_width - 1 - x)];
341         }
342       }
343       /* Flip V */
344       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
345       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
346       for (y = 0; y < dest_v_height; y++) {
347         for (x = 0; x < dest_v_width; x++) {
348           d[y * dest_v_stride + x] =
349               s[y * src_v_stride + (src_v_width - 1 - x)];
350         }
351       }
352       break;
353     case GST_VIDEO_ORIENTATION_VERT:
354       /* Flip Y */
355       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
356       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
357       for (y = 0; y < dest_y_height; y++) {
358         for (x = 0; x < dest_y_width; x++) {
359           d[y * dest_y_stride + x] =
360               s[(src_y_height - 1 - y) * src_y_stride + x];
361         }
362       }
363       /* Flip U */
364       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
365       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
366       for (y = 0; y < dest_u_height; y++) {
367         for (x = 0; x < dest_u_width; x++) {
368           d[y * dest_u_stride + x] =
369               s[(src_u_height - 1 - y) * src_u_stride + x];
370         }
371       }
372       /* Flip V */
373       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
374       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
375       for (y = 0; y < dest_v_height; y++) {
376         for (x = 0; x < dest_v_width; x++) {
377           d[y * dest_v_stride + x] =
378               s[(src_v_height - 1 - y) * src_v_stride + x];
379         }
380       }
381       break;
382     case GST_VIDEO_ORIENTATION_UL_LR:
383       /* Flip Y */
384       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
385       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
386       for (y = 0; y < dest_y_height; y++) {
387         for (x = 0; x < dest_y_width; x++) {
388           d[y * dest_y_stride + x] = s[x * src_y_stride + y];
389         }
390       }
391       /* Flip U */
392       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
393       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
394       for (y = 0; y < dest_u_height; y++) {
395         for (x = 0; x < dest_u_width; x++) {
396           d[y * dest_u_stride + x] = s[x * src_u_stride + y];
397         }
398       }
399       /* Flip V */
400       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
401       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
402       for (y = 0; y < dest_u_height; y++) {
403         for (x = 0; x < dest_u_width; x++) {
404           d[y * dest_v_stride + x] = s[x * src_v_stride + y];
405         }
406       }
407       break;
408     case GST_VIDEO_ORIENTATION_UR_LL:
409       /* Flip Y */
410       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
411       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
412       for (y = 0; y < dest_y_height; y++) {
413         for (x = 0; x < dest_y_width; x++) {
414           d[y * dest_y_stride + x] =
415               s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
416         }
417       }
418       /* Flip U */
419       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
420       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
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] =
424               s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
425         }
426       }
427       /* Flip V */
428       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
429       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
430       for (y = 0; y < dest_v_height; y++) {
431         for (x = 0; x < dest_v_width; x++) {
432           d[y * dest_v_stride + x] =
433               s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
434         }
435       }
436       break;
437     case GST_VIDEO_ORIENTATION_IDENTITY:
438       g_assert_not_reached ();
439       break;
440     default:
441       g_assert_not_reached ();
442       break;
443   }
444 }
445 
446 static void
gst_video_flip_semi_planar_yuv(GstVideoFlip * videoflip,GstVideoFrame * dest,const GstVideoFrame * src)447 gst_video_flip_semi_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
448     const GstVideoFrame * src)
449 {
450   gint x, y;
451   guint8 const *s;
452   guint8 *d;
453   gint s_off, d_off;
454   gint src_y_stride, src_uv_stride;
455   gint src_y_height, src_uv_height;
456   gint src_y_width, src_uv_width;
457   gint dest_y_stride, dest_uv_stride;
458   gint dest_y_height, dest_uv_height;
459   gint dest_y_width, dest_uv_width;
460 
461 
462   src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
463   src_uv_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1);
464 
465   dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
466   dest_uv_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1);
467 
468   src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
469   src_uv_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
470 
471   dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
472   dest_uv_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
473 
474   src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
475   src_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
476 
477   dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
478   dest_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
479 
480   switch (videoflip->active_method) {
481     case GST_VIDEO_ORIENTATION_90R:
482       /* Flip Y */
483       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
484       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
485       for (y = 0; y < dest_y_height; y++) {
486         for (x = 0; x < dest_y_width; x++) {
487           d[y * dest_y_stride + x] =
488               s[(src_y_height - 1 - x) * src_y_stride + y];
489         }
490       }
491       /* Flip UV */
492       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
493       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
494       for (y = 0; y < dest_uv_height; y++) {
495         for (x = 0; x < dest_uv_width; x++) {
496           d_off = y * dest_uv_stride + x * 2;
497           s_off = (src_uv_height - 1 - x) * src_uv_stride + y * 2;
498           d[d_off] = s[s_off];
499           d[d_off + 1] = s[s_off + 1];
500         }
501       }
502       break;
503     case GST_VIDEO_ORIENTATION_90L:
504       /* Flip Y */
505       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
506       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
507       for (y = 0; y < dest_y_height; y++) {
508         for (x = 0; x < dest_y_width; x++) {
509           d[y * dest_y_stride + x] =
510               s[x * src_y_stride + (src_y_width - 1 - y)];
511         }
512       }
513       /* Flip UV */
514       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
515       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
516       for (y = 0; y < dest_uv_height; y++) {
517         for (x = 0; x < dest_uv_width; x++) {
518           d_off = y * dest_uv_stride + x * 2;
519           s_off = x * src_uv_stride + (src_uv_width - 1 - y) * 2;
520           d[d_off] = s[s_off];
521           d[d_off + 1] = s[s_off + 1];
522         }
523       }
524       break;
525     case GST_VIDEO_ORIENTATION_180:
526       /* Flip Y */
527       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
528       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
529       for (y = 0; y < dest_y_height; y++) {
530         for (x = 0; x < dest_y_width; x++) {
531           d[y * dest_y_stride + x] =
532               s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
533         }
534       }
535       /* Flip UV */
536       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
537       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
538       for (y = 0; y < dest_uv_height; y++) {
539         for (x = 0; x < dest_uv_width; x++) {
540           d_off = y * dest_uv_stride + x * 2;
541           s_off = (src_uv_height - 1 - y) * src_uv_stride + (src_uv_width - 1 -
542               x) * 2;
543           d[d_off] = s[s_off];
544           d[d_off + 1] = s[s_off + 1];
545         }
546       }
547       break;
548     case GST_VIDEO_ORIENTATION_HORIZ:
549       /* Flip Y */
550       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
551       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
552       for (y = 0; y < dest_y_height; y++) {
553         for (x = 0; x < dest_y_width; x++) {
554           d[y * dest_y_stride + x] =
555               s[y * src_y_stride + (src_y_width - 1 - x)];
556         }
557       }
558       /* Flip UV */
559       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
560       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
561       for (y = 0; y < dest_uv_height; y++) {
562         for (x = 0; x < dest_uv_width; x++) {
563           d_off = y * dest_uv_stride + x * 2;
564           s_off = y * src_uv_stride + (src_uv_width - 1 - x) * 2;
565           d[d_off] = s[s_off];
566           d[d_off + 1] = s[s_off + 1];
567         }
568       }
569       break;
570     case GST_VIDEO_ORIENTATION_VERT:
571       /* Flip Y */
572       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
573       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
574       for (y = 0; y < dest_y_height; y++) {
575         for (x = 0; x < dest_y_width; x++) {
576           d[y * dest_y_stride + x] =
577               s[(src_y_height - 1 - y) * src_y_stride + x];
578         }
579       }
580       /* Flip UV */
581       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
582       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
583       for (y = 0; y < dest_uv_height; y++) {
584         for (x = 0; x < dest_uv_width; x++) {
585           d_off = y * dest_uv_stride + x * 2;
586           s_off = (src_uv_height - 1 - y) * src_uv_stride + x * 2;
587           d[d_off] = s[s_off];
588           d[d_off + 1] = s[s_off + 1];
589         }
590       }
591       break;
592     case GST_VIDEO_ORIENTATION_UL_LR:
593       /* Flip Y */
594       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
595       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
596       for (y = 0; y < dest_y_height; y++) {
597         for (x = 0; x < dest_y_width; x++) {
598           d[y * dest_y_stride + x] = s[x * src_y_stride + y];
599         }
600       }
601       /* Flip UV */
602       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
603       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
604       for (y = 0; y < dest_uv_height; y++) {
605         for (x = 0; x < dest_uv_width; x++) {
606           d_off = y * dest_uv_stride + x * 2;
607           s_off = x * src_uv_stride + y * 2;
608           d[d_off] = s[s_off];
609           d[d_off + 1] = s[s_off + 1];
610         }
611       }
612       break;
613     case GST_VIDEO_ORIENTATION_UR_LL:
614       /* Flip Y */
615       s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
616       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
617       for (y = 0; y < dest_y_height; y++) {
618         for (x = 0; x < dest_y_width; x++) {
619           d[y * dest_y_stride + x] =
620               s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
621         }
622       }
623       /* Flip UV */
624       s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
625       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
626       for (y = 0; y < dest_uv_height; y++) {
627         for (x = 0; x < dest_uv_width; x++) {
628           d_off = y * dest_uv_stride + x * 2;
629           s_off = (src_uv_height - 1 - x) * src_uv_stride + (src_uv_width - 1 -
630               y) * 2;
631           d[d_off] = s[s_off];
632           d[d_off + 1] = s[s_off + 1];
633         }
634       }
635       break;
636     case GST_VIDEO_ORIENTATION_IDENTITY:
637       g_assert_not_reached ();
638       break;
639     default:
640       g_assert_not_reached ();
641       break;
642   }
643 }
644 
645 static void
gst_video_flip_packed_simple(GstVideoFlip * videoflip,GstVideoFrame * dest,const GstVideoFrame * src)646 gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest,
647     const GstVideoFrame * src)
648 {
649   gint x, y, z;
650   guint8 const *s;
651   guint8 *d;
652   gint sw = GST_VIDEO_FRAME_WIDTH (src);
653   gint sh = GST_VIDEO_FRAME_HEIGHT (src);
654   gint dw = GST_VIDEO_FRAME_WIDTH (dest);
655   gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
656   gint src_stride, dest_stride;
657   gint bpp;
658 
659   s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
660   d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
661 
662   src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
663   dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
664   /* This is only true for non-subsampled formats! */
665   bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
666 
667   switch (videoflip->active_method) {
668     case GST_VIDEO_ORIENTATION_90R:
669       for (y = 0; y < dh; y++) {
670         for (x = 0; x < dw; x++) {
671           for (z = 0; z < bpp; z++) {
672             d[y * dest_stride + x * bpp + z] =
673                 s[(sh - 1 - x) * src_stride + y * bpp + z];
674           }
675         }
676       }
677       break;
678     case GST_VIDEO_ORIENTATION_90L:
679       for (y = 0; y < dh; y++) {
680         for (x = 0; x < dw; x++) {
681           for (z = 0; z < bpp; z++) {
682             d[y * dest_stride + x * bpp + z] =
683                 s[x * src_stride + (sw - 1 - y) * bpp + z];
684           }
685         }
686       }
687       break;
688     case GST_VIDEO_ORIENTATION_180:
689       for (y = 0; y < dh; y++) {
690         for (x = 0; x < dw; x++) {
691           for (z = 0; z < bpp; z++) {
692             d[y * dest_stride + x * bpp + z] =
693                 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + z];
694           }
695         }
696       }
697       break;
698     case GST_VIDEO_ORIENTATION_HORIZ:
699       for (y = 0; y < dh; y++) {
700         for (x = 0; x < dw; x++) {
701           for (z = 0; z < bpp; z++) {
702             d[y * dest_stride + x * bpp + z] =
703                 s[y * src_stride + (sw - 1 - x) * bpp + z];
704           }
705         }
706       }
707       break;
708     case GST_VIDEO_ORIENTATION_VERT:
709       for (y = 0; y < dh; y++) {
710         for (x = 0; x < dw; x++) {
711           for (z = 0; z < bpp; z++) {
712             d[y * dest_stride + x * bpp + z] =
713                 s[(sh - 1 - y) * src_stride + x * bpp + z];
714           }
715         }
716       }
717       break;
718     case GST_VIDEO_ORIENTATION_UL_LR:
719       for (y = 0; y < dh; y++) {
720         for (x = 0; x < dw; x++) {
721           for (z = 0; z < bpp; z++) {
722             d[y * dest_stride + x * bpp + z] = s[x * src_stride + y * bpp + z];
723           }
724         }
725       }
726       break;
727     case GST_VIDEO_ORIENTATION_UR_LL:
728       for (y = 0; y < dh; y++) {
729         for (x = 0; x < dw; x++) {
730           for (z = 0; z < bpp; z++) {
731             d[y * dest_stride + x * bpp + z] =
732                 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + z];
733           }
734         }
735       }
736       break;
737     case GST_VIDEO_ORIENTATION_IDENTITY:
738       g_assert_not_reached ();
739       break;
740     default:
741       g_assert_not_reached ();
742       break;
743   }
744 }
745 
746 
747 static void
gst_video_flip_y422(GstVideoFlip * videoflip,GstVideoFrame * dest,const GstVideoFrame * src)748 gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest,
749     const GstVideoFrame * src)
750 {
751   gint x, y;
752   guint8 const *s;
753   guint8 *d;
754   gint sw = GST_VIDEO_FRAME_WIDTH (src);
755   gint sh = GST_VIDEO_FRAME_HEIGHT (src);
756   gint dw = GST_VIDEO_FRAME_WIDTH (dest);
757   gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
758   gint src_stride, dest_stride;
759   gint bpp;
760   gint y_offset;
761   gint u_offset;
762   gint v_offset;
763   gint y_stride;
764 
765   s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
766   d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
767 
768   src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
769   dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
770 
771   y_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 0);
772   u_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 1);
773   v_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 2);
774   y_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
775   bpp = y_stride;
776 
777   switch (videoflip->active_method) {
778     case GST_VIDEO_ORIENTATION_90R:
779       for (y = 0; y < dh; y++) {
780         for (x = 0; x < dw; x += 2) {
781           guint8 u;
782           guint8 v;
783           /* u/v must be calculated using the offset of the even column */
784           gint even_y = (y & ~1);
785 
786           u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
787           if (x + 1 < dw)
788             u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
789                 + u) >> 1;
790           v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
791           if (x + 1 < dw)
792             v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
793                 + v) >> 1;
794 
795           d[y * dest_stride + x * bpp + u_offset] = u;
796           d[y * dest_stride + x * bpp + v_offset] = v;
797           d[y * dest_stride + x * bpp + y_offset] =
798               s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
799           if (x + 1 < dw)
800             d[y * dest_stride + (x + 1) * bpp + y_offset] =
801                 s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
802         }
803       }
804       break;
805     case GST_VIDEO_ORIENTATION_90L:
806       for (y = 0; y < dh; y++) {
807         for (x = 0; x < dw; x += 2) {
808           guint8 u;
809           guint8 v;
810           /* u/v must be calculated using the offset of the even column */
811           gint even_y = ((sw - 1 - y) & ~1);
812 
813           u = s[x * src_stride + even_y * bpp + u_offset];
814           if (x + 1 < dw)
815             u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
816           v = s[x * src_stride + even_y * bpp + v_offset];
817           if (x + 1 < dw)
818             v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
819 
820           d[y * dest_stride + x * bpp + u_offset] = u;
821           d[y * dest_stride + x * bpp + v_offset] = v;
822           d[y * dest_stride + x * bpp + y_offset] =
823               s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
824           if (x + 1 < dw)
825             d[y * dest_stride + (x + 1) * bpp + y_offset] =
826                 s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
827         }
828       }
829       break;
830     case GST_VIDEO_ORIENTATION_180:
831       for (y = 0; y < dh; y++) {
832         for (x = 0; x < dw; x += 2) {
833           guint8 u;
834           guint8 v;
835           /* u/v must be calculated using the offset of the even column */
836           gint even_x = ((sw - 1 - x) & ~1);
837 
838           u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
839               s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
840           v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
841               s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
842 
843           d[y * dest_stride + x * bpp + u_offset] = u;
844           d[y * dest_stride + x * bpp + v_offset] = v;
845           d[y * dest_stride + x * bpp + y_offset] =
846               s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
847           if (x + 1 < dw)
848             d[y * dest_stride + (x + 1) * bpp + y_offset] =
849                 s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
850                 y_offset];
851         }
852       }
853       break;
854     case GST_VIDEO_ORIENTATION_HORIZ:
855       for (y = 0; y < dh; y++) {
856         for (x = 0; x < dw; x += 2) {
857           guint8 u;
858           guint8 v;
859           /* u/v must be calculated using the offset of the even column */
860           gint even_x = ((sw - 1 - x) & ~1);
861 
862           u = (s[y * src_stride + even_x * bpp + u_offset] +
863               s[y * src_stride + even_x * bpp + u_offset]) / 2;
864           v = (s[y * src_stride + even_x * bpp + v_offset] +
865               s[y * src_stride + even_x * bpp + v_offset]) / 2;
866 
867           d[y * dest_stride + x * bpp + u_offset] = u;
868           d[y * dest_stride + x * bpp + v_offset] = v;
869           d[y * dest_stride + x * bpp + y_offset] =
870               s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
871           if (x + 1 < dw)
872             d[y * dest_stride + (x + 1) * bpp + y_offset] =
873                 s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
874         }
875       }
876       break;
877     case GST_VIDEO_ORIENTATION_VERT:
878       for (y = 0; y < dh; y++) {
879         for (x = 0; x < dw; x += 2) {
880           guint8 u;
881           guint8 v;
882           /* u/v must be calculated using the offset of the even column */
883           gint even_x = (x & ~1);
884 
885           u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
886               s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
887           v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
888               s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
889 
890           d[y * dest_stride + x * bpp + u_offset] = u;
891           d[y * dest_stride + x * bpp + v_offset] = v;
892           d[y * dest_stride + x * bpp + y_offset] =
893               s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
894           if (x + 1 < dw)
895             d[y * dest_stride + (x + 1) * bpp + y_offset] =
896                 s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
897         }
898       }
899       break;
900     case GST_VIDEO_ORIENTATION_UL_LR:
901       for (y = 0; y < dh; y++) {
902         for (x = 0; x < dw; x += 2) {
903           guint8 u;
904           guint8 v;
905           /* u/v must be calculated using the offset of the even column */
906           gint even_y = (y & ~1);
907 
908           u = s[x * src_stride + even_y * bpp + u_offset];
909           if (x + 1 < dw)
910             u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
911           v = s[x * src_stride + even_y * bpp + v_offset];
912           if (x + 1 < dw)
913             v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
914 
915           d[y * dest_stride + x * bpp + u_offset] = u;
916           d[y * dest_stride + x * bpp + v_offset] = v;
917           d[y * dest_stride + x * bpp + y_offset] =
918               s[x * src_stride + y * bpp + y_offset];
919           if (x + 1 < dw)
920             d[y * dest_stride + (x + 1) * bpp + y_offset] =
921                 s[(x + 1) * src_stride + y * bpp + y_offset];
922         }
923       }
924       break;
925     case GST_VIDEO_ORIENTATION_UR_LL:
926       for (y = 0; y < dh; y++) {
927         for (x = 0; x < dw; x += 2) {
928           guint8 u;
929           guint8 v;
930           /* u/v must be calculated using the offset of the even column */
931           gint even_y = ((sw - 1 - y) & ~1);
932 
933           u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
934           if (x + 1 < dw)
935             u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
936                 + u) >> 1;
937           v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
938           if (x + 1 < dw)
939             v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
940                 + v) >> 1;
941 
942           d[y * dest_stride + x * bpp + u_offset] = u;
943           d[y * dest_stride + x * bpp + v_offset] = v;
944           d[y * dest_stride + x * bpp + y_offset] =
945               s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
946           if (x + 1 < dw)
947             d[y * dest_stride + (x + 1) * bpp + y_offset] =
948                 s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
949                 y_offset];
950         }
951       }
952       break;
953     case GST_VIDEO_ORIENTATION_IDENTITY:
954       g_assert_not_reached ();
955       break;
956     default:
957       g_assert_not_reached ();
958       break;
959   }
960 }
961 
962 
963 static gboolean
gst_video_flip_set_info(GstVideoFilter * vfilter,GstCaps * incaps,GstVideoInfo * in_info,GstCaps * outcaps,GstVideoInfo * out_info)964 gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
965     GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
966 {
967   GstVideoFlip *vf = GST_VIDEO_FLIP (vfilter);
968   gboolean ret = FALSE;
969 
970   vf->process = NULL;
971 
972   if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_INFO_FORMAT (out_info))
973     goto invalid_caps;
974 
975   /* Check that they are correct */
976   switch (vf->active_method) {
977     case GST_VIDEO_ORIENTATION_90R:
978     case GST_VIDEO_ORIENTATION_90L:
979     case GST_VIDEO_ORIENTATION_UL_LR:
980     case GST_VIDEO_ORIENTATION_UR_LL:
981       if ((in_info->width != out_info->height) ||
982           (in_info->height != out_info->width)) {
983         GST_ERROR_OBJECT (vf, "we are inverting width and height but caps "
984             "are not correct : %dx%d to %dx%d", in_info->width,
985             in_info->height, out_info->width, out_info->height);
986         goto beach;
987       }
988       break;
989     case GST_VIDEO_ORIENTATION_IDENTITY:
990 
991       break;
992     case GST_VIDEO_ORIENTATION_180:
993     case GST_VIDEO_ORIENTATION_HORIZ:
994     case GST_VIDEO_ORIENTATION_VERT:
995       if ((in_info->width != out_info->width) ||
996           (in_info->height != out_info->height)) {
997         GST_ERROR_OBJECT (vf, "we are keeping width and height but caps "
998             "are not correct : %dx%d to %dx%d", in_info->width,
999             in_info->height, out_info->width, out_info->height);
1000         goto beach;
1001       }
1002       break;
1003     default:
1004       g_assert_not_reached ();
1005       break;
1006   }
1007 
1008   ret = TRUE;
1009 
1010   switch (GST_VIDEO_INFO_FORMAT (in_info)) {
1011     case GST_VIDEO_FORMAT_I420:
1012     case GST_VIDEO_FORMAT_YV12:
1013     case GST_VIDEO_FORMAT_Y444:
1014       vf->process = gst_video_flip_planar_yuv;
1015       break;
1016     case GST_VIDEO_FORMAT_YUY2:
1017     case GST_VIDEO_FORMAT_UYVY:
1018     case GST_VIDEO_FORMAT_YVYU:
1019       vf->process = gst_video_flip_y422;
1020       break;
1021     case GST_VIDEO_FORMAT_AYUV:
1022     case GST_VIDEO_FORMAT_ARGB:
1023     case GST_VIDEO_FORMAT_ABGR:
1024     case GST_VIDEO_FORMAT_RGBA:
1025     case GST_VIDEO_FORMAT_BGRA:
1026     case GST_VIDEO_FORMAT_xRGB:
1027     case GST_VIDEO_FORMAT_xBGR:
1028     case GST_VIDEO_FORMAT_RGBx:
1029     case GST_VIDEO_FORMAT_BGRx:
1030     case GST_VIDEO_FORMAT_RGB:
1031     case GST_VIDEO_FORMAT_BGR:
1032     case GST_VIDEO_FORMAT_GRAY8:
1033     case GST_VIDEO_FORMAT_GRAY16_BE:
1034     case GST_VIDEO_FORMAT_GRAY16_LE:
1035       vf->process = gst_video_flip_packed_simple;
1036       break;
1037     case GST_VIDEO_FORMAT_NV12:
1038     case GST_VIDEO_FORMAT_NV21:
1039       vf->process = gst_video_flip_semi_planar_yuv;
1040       break;
1041     default:
1042       break;
1043   }
1044 
1045 beach:
1046   return ret && (vf->process != NULL);
1047 
1048 invalid_caps:
1049   GST_ERROR_OBJECT (vf, "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT,
1050       incaps, outcaps);
1051   return FALSE;
1052 }
1053 
1054 static void
gst_video_flip_set_method(GstVideoFlip * videoflip,GstVideoOrientationMethod method,gboolean from_tag)1055 gst_video_flip_set_method (GstVideoFlip * videoflip,
1056     GstVideoOrientationMethod method, gboolean from_tag)
1057 {
1058   GST_OBJECT_LOCK (videoflip);
1059 
1060   if (method == GST_VIDEO_ORIENTATION_CUSTOM) {
1061     GST_WARNING_OBJECT (videoflip, "unsupported custom orientation");
1062     GST_OBJECT_UNLOCK (videoflip);
1063     return;
1064   }
1065 
1066   /* Store updated method */
1067   if (from_tag)
1068     videoflip->tag_method = method;
1069   else
1070     videoflip->method = method;
1071 
1072   /* Get the new method */
1073   if (videoflip->method == GST_VIDEO_ORIENTATION_AUTO)
1074     method = videoflip->tag_method;
1075   else
1076     method = videoflip->method;
1077 
1078   if (method != videoflip->active_method) {
1079     GEnumValue *active_method_enum, *method_enum;
1080     GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
1081     GEnumClass *enum_class =
1082         g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
1083 
1084     active_method_enum =
1085         g_enum_get_value (enum_class, videoflip->active_method);
1086     method_enum = g_enum_get_value (enum_class, method);
1087     GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
1088         active_method_enum ? active_method_enum->value_nick : "(nil)",
1089         method_enum ? method_enum->value_nick : "(nil)");
1090     g_type_class_unref (enum_class);
1091 
1092     videoflip->active_method = method;
1093 
1094     GST_OBJECT_UNLOCK (videoflip);
1095 
1096     gst_base_transform_set_passthrough (btrans,
1097         method == GST_VIDEO_ORIENTATION_IDENTITY);
1098     gst_base_transform_reconfigure_src (btrans);
1099   } else {
1100     GST_OBJECT_UNLOCK (videoflip);
1101   }
1102 }
1103 
1104 static void
gst_video_flip_before_transform(GstBaseTransform * trans,GstBuffer * in)1105 gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
1106 {
1107   GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
1108   GstClockTime timestamp, stream_time;
1109 
1110   timestamp = GST_BUFFER_TIMESTAMP (in);
1111   stream_time =
1112       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
1113 
1114   GST_DEBUG_OBJECT (videoflip, "sync to %" GST_TIME_FORMAT,
1115       GST_TIME_ARGS (timestamp));
1116 
1117   if (GST_CLOCK_TIME_IS_VALID (stream_time))
1118     gst_object_sync_values (GST_OBJECT (videoflip), stream_time);
1119 }
1120 
1121 static GstFlowReturn
gst_video_flip_transform_frame(GstVideoFilter * vfilter,GstVideoFrame * in_frame,GstVideoFrame * out_frame)1122 gst_video_flip_transform_frame (GstVideoFilter * vfilter,
1123     GstVideoFrame * in_frame, GstVideoFrame * out_frame)
1124 {
1125   GEnumClass *enum_class;
1126   GEnumValue *active_method_enum;
1127   GstVideoFlip *videoflip = GST_VIDEO_FLIP (vfilter);
1128 
1129   if (G_UNLIKELY (videoflip->process == NULL))
1130     goto not_negotiated;
1131 
1132   enum_class = g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
1133   active_method_enum = g_enum_get_value (enum_class, videoflip->active_method);
1134   GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
1135       active_method_enum ? active_method_enum->value_nick : "(nil)");
1136   g_type_class_unref (enum_class);
1137 
1138   GST_OBJECT_LOCK (videoflip);
1139   videoflip->process (videoflip, out_frame, in_frame);
1140   GST_OBJECT_UNLOCK (videoflip);
1141 
1142   return GST_FLOW_OK;
1143 
1144 not_negotiated:
1145   {
1146     GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
1147     return GST_FLOW_NOT_NEGOTIATED;
1148   }
1149 }
1150 
1151 static gboolean
gst_video_flip_src_event(GstBaseTransform * trans,GstEvent * event)1152 gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
1153 {
1154   GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
1155   gdouble new_x, new_y, x, y;
1156   GstStructure *structure;
1157   gboolean ret;
1158   GstVideoInfo *out_info = &GST_VIDEO_FILTER (trans)->out_info;
1159 
1160   GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
1161 
1162   switch (GST_EVENT_TYPE (event)) {
1163     case GST_EVENT_NAVIGATION:
1164       event =
1165           GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
1166 
1167       structure = (GstStructure *) gst_event_get_structure (event);
1168       if (gst_structure_get_double (structure, "pointer_x", &x) &&
1169           gst_structure_get_double (structure, "pointer_y", &y)) {
1170         GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
1171         switch (vf->active_method) {
1172           case GST_VIDEO_ORIENTATION_90R:
1173             new_x = y;
1174             new_y = out_info->width - x;
1175             break;
1176           case GST_VIDEO_ORIENTATION_90L:
1177             new_x = out_info->height - y;
1178             new_y = x;
1179             break;
1180           case GST_VIDEO_ORIENTATION_UR_LL:
1181             new_x = out_info->height - y;
1182             new_y = out_info->width - x;
1183             break;
1184           case GST_VIDEO_ORIENTATION_UL_LR:
1185             new_x = y;
1186             new_y = x;
1187             break;
1188           case GST_VIDEO_ORIENTATION_180:
1189             new_x = out_info->width - x;
1190             new_y = out_info->height - y;
1191             break;
1192           case GST_VIDEO_ORIENTATION_HORIZ:
1193             new_x = out_info->width - x;
1194             new_y = y;
1195             break;
1196           case GST_VIDEO_ORIENTATION_VERT:
1197             new_x = x;
1198             new_y = out_info->height - y;
1199             break;
1200           default:
1201             new_x = x;
1202             new_y = y;
1203             break;
1204         }
1205         GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
1206         gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
1207             "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
1208       }
1209       break;
1210     default:
1211       break;
1212   }
1213 
1214   ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
1215 
1216   return ret;
1217 }
1218 
1219 static gboolean
gst_video_flip_sink_event(GstBaseTransform * trans,GstEvent * event)1220 gst_video_flip_sink_event (GstBaseTransform * trans, GstEvent * event)
1221 {
1222   GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
1223   GstTagList *taglist;
1224   gchar *orientation;
1225   gboolean ret;
1226 
1227   GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
1228 
1229   switch (GST_EVENT_TYPE (event)) {
1230     case GST_EVENT_TAG:
1231       gst_event_parse_tag (event, &taglist);
1232 
1233       if (gst_tag_list_get_string (taglist, "image-orientation", &orientation)) {
1234         if (!g_strcmp0 ("rotate-0", orientation))
1235           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_IDENTITY, TRUE);
1236         else if (!g_strcmp0 ("rotate-90", orientation))
1237           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90R, TRUE);
1238         else if (!g_strcmp0 ("rotate-180", orientation))
1239           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_180, TRUE);
1240         else if (!g_strcmp0 ("rotate-270", orientation))
1241           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90L, TRUE);
1242         else if (!g_strcmp0 ("flip-rotate-0", orientation))
1243           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_HORIZ, TRUE);
1244         else if (!g_strcmp0 ("flip-rotate-90", orientation))
1245           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_UL_LR, TRUE);
1246         else if (!g_strcmp0 ("flip-rotate-180", orientation))
1247           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_VERT, TRUE);
1248         else if (!g_strcmp0 ("flip-rotate-270", orientation))
1249           gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_UR_LL, TRUE);
1250 
1251         g_free (orientation);
1252       }
1253       break;
1254     default:
1255       break;
1256   }
1257 
1258   ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
1259 
1260   return ret;
1261 }
1262 
1263 static void
gst_video_flip_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1264 gst_video_flip_set_property (GObject * object, guint prop_id,
1265     const GValue * value, GParamSpec * pspec)
1266 {
1267   GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
1268 
1269   switch (prop_id) {
1270     case PROP_METHOD:
1271     case PROP_VIDEO_DIRECTION:
1272       gst_video_flip_set_method (videoflip, g_value_get_enum (value), FALSE);
1273       break;
1274     default:
1275       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1276       break;
1277   }
1278 }
1279 
1280 static void
gst_video_flip_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1281 gst_video_flip_get_property (GObject * object, guint prop_id, GValue * value,
1282     GParamSpec * pspec)
1283 {
1284   GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
1285 
1286   switch (prop_id) {
1287     case PROP_METHOD:
1288     case PROP_VIDEO_DIRECTION:
1289       g_value_set_enum (value, videoflip->method);
1290       break;
1291     default:
1292       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1293       break;
1294   }
1295 }
1296 
1297 static void
gst_video_flip_class_init(GstVideoFlipClass * klass)1298 gst_video_flip_class_init (GstVideoFlipClass * klass)
1299 {
1300   GObjectClass *gobject_class = (GObjectClass *) klass;
1301   GstElementClass *gstelement_class = (GstElementClass *) klass;
1302   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
1303   GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
1304 
1305   GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
1306 
1307   gobject_class->set_property = gst_video_flip_set_property;
1308   gobject_class->get_property = gst_video_flip_get_property;
1309 
1310   g_object_class_install_property (gobject_class, PROP_METHOD,
1311       g_param_spec_enum ("method", "method",
1312           "method (deprecated, use video-direction instead)",
1313           GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
1314           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
1315           G_PARAM_STATIC_STRINGS));
1316   g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
1317       "video-direction");
1318 
1319   gst_element_class_set_static_metadata (gstelement_class, "Video flipper",
1320       "Filter/Effect/Video",
1321       "Flips and rotates video", "David Schleef <ds@schleef.org>");
1322 
1323   gst_element_class_add_static_pad_template (gstelement_class,
1324       &gst_video_flip_sink_template);
1325   gst_element_class_add_static_pad_template (gstelement_class,
1326       &gst_video_flip_src_template);
1327 
1328   trans_class->transform_caps =
1329       GST_DEBUG_FUNCPTR (gst_video_flip_transform_caps);
1330   trans_class->before_transform =
1331       GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
1332   trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
1333   trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_video_flip_sink_event);
1334 
1335   vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info);
1336   vfilter_class->transform_frame =
1337       GST_DEBUG_FUNCPTR (gst_video_flip_transform_frame);
1338 }
1339 
1340 static void
gst_video_flip_init(GstVideoFlip * videoflip)1341 gst_video_flip_init (GstVideoFlip * videoflip)
1342 {
1343   /* AUTO is not valid for active method, this is just to ensure we setup the
1344    * method in gst_video_flip_set_method() */
1345   videoflip->active_method = GST_VIDEO_ORIENTATION_AUTO;
1346 }
1347