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