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>
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.
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.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * This file was (probably) generated from gstvideoflip.c,
25 * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp
28 * SECTION:element-videoflip
30 * Flips and rotates video.
33 * <title>Example launch line</title>
35 * gst-launch videotestsrc ! videoflip method=clockwise ! ffmpegcolorspace ! ximagesink
36 * ]| This pipeline flips the test image 90 degrees clockwise.
39 * Last reviewed on 2010-04-18 (0.10.22)
47 #include "gstvideoflip.h"
51 #include <gst/controller/gstcontroller.h>
52 #include <gst/video/video.h>
54 /* GstVideoFlip properties */
62 #define PROP_METHOD_DEFAULT GST_VIDEO_FLIP_METHOD_IDENTITY
64 GST_DEBUG_CATEGORY_STATIC (video_flip_debug);
65 #define GST_CAT_DEFAULT video_flip_debug
67 static GstStaticPadTemplate gst_video_flip_src_template =
68 GST_STATIC_PAD_TEMPLATE ("src",
71 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
72 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
73 GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
74 GST_VIDEO_CAPS_YUV ("Y444") ";"
75 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
76 GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
77 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
78 GST_VIDEO_CAPS_YUV ("I420") ";"
79 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";"
80 GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";"
81 GST_VIDEO_CAPS_YUV ("YVYU")
86 static GstStaticPadTemplate gst_video_flip_sink_template =
87 GST_STATIC_PAD_TEMPLATE ("sink",
90 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
91 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
92 GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
93 GST_VIDEO_CAPS_YUV ("Y444") ";"
94 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
95 GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
96 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
97 GST_VIDEO_CAPS_YUV ("I420") ";"
98 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";"
99 GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";"
100 GST_VIDEO_CAPS_YUV ("YVYU")
104 #define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
106 static const GEnumValue video_flip_methods[] = {
107 {GST_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
108 {GST_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
109 {GST_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
110 {GST_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
112 {GST_VIDEO_FLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
113 {GST_VIDEO_FLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
114 {GST_VIDEO_FLIP_METHOD_TRANS,
115 "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
116 {GST_VIDEO_FLIP_METHOD_OTHER,
117 "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
122 gst_video_flip_method_get_type (void)
124 static GType video_flip_method_type = 0;
126 if (!video_flip_method_type) {
127 video_flip_method_type = g_enum_register_static ("GstVideoFlipMethod",
130 return video_flip_method_type;
133 GST_BOILERPLATE (GstVideoFlip, gst_video_flip, GstVideoFilter,
134 GST_TYPE_VIDEO_FILTER);
137 gst_video_flip_transform_caps (GstBaseTransform * trans,
138 GstPadDirection direction, GstCaps * caps)
140 GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
142 gint width, height, i;
144 ret = gst_caps_copy (caps);
146 for (i = 0; i < gst_caps_get_size (ret); i++) {
147 GstStructure *structure = gst_caps_get_structure (ret, i);
150 if (gst_structure_get_int (structure, "width", &width) &&
151 gst_structure_get_int (structure, "height", &height)) {
153 switch (videoflip->method) {
154 case GST_VIDEO_FLIP_METHOD_90R:
155 case GST_VIDEO_FLIP_METHOD_90L:
156 case GST_VIDEO_FLIP_METHOD_TRANS:
157 case GST_VIDEO_FLIP_METHOD_OTHER:
158 gst_structure_set (structure, "width", G_TYPE_INT, height,
159 "height", G_TYPE_INT, width, NULL);
160 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
162 if (par_n != 1 || par_d != 1) {
165 g_value_init (&val, GST_TYPE_FRACTION);
166 gst_value_set_fraction (&val, par_d, par_n);
167 gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
168 g_value_unset (&val);
172 case GST_VIDEO_FLIP_METHOD_IDENTITY:
173 case GST_VIDEO_FLIP_METHOD_180:
174 case GST_VIDEO_FLIP_METHOD_HORIZ:
175 case GST_VIDEO_FLIP_METHOD_VERT:
176 gst_structure_set (structure, "width", G_TYPE_INT, width,
177 "height", G_TYPE_INT, height, NULL);
180 g_assert_not_reached ();
186 GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
187 GST_PTR_FORMAT, caps, ret);
193 gst_video_flip_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
196 GstVideoFormat format;
199 if (!gst_video_format_parse_caps (caps, &format, &width, &height))
202 *size = gst_video_format_get_size (format, width, height);
204 GST_DEBUG_OBJECT (btrans, "our frame size is %d bytes (%dx%d)", *size,
211 gst_video_flip_planar_yuv (GstVideoFlip * videoflip, guint8 * dest,
217 GstVideoFormat format = videoflip->format;
218 gint sw = videoflip->from_width;
219 gint sh = videoflip->from_height;
220 gint dw = videoflip->to_width;
221 gint dh = videoflip->to_height;
222 gint src_y_stride, src_u_stride, src_v_stride;
223 gint src_y_offset, src_u_offset, src_v_offset;
224 gint src_y_height, src_u_height, src_v_height;
225 gint src_y_width, src_u_width, src_v_width;
226 gint dest_y_stride, dest_u_stride, dest_v_stride;
227 gint dest_y_offset, dest_u_offset, dest_v_offset;
228 gint dest_y_height, dest_u_height, dest_v_height;
229 gint dest_y_width, dest_u_width, dest_v_width;
231 src_y_stride = gst_video_format_get_row_stride (format, 0, sw);
232 src_u_stride = gst_video_format_get_row_stride (format, 1, sw);
233 src_v_stride = gst_video_format_get_row_stride (format, 2, sw);
235 dest_y_stride = gst_video_format_get_row_stride (format, 0, dw);
236 dest_u_stride = gst_video_format_get_row_stride (format, 1, dw);
237 dest_v_stride = gst_video_format_get_row_stride (format, 2, dw);
239 src_y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
240 src_u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
241 src_v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);
243 dest_y_offset = gst_video_format_get_component_offset (format, 0, dw, dh);
244 dest_u_offset = gst_video_format_get_component_offset (format, 1, dw, dh);
245 dest_v_offset = gst_video_format_get_component_offset (format, 2, dw, dh);
247 src_y_width = gst_video_format_get_component_width (format, 0, sw);
248 src_u_width = gst_video_format_get_component_width (format, 1, sw);
249 src_v_width = gst_video_format_get_component_width (format, 2, sw);
251 dest_y_width = gst_video_format_get_component_width (format, 0, dw);
252 dest_u_width = gst_video_format_get_component_width (format, 1, dw);
253 dest_v_width = gst_video_format_get_component_width (format, 2, dw);
255 src_y_height = gst_video_format_get_component_height (format, 0, sh);
256 src_u_height = gst_video_format_get_component_height (format, 1, sh);
257 src_v_height = gst_video_format_get_component_height (format, 2, sh);
259 dest_y_height = gst_video_format_get_component_height (format, 0, dh);
260 dest_u_height = gst_video_format_get_component_height (format, 1, dh);
261 dest_v_height = gst_video_format_get_component_height (format, 2, dh);
263 switch (videoflip->method) {
264 case GST_VIDEO_FLIP_METHOD_90R:
266 s = src + src_y_offset;
267 d = dest + dest_y_offset;
268 for (y = 0; y < dest_y_height; y++) {
269 for (x = 0; x < dest_y_width; x++) {
270 d[y * dest_y_stride + x] =
271 s[(src_y_height - 1 - x) * src_y_stride + y];
275 s = src + src_u_offset;
276 d = dest + dest_u_offset;
277 for (y = 0; y < dest_u_height; y++) {
278 for (x = 0; x < dest_u_width; x++) {
279 d[y * dest_u_stride + x] =
280 s[(src_u_height - 1 - x) * src_u_stride + y];
284 s = src + src_v_offset;
285 d = dest + dest_v_offset;
286 for (y = 0; y < dest_v_height; y++) {
287 for (x = 0; x < dest_v_width; x++) {
288 d[y * dest_v_stride + x] =
289 s[(src_v_height - 1 - x) * src_v_stride + y];
293 case GST_VIDEO_FLIP_METHOD_90L:
295 s = src + src_y_offset;
296 d = dest + dest_y_offset;
297 for (y = 0; y < dest_y_height; y++) {
298 for (x = 0; x < dest_y_width; x++) {
299 d[y * dest_y_stride + x] =
300 s[x * src_y_stride + (src_y_width - 1 - y)];
304 s = src + src_u_offset;
305 d = dest + dest_u_offset;
306 for (y = 0; y < dest_u_height; y++) {
307 for (x = 0; x < dest_u_width; x++) {
308 d[y * dest_u_stride + x] =
309 s[x * src_u_stride + (src_u_width - 1 - y)];
313 s = src + src_v_offset;
314 d = dest + dest_v_offset;
315 for (y = 0; y < dest_v_height; y++) {
316 for (x = 0; x < dest_v_width; x++) {
317 d[y * dest_v_stride + x] =
318 s[x * src_v_stride + (src_v_width - 1 - y)];
322 case GST_VIDEO_FLIP_METHOD_180:
324 s = src + src_y_offset;
325 d = dest + dest_y_offset;
326 for (y = 0; y < dest_y_height; y++) {
327 for (x = 0; x < dest_y_width; x++) {
328 d[y * dest_y_stride + x] =
329 s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
333 s = src + src_u_offset;
334 d = dest + dest_u_offset;
335 for (y = 0; y < dest_u_height; y++) {
336 for (x = 0; x < dest_u_width; x++) {
337 d[y * dest_u_stride + x] =
338 s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
342 s = src + src_v_offset;
343 d = dest + dest_v_offset;
344 for (y = 0; y < dest_v_height; y++) {
345 for (x = 0; x < dest_v_width; x++) {
346 d[y * dest_v_stride + x] =
347 s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
351 case GST_VIDEO_FLIP_METHOD_HORIZ:
353 s = src + src_y_offset;
354 d = dest + dest_y_offset;
355 for (y = 0; y < dest_y_height; y++) {
356 for (x = 0; x < dest_y_width; x++) {
357 d[y * dest_y_stride + x] =
358 s[y * src_y_stride + (src_y_width - 1 - x)];
362 s = src + src_u_offset;
363 d = dest + dest_u_offset;
364 for (y = 0; y < dest_u_height; y++) {
365 for (x = 0; x < dest_u_width; x++) {
366 d[y * dest_u_stride + x] =
367 s[y * src_u_stride + (src_u_width - 1 - x)];
371 s = src + src_v_offset;
372 d = dest + dest_v_offset;
373 for (y = 0; y < dest_v_height; y++) {
374 for (x = 0; x < dest_v_width; x++) {
375 d[y * dest_v_stride + x] =
376 s[y * src_v_stride + (src_v_width - 1 - x)];
380 case GST_VIDEO_FLIP_METHOD_VERT:
382 s = src + src_y_offset;
383 d = dest + dest_y_offset;
384 for (y = 0; y < dest_y_height; y++) {
385 for (x = 0; x < dest_y_width; x++) {
386 d[y * dest_y_stride + x] =
387 s[(src_y_height - 1 - y) * src_y_stride + x];
391 s = src + src_u_offset;
392 d = dest + dest_u_offset;
393 for (y = 0; y < dest_u_height; y++) {
394 for (x = 0; x < dest_u_width; x++) {
395 d[y * dest_u_stride + x] =
396 s[(src_u_height - 1 - y) * src_u_stride + x];
400 s = src + src_v_offset;
401 d = dest + dest_v_offset;
402 for (y = 0; y < dest_v_height; y++) {
403 for (x = 0; x < dest_v_width; x++) {
404 d[y * dest_v_stride + x] =
405 s[(src_v_height - 1 - y) * src_v_stride + x];
409 case GST_VIDEO_FLIP_METHOD_TRANS:
411 s = src + src_y_offset;
412 d = dest + dest_y_offset;
413 for (y = 0; y < dest_y_height; y++) {
414 for (x = 0; x < dest_y_width; x++) {
415 d[y * dest_y_stride + x] = s[x * src_y_stride + y];
419 s = src + src_u_offset;
420 d = dest + dest_u_offset;
421 for (y = 0; y < dest_u_height; y++) {
422 for (x = 0; x < dest_u_width; x++) {
423 d[y * dest_u_stride + x] = s[x * src_u_stride + y];
427 s = src + src_v_offset;
428 d = dest + dest_v_offset;
429 for (y = 0; y < dest_u_height; y++) {
430 for (x = 0; x < dest_u_width; x++) {
431 d[y * dest_v_stride + x] = s[x * src_v_stride + y];
435 case GST_VIDEO_FLIP_METHOD_OTHER:
437 s = src + src_y_offset;
438 d = dest + dest_y_offset;
439 for (y = 0; y < dest_y_height; y++) {
440 for (x = 0; x < dest_y_width; x++) {
441 d[y * dest_y_stride + x] =
442 s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
446 s = src + src_u_offset;
447 d = dest + dest_u_offset;
448 for (y = 0; y < dest_u_height; y++) {
449 for (x = 0; x < dest_u_width; x++) {
450 d[y * dest_u_stride + x] =
451 s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
455 s = src + src_v_offset;
456 d = dest + dest_v_offset;
457 for (y = 0; y < dest_v_height; y++) {
458 for (x = 0; x < dest_v_width; x++) {
459 d[y * dest_v_stride + x] =
460 s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
464 case GST_VIDEO_FLIP_METHOD_IDENTITY:
465 g_assert_not_reached ();
468 g_assert_not_reached ();
474 gst_video_flip_packed_simple (GstVideoFlip * videoflip, guint8 * dest,
478 guint8 const *s = src;
480 GstVideoFormat format = videoflip->format;
481 gint sw = videoflip->from_width;
482 gint sh = videoflip->from_height;
483 gint dw = videoflip->to_width;
484 gint dh = videoflip->to_height;
485 gint src_stride, dest_stride;
488 src_stride = gst_video_format_get_row_stride (format, 0, sw);
489 dest_stride = gst_video_format_get_row_stride (format, 0, dw);
490 /* This is only true for non-subsampled formats! */
491 bpp = gst_video_format_get_pixel_stride (format, 0);
493 switch (videoflip->method) {
494 case GST_VIDEO_FLIP_METHOD_90R:
495 for (y = 0; y < dh; y++) {
496 for (x = 0; x < dw; x++) {
497 for (z = 0; z < bpp; z++) {
498 d[y * dest_stride + x * bpp + z] =
499 s[(sh - 1 - x) * src_stride + y * bpp + z];
504 case GST_VIDEO_FLIP_METHOD_90L:
505 for (y = 0; y < dh; y++) {
506 for (x = 0; x < dw; x++) {
507 for (z = 0; z < bpp; z++) {
508 d[y * dest_stride + x * bpp + z] =
509 s[x * src_stride + (sw - 1 - y) * bpp + z];
514 case GST_VIDEO_FLIP_METHOD_180:
515 for (y = 0; y < dh; y++) {
516 for (x = 0; x < dw; x++) {
517 for (z = 0; z < bpp; z++) {
518 d[y * dest_stride + x * bpp + z] =
519 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + z];
524 case GST_VIDEO_FLIP_METHOD_HORIZ:
525 for (y = 0; y < dh; y++) {
526 for (x = 0; x < dw; x++) {
527 for (z = 0; z < bpp; z++) {
528 d[y * dest_stride + x * bpp + z] =
529 s[y * src_stride + (sw - 1 - x) * bpp + z];
534 case GST_VIDEO_FLIP_METHOD_VERT:
535 for (y = 0; y < dh; y++) {
536 for (x = 0; x < dw; x++) {
537 for (z = 0; z < bpp; z++) {
538 d[y * dest_stride + x * bpp + z] =
539 s[(sh - 1 - y) * src_stride + x * bpp + z];
544 case GST_VIDEO_FLIP_METHOD_TRANS:
545 for (y = 0; y < dh; y++) {
546 for (x = 0; x < dw; x++) {
547 for (z = 0; z < bpp; z++) {
548 d[y * dest_stride + x * bpp + z] = s[x * src_stride + y * bpp + z];
553 case GST_VIDEO_FLIP_METHOD_OTHER:
554 for (y = 0; y < dh; y++) {
555 for (x = 0; x < dw; x++) {
556 for (z = 0; z < bpp; z++) {
557 d[y * dest_stride + x * bpp + z] =
558 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + z];
563 case GST_VIDEO_FLIP_METHOD_IDENTITY:
564 g_assert_not_reached ();
567 g_assert_not_reached ();
574 gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest,
578 guint8 const *s = src;
580 GstVideoFormat format = videoflip->format;
581 gint sw = videoflip->from_width;
582 gint sh = videoflip->from_height;
583 gint dw = videoflip->to_width;
584 gint dh = videoflip->to_height;
585 gint src_stride, dest_stride;
592 src_stride = gst_video_format_get_row_stride (format, 0, sw);
593 dest_stride = gst_video_format_get_row_stride (format, 0, dw);
595 y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
596 u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
597 v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);
598 y_stride = gst_video_format_get_pixel_stride (format, 0);
601 switch (videoflip->method) {
602 case GST_VIDEO_FLIP_METHOD_90R:
603 for (y = 0; y < dh; y++) {
604 for (x = 0; x < dw; x += 2) {
607 /* u/v must be calculated using the offset of the even column */
608 gint even_y = (y & ~1);
610 u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
612 u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
614 v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
616 v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
619 d[y * dest_stride + x * bpp + u_offset] = u;
620 d[y * dest_stride + x * bpp + v_offset] = v;
621 d[y * dest_stride + x * bpp + y_offset] =
622 s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
624 d[y * dest_stride + (x + 1) * bpp + y_offset] =
625 s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
629 case GST_VIDEO_FLIP_METHOD_90L:
630 for (y = 0; y < dh; y++) {
631 for (x = 0; x < dw; x += 2) {
634 /* u/v must be calculated using the offset of the even column */
635 gint even_y = ((sw - 1 - y) & ~1);
637 u = s[x * src_stride + even_y * bpp + u_offset];
639 u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
640 v = s[x * src_stride + even_y * bpp + v_offset];
642 v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
644 d[y * dest_stride + x * bpp + u_offset] = u;
645 d[y * dest_stride + x * bpp + v_offset] = v;
646 d[y * dest_stride + x * bpp + y_offset] =
647 s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
649 d[y * dest_stride + (x + 1) * bpp + y_offset] =
650 s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
654 case GST_VIDEO_FLIP_METHOD_180:
655 for (y = 0; y < dh; y++) {
656 for (x = 0; x < dw; x += 2) {
659 /* u/v must be calculated using the offset of the even column */
660 gint even_x = ((sw - 1 - x) & ~1);
662 u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
663 s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
664 v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
665 s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
667 d[y * dest_stride + x * bpp + u_offset] = u;
668 d[y * dest_stride + x * bpp + v_offset] = v;
669 d[y * dest_stride + x * bpp + y_offset] =
670 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
672 d[y * dest_stride + (x + 1) * bpp + y_offset] =
673 s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
678 case GST_VIDEO_FLIP_METHOD_HORIZ:
679 for (y = 0; y < dh; y++) {
680 for (x = 0; x < dw; x += 2) {
683 /* u/v must be calculated using the offset of the even column */
684 gint even_x = ((sw - 1 - x) & ~1);
686 u = (s[y * src_stride + even_x * bpp + u_offset] +
687 s[y * src_stride + even_x * bpp + u_offset]) / 2;
688 v = (s[y * src_stride + even_x * bpp + v_offset] +
689 s[y * src_stride + even_x * bpp + v_offset]) / 2;
691 d[y * dest_stride + x * bpp + u_offset] = u;
692 d[y * dest_stride + x * bpp + v_offset] = v;
693 d[y * dest_stride + x * bpp + y_offset] =
694 s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
696 d[y * dest_stride + (x + 1) * bpp + y_offset] =
697 s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
701 case GST_VIDEO_FLIP_METHOD_VERT:
702 for (y = 0; y < dh; y++) {
703 for (x = 0; x < dw; x += 2) {
706 /* u/v must be calculated using the offset of the even column */
707 gint even_x = (x & ~1);
709 u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
710 s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
711 v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
712 s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
714 d[y * dest_stride + x * bpp + u_offset] = u;
715 d[y * dest_stride + x * bpp + v_offset] = v;
716 d[y * dest_stride + x * bpp + y_offset] =
717 s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
719 d[y * dest_stride + (x + 1) * bpp + y_offset] =
720 s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
724 case GST_VIDEO_FLIP_METHOD_TRANS:
725 for (y = 0; y < dh; y++) {
726 for (x = 0; x < dw; x += 2) {
729 /* u/v must be calculated using the offset of the even column */
730 gint even_y = (y & ~1);
732 u = s[x * src_stride + even_y * bpp + u_offset];
734 u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
735 v = s[x * src_stride + even_y * bpp + v_offset];
737 v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
739 d[y * dest_stride + x * bpp + u_offset] = u;
740 d[y * dest_stride + x * bpp + v_offset] = v;
741 d[y * dest_stride + x * bpp + y_offset] =
742 s[x * src_stride + y * bpp + y_offset];
744 d[y * dest_stride + (x + 1) * bpp + y_offset] =
745 s[(x + 1) * src_stride + y * bpp + y_offset];
749 case GST_VIDEO_FLIP_METHOD_OTHER:
750 for (y = 0; y < dh; y++) {
751 for (x = 0; x < dw; x += 2) {
754 /* u/v must be calculated using the offset of the even column */
755 gint even_y = ((sw - 1 - y) & ~1);
757 u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
759 u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
761 v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
763 v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
766 d[y * dest_stride + x * bpp + u_offset] = u;
767 d[y * dest_stride + x * bpp + v_offset] = v;
768 d[y * dest_stride + x * bpp + y_offset] =
769 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
771 d[y * dest_stride + (x + 1) * bpp + y_offset] =
772 s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
777 case GST_VIDEO_FLIP_METHOD_IDENTITY:
778 g_assert_not_reached ();
781 g_assert_not_reached ();
788 gst_video_flip_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
791 GstVideoFlip *vf = GST_VIDEO_FLIP (btrans);
792 GstVideoFormat in_format, out_format;
793 gboolean ret = FALSE;
797 if (!gst_video_format_parse_caps (incaps, &in_format, &vf->from_width,
799 || !gst_video_format_parse_caps (outcaps, &out_format, &vf->to_width,
803 if (in_format != out_format)
805 vf->format = in_format;
807 /* Check that they are correct */
808 switch (vf->method) {
809 case GST_VIDEO_FLIP_METHOD_90R:
810 case GST_VIDEO_FLIP_METHOD_90L:
811 case GST_VIDEO_FLIP_METHOD_TRANS:
812 case GST_VIDEO_FLIP_METHOD_OTHER:
813 if ((vf->from_width != vf->to_height) ||
814 (vf->from_height != vf->to_width)) {
815 GST_ERROR_OBJECT (vf, "we are inverting width and height but caps "
816 "are not correct : %dx%d to %dx%d", vf->from_width,
817 vf->from_height, vf->to_width, vf->to_height);
821 case GST_VIDEO_FLIP_METHOD_IDENTITY:
824 case GST_VIDEO_FLIP_METHOD_180:
825 case GST_VIDEO_FLIP_METHOD_HORIZ:
826 case GST_VIDEO_FLIP_METHOD_VERT:
827 if ((vf->from_width != vf->to_width) ||
828 (vf->from_height != vf->to_height)) {
829 GST_ERROR_OBJECT (vf, "we are keeping width and height but caps "
830 "are not correct : %dx%d to %dx%d", vf->from_width,
831 vf->from_height, vf->to_width, vf->to_height);
836 g_assert_not_reached ();
842 switch (vf->format) {
843 case GST_VIDEO_FORMAT_I420:
844 case GST_VIDEO_FORMAT_YV12:
845 case GST_VIDEO_FORMAT_Y444:
846 vf->process = gst_video_flip_planar_yuv;
848 case GST_VIDEO_FORMAT_YUY2:
849 case GST_VIDEO_FORMAT_UYVY:
850 case GST_VIDEO_FORMAT_YVYU:
851 vf->process = gst_video_flip_y422;
853 case GST_VIDEO_FORMAT_AYUV:
854 case GST_VIDEO_FORMAT_ARGB:
855 case GST_VIDEO_FORMAT_ABGR:
856 case GST_VIDEO_FORMAT_RGBA:
857 case GST_VIDEO_FORMAT_BGRA:
858 case GST_VIDEO_FORMAT_xRGB:
859 case GST_VIDEO_FORMAT_xBGR:
860 case GST_VIDEO_FORMAT_RGBx:
861 case GST_VIDEO_FORMAT_BGRx:
862 case GST_VIDEO_FORMAT_RGB:
863 case GST_VIDEO_FORMAT_BGR:
864 vf->process = gst_video_flip_packed_simple;
871 return ret && (vf->process != NULL);
874 GST_ERROR_OBJECT (vf, "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT,
880 gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
882 GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
883 GstClockTime timestamp, stream_time;
885 timestamp = GST_BUFFER_TIMESTAMP (in);
887 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
889 GST_DEBUG_OBJECT (videoflip, "sync to %" GST_TIME_FORMAT,
890 GST_TIME_ARGS (timestamp));
892 if (GST_CLOCK_TIME_IS_VALID (stream_time))
893 gst_object_sync_values (G_OBJECT (videoflip), stream_time);
897 gst_video_flip_transform (GstBaseTransform * trans, GstBuffer * in,
900 GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
904 if (G_UNLIKELY (videoflip->process == NULL))
907 src = GST_BUFFER_DATA (in);
908 dest = GST_BUFFER_DATA (out);
910 GST_LOG_OBJECT (videoflip, "videoflip: flipping %dx%d to %dx%d (%s)",
911 videoflip->from_width, videoflip->from_height, videoflip->to_width,
912 videoflip->to_height, video_flip_methods[videoflip->method].value_nick);
914 GST_OBJECT_LOCK (videoflip);
915 videoflip->process (videoflip, dest, src);
916 GST_OBJECT_UNLOCK (videoflip);
921 GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
922 return GST_FLOW_NOT_NEGOTIATED;
926 gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
928 GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
929 gdouble new_x, new_y, x, y;
930 GstStructure *structure;
933 GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
935 switch (GST_EVENT_TYPE (event)) {
936 case GST_EVENT_NAVIGATION:
938 GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
940 structure = (GstStructure *) gst_event_get_structure (event);
941 if (gst_structure_get_double (structure, "pointer_x", &x) &&
942 gst_structure_get_double (structure, "pointer_y", &y)) {
943 GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
944 switch (vf->method) {
945 case GST_VIDEO_FLIP_METHOD_90R:
947 new_y = vf->to_width - x;
949 case GST_VIDEO_FLIP_METHOD_90L:
950 new_x = vf->to_height - y;
953 case GST_VIDEO_FLIP_METHOD_OTHER:
954 new_x = vf->to_height - y;
955 new_y = vf->to_width - x;
957 case GST_VIDEO_FLIP_METHOD_TRANS:
961 case GST_VIDEO_FLIP_METHOD_180:
962 new_x = vf->to_width - x;
963 new_y = vf->to_height - y;
965 case GST_VIDEO_FLIP_METHOD_HORIZ:
966 new_x = vf->to_width - x;
969 case GST_VIDEO_FLIP_METHOD_VERT:
971 new_y = vf->to_height - y;
978 GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
979 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
980 "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
987 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
993 gst_video_flip_set_property (GObject * object, guint prop_id,
994 const GValue * value, GParamSpec * pspec)
996 GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
1001 GstVideoFlipMethod method;
1003 method = g_value_get_enum (value);
1004 GST_OBJECT_LOCK (videoflip);
1005 if (method != videoflip->method) {
1006 GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
1008 GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
1009 video_flip_methods[videoflip->method].value_nick,
1010 video_flip_methods[method].value_nick);
1012 videoflip->method = method;
1013 GST_OBJECT_UNLOCK (videoflip);
1015 gst_base_transform_set_passthrough (btrans,
1016 method == GST_VIDEO_FLIP_METHOD_IDENTITY);
1017 gst_base_transform_reconfigure (btrans);
1019 GST_OBJECT_UNLOCK (videoflip);
1024 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1030 gst_video_flip_get_property (GObject * object, guint prop_id, GValue * value,
1033 GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
1037 g_value_set_enum (value, videoflip->method);
1040 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1046 gst_video_flip_base_init (gpointer g_class)
1048 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1050 gst_element_class_set_details_simple (element_class, "Video flipper",
1051 "Filter/Effect/Video",
1052 "Flips and rotates video", "David Schleef <ds@schleef.org>");
1054 gst_element_class_add_static_pad_template (element_class,
1055 &gst_video_flip_sink_template);
1056 gst_element_class_add_static_pad_template (element_class,
1057 &gst_video_flip_src_template);
1061 gst_video_flip_class_init (GstVideoFlipClass * klass)
1063 GObjectClass *gobject_class = (GObjectClass *) klass;
1064 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
1066 GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
1068 gobject_class->set_property = gst_video_flip_set_property;
1069 gobject_class->get_property = gst_video_flip_get_property;
1071 g_object_class_install_property (gobject_class, PROP_METHOD,
1072 g_param_spec_enum ("method", "method", "method",
1073 GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
1074 GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1076 trans_class->transform_caps =
1077 GST_DEBUG_FUNCPTR (gst_video_flip_transform_caps);
1078 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_flip_set_caps);
1079 trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_flip_get_unit_size);
1080 trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_flip_transform);
1081 trans_class->before_transform =
1082 GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
1083 trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
1087 gst_video_flip_init (GstVideoFlip * videoflip, GstVideoFlipClass * klass)
1089 videoflip->method = PROP_METHOD_DEFAULT;
1090 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip), TRUE);