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/video/video.h>
53 /* GstVideoFlip properties */
61 #define PROP_METHOD_DEFAULT GST_VIDEO_FLIP_METHOD_IDENTITY
63 GST_DEBUG_CATEGORY_STATIC (video_flip_debug);
64 #define GST_CAT_DEFAULT video_flip_debug
66 static GstStaticPadTemplate gst_video_flip_src_template =
67 GST_STATIC_PAD_TEMPLATE ("src",
70 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
71 "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx,xBGR, BGRx, "
72 "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU }"))
75 static GstStaticPadTemplate gst_video_flip_sink_template =
76 GST_STATIC_PAD_TEMPLATE ("sink",
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 }"))
84 #define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
86 static const GEnumValue video_flip_methods[] = {
87 {GST_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
88 {GST_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
89 {GST_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
90 {GST_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
92 {GST_VIDEO_FLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
93 {GST_VIDEO_FLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
94 {GST_VIDEO_FLIP_METHOD_TRANS,
95 "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
96 {GST_VIDEO_FLIP_METHOD_OTHER,
97 "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
102 gst_video_flip_method_get_type (void)
104 static GType video_flip_method_type = 0;
106 if (!video_flip_method_type) {
107 video_flip_method_type = g_enum_register_static ("GstVideoFlipMethod",
110 return video_flip_method_type;
113 #define gst_video_flip_parent_class parent_class
114 G_DEFINE_TYPE (GstVideoFlip, gst_video_flip, GST_TYPE_VIDEO_FILTER);
117 gst_video_flip_transform_caps (GstBaseTransform * trans,
118 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
120 GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
122 gint width, height, i;
124 ret = gst_caps_copy (caps);
126 for (i = 0; i < gst_caps_get_size (ret); i++) {
127 GstStructure *structure = gst_caps_get_structure (ret, i);
130 if (gst_structure_get_int (structure, "width", &width) &&
131 gst_structure_get_int (structure, "height", &height)) {
133 switch (videoflip->method) {
134 case GST_VIDEO_FLIP_METHOD_90R:
135 case GST_VIDEO_FLIP_METHOD_90L:
136 case GST_VIDEO_FLIP_METHOD_TRANS:
137 case GST_VIDEO_FLIP_METHOD_OTHER:
138 gst_structure_set (structure, "width", G_TYPE_INT, height,
139 "height", G_TYPE_INT, width, NULL);
140 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
142 if (par_n != 1 || par_d != 1) {
145 g_value_init (&val, GST_TYPE_FRACTION);
146 gst_value_set_fraction (&val, par_d, par_n);
147 gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
148 g_value_unset (&val);
152 case GST_VIDEO_FLIP_METHOD_IDENTITY:
153 case GST_VIDEO_FLIP_METHOD_180:
154 case GST_VIDEO_FLIP_METHOD_HORIZ:
155 case GST_VIDEO_FLIP_METHOD_VERT:
156 gst_structure_set (structure, "width", G_TYPE_INT, width,
157 "height", G_TYPE_INT, height, NULL);
160 g_assert_not_reached ();
166 GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
167 GST_PTR_FORMAT, caps, ret);
170 GstCaps *intersection;
172 GST_DEBUG_OBJECT (videoflip, "Using filter caps %" GST_PTR_FORMAT, filter);
174 gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
175 gst_caps_unref (ret);
177 GST_DEBUG_OBJECT (videoflip, "Intersection %" GST_PTR_FORMAT, ret);
184 gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
185 const GstVideoFrame * src)
190 gint src_y_stride, src_u_stride, src_v_stride;
191 gint src_y_height, src_u_height, src_v_height;
192 gint src_y_width, src_u_width, src_v_width;
193 gint dest_y_stride, dest_u_stride, dest_v_stride;
194 gint dest_y_height, dest_u_height, dest_v_height;
195 gint dest_y_width, dest_u_width, dest_v_width;
197 src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
198 src_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1);
199 src_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 2);
201 dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
202 dest_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1);
203 dest_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 2);
205 src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
206 src_u_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
207 src_v_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 2);
209 dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
210 dest_u_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
211 dest_v_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 2);
213 src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
214 src_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
215 src_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 2);
217 dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
218 dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
219 dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
221 switch (videoflip->method) {
222 case GST_VIDEO_FLIP_METHOD_90R:
224 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
225 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
226 for (y = 0; y < dest_y_height; y++) {
227 for (x = 0; x < dest_y_width; x++) {
228 d[y * dest_y_stride + x] =
229 s[(src_y_height - 1 - x) * src_y_stride + y];
233 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
234 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
235 for (y = 0; y < dest_u_height; y++) {
236 for (x = 0; x < dest_u_width; x++) {
237 d[y * dest_u_stride + x] =
238 s[(src_u_height - 1 - x) * src_u_stride + y];
242 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
243 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
244 for (y = 0; y < dest_v_height; y++) {
245 for (x = 0; x < dest_v_width; x++) {
246 d[y * dest_v_stride + x] =
247 s[(src_v_height - 1 - x) * src_v_stride + y];
251 case GST_VIDEO_FLIP_METHOD_90L:
253 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
254 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
255 for (y = 0; y < dest_y_height; y++) {
256 for (x = 0; x < dest_y_width; x++) {
257 d[y * dest_y_stride + x] =
258 s[x * src_y_stride + (src_y_width - 1 - y)];
262 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
263 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
264 for (y = 0; y < dest_u_height; y++) {
265 for (x = 0; x < dest_u_width; x++) {
266 d[y * dest_u_stride + x] =
267 s[x * src_u_stride + (src_u_width - 1 - y)];
271 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
272 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
273 for (y = 0; y < dest_v_height; y++) {
274 for (x = 0; x < dest_v_width; x++) {
275 d[y * dest_v_stride + x] =
276 s[x * src_v_stride + (src_v_width - 1 - y)];
280 case GST_VIDEO_FLIP_METHOD_180:
282 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
283 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
284 for (y = 0; y < dest_y_height; y++) {
285 for (x = 0; x < dest_y_width; x++) {
286 d[y * dest_y_stride + x] =
287 s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
291 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
292 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
293 for (y = 0; y < dest_u_height; y++) {
294 for (x = 0; x < dest_u_width; x++) {
295 d[y * dest_u_stride + x] =
296 s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
300 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
301 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
302 for (y = 0; y < dest_v_height; y++) {
303 for (x = 0; x < dest_v_width; x++) {
304 d[y * dest_v_stride + x] =
305 s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
309 case GST_VIDEO_FLIP_METHOD_HORIZ:
311 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
312 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
313 for (y = 0; y < dest_y_height; y++) {
314 for (x = 0; x < dest_y_width; x++) {
315 d[y * dest_y_stride + x] =
316 s[y * src_y_stride + (src_y_width - 1 - x)];
320 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
321 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
322 for (y = 0; y < dest_u_height; y++) {
323 for (x = 0; x < dest_u_width; x++) {
324 d[y * dest_u_stride + x] =
325 s[y * src_u_stride + (src_u_width - 1 - x)];
329 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
330 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
331 for (y = 0; y < dest_v_height; y++) {
332 for (x = 0; x < dest_v_width; x++) {
333 d[y * dest_v_stride + x] =
334 s[y * src_v_stride + (src_v_width - 1 - x)];
338 case GST_VIDEO_FLIP_METHOD_VERT:
340 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
341 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
342 for (y = 0; y < dest_y_height; y++) {
343 for (x = 0; x < dest_y_width; x++) {
344 d[y * dest_y_stride + x] =
345 s[(src_y_height - 1 - y) * src_y_stride + x];
349 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
350 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
351 for (y = 0; y < dest_u_height; y++) {
352 for (x = 0; x < dest_u_width; x++) {
353 d[y * dest_u_stride + x] =
354 s[(src_u_height - 1 - y) * src_u_stride + x];
358 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
359 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
360 for (y = 0; y < dest_v_height; y++) {
361 for (x = 0; x < dest_v_width; x++) {
362 d[y * dest_v_stride + x] =
363 s[(src_v_height - 1 - y) * src_v_stride + x];
367 case GST_VIDEO_FLIP_METHOD_TRANS:
369 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
370 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
371 for (y = 0; y < dest_y_height; y++) {
372 for (x = 0; x < dest_y_width; x++) {
373 d[y * dest_y_stride + x] = s[x * src_y_stride + y];
377 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
378 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
379 for (y = 0; y < dest_u_height; y++) {
380 for (x = 0; x < dest_u_width; x++) {
381 d[y * dest_u_stride + x] = s[x * src_u_stride + y];
385 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
386 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
387 for (y = 0; y < dest_u_height; y++) {
388 for (x = 0; x < dest_u_width; x++) {
389 d[y * dest_v_stride + x] = s[x * src_v_stride + y];
393 case GST_VIDEO_FLIP_METHOD_OTHER:
395 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
396 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
397 for (y = 0; y < dest_y_height; y++) {
398 for (x = 0; x < dest_y_width; x++) {
399 d[y * dest_y_stride + x] =
400 s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
404 s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
405 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
406 for (y = 0; y < dest_u_height; y++) {
407 for (x = 0; x < dest_u_width; x++) {
408 d[y * dest_u_stride + x] =
409 s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
413 s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
414 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
415 for (y = 0; y < dest_v_height; y++) {
416 for (x = 0; x < dest_v_width; x++) {
417 d[y * dest_v_stride + x] =
418 s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
422 case GST_VIDEO_FLIP_METHOD_IDENTITY:
423 g_assert_not_reached ();
426 g_assert_not_reached ();
432 gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest,
433 const GstVideoFrame * src)
438 gint sw = GST_VIDEO_FRAME_WIDTH (src);
439 gint sh = GST_VIDEO_FRAME_HEIGHT (src);
440 gint dw = GST_VIDEO_FRAME_WIDTH (dest);
441 gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
442 gint src_stride, dest_stride;
445 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
446 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
448 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
449 dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
450 /* This is only true for non-subsampled formats! */
451 bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
453 switch (videoflip->method) {
454 case GST_VIDEO_FLIP_METHOD_90R:
455 for (y = 0; y < dh; y++) {
456 for (x = 0; x < dw; x++) {
457 for (z = 0; z < bpp; z++) {
458 d[y * dest_stride + x * bpp + z] =
459 s[(sh - 1 - x) * src_stride + y * bpp + z];
464 case GST_VIDEO_FLIP_METHOD_90L:
465 for (y = 0; y < dh; y++) {
466 for (x = 0; x < dw; x++) {
467 for (z = 0; z < bpp; z++) {
468 d[y * dest_stride + x * bpp + z] =
469 s[x * src_stride + (sw - 1 - y) * bpp + z];
474 case GST_VIDEO_FLIP_METHOD_180:
475 for (y = 0; y < dh; y++) {
476 for (x = 0; x < dw; x++) {
477 for (z = 0; z < bpp; z++) {
478 d[y * dest_stride + x * bpp + z] =
479 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + z];
484 case GST_VIDEO_FLIP_METHOD_HORIZ:
485 for (y = 0; y < dh; y++) {
486 for (x = 0; x < dw; x++) {
487 for (z = 0; z < bpp; z++) {
488 d[y * dest_stride + x * bpp + z] =
489 s[y * src_stride + (sw - 1 - x) * bpp + z];
494 case GST_VIDEO_FLIP_METHOD_VERT:
495 for (y = 0; y < dh; y++) {
496 for (x = 0; x < dw; x++) {
497 for (z = 0; z < bpp; z++) {
498 d[y * dest_stride + x * bpp + z] =
499 s[(sh - 1 - y) * src_stride + x * bpp + z];
504 case GST_VIDEO_FLIP_METHOD_TRANS:
505 for (y = 0; y < dh; y++) {
506 for (x = 0; x < dw; x++) {
507 for (z = 0; z < bpp; z++) {
508 d[y * dest_stride + x * bpp + z] = s[x * src_stride + y * bpp + z];
513 case GST_VIDEO_FLIP_METHOD_OTHER:
514 for (y = 0; y < dh; y++) {
515 for (x = 0; x < dw; x++) {
516 for (z = 0; z < bpp; z++) {
517 d[y * dest_stride + x * bpp + z] =
518 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + z];
523 case GST_VIDEO_FLIP_METHOD_IDENTITY:
524 g_assert_not_reached ();
527 g_assert_not_reached ();
534 gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest,
535 const GstVideoFrame * src)
540 gint sw = GST_VIDEO_FRAME_WIDTH (src);
541 gint sh = GST_VIDEO_FRAME_HEIGHT (src);
542 gint dw = GST_VIDEO_FRAME_WIDTH (dest);
543 gint dh = GST_VIDEO_FRAME_HEIGHT (dest);
544 gint src_stride, dest_stride;
551 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
552 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
554 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0);
555 dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0);
557 y_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 0);
558 u_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 1);
559 v_offset = GST_VIDEO_FRAME_COMP_OFFSET (src, 2);
560 y_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
563 switch (videoflip->method) {
564 case GST_VIDEO_FLIP_METHOD_90R:
565 for (y = 0; y < dh; y++) {
566 for (x = 0; x < dw; x += 2) {
569 /* u/v must be calculated using the offset of the even column */
570 gint even_y = (y & ~1);
572 u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
574 u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
576 v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
578 v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
581 d[y * dest_stride + x * bpp + u_offset] = u;
582 d[y * dest_stride + x * bpp + v_offset] = v;
583 d[y * dest_stride + x * bpp + y_offset] =
584 s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
586 d[y * dest_stride + (x + 1) * bpp + y_offset] =
587 s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
591 case GST_VIDEO_FLIP_METHOD_90L:
592 for (y = 0; y < dh; y++) {
593 for (x = 0; x < dw; x += 2) {
596 /* u/v must be calculated using the offset of the even column */
597 gint even_y = ((sw - 1 - y) & ~1);
599 u = s[x * src_stride + even_y * bpp + u_offset];
601 u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
602 v = s[x * src_stride + even_y * bpp + v_offset];
604 v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
606 d[y * dest_stride + x * bpp + u_offset] = u;
607 d[y * dest_stride + x * bpp + v_offset] = v;
608 d[y * dest_stride + x * bpp + y_offset] =
609 s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
611 d[y * dest_stride + (x + 1) * bpp + y_offset] =
612 s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
616 case GST_VIDEO_FLIP_METHOD_180:
617 for (y = 0; y < dh; y++) {
618 for (x = 0; x < dw; x += 2) {
621 /* u/v must be calculated using the offset of the even column */
622 gint even_x = ((sw - 1 - x) & ~1);
624 u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
625 s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
626 v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
627 s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
629 d[y * dest_stride + x * bpp + u_offset] = u;
630 d[y * dest_stride + x * bpp + v_offset] = v;
631 d[y * dest_stride + x * bpp + y_offset] =
632 s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
634 d[y * dest_stride + (x + 1) * bpp + y_offset] =
635 s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
640 case GST_VIDEO_FLIP_METHOD_HORIZ:
641 for (y = 0; y < dh; y++) {
642 for (x = 0; x < dw; x += 2) {
645 /* u/v must be calculated using the offset of the even column */
646 gint even_x = ((sw - 1 - x) & ~1);
648 u = (s[y * src_stride + even_x * bpp + u_offset] +
649 s[y * src_stride + even_x * bpp + u_offset]) / 2;
650 v = (s[y * src_stride + even_x * bpp + v_offset] +
651 s[y * src_stride + even_x * bpp + v_offset]) / 2;
653 d[y * dest_stride + x * bpp + u_offset] = u;
654 d[y * dest_stride + x * bpp + v_offset] = v;
655 d[y * dest_stride + x * bpp + y_offset] =
656 s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
658 d[y * dest_stride + (x + 1) * bpp + y_offset] =
659 s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
663 case GST_VIDEO_FLIP_METHOD_VERT:
664 for (y = 0; y < dh; y++) {
665 for (x = 0; x < dw; x += 2) {
668 /* u/v must be calculated using the offset of the even column */
669 gint even_x = (x & ~1);
671 u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
672 s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
673 v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
674 s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;
676 d[y * dest_stride + x * bpp + u_offset] = u;
677 d[y * dest_stride + x * bpp + v_offset] = v;
678 d[y * dest_stride + x * bpp + y_offset] =
679 s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
681 d[y * dest_stride + (x + 1) * bpp + y_offset] =
682 s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
686 case GST_VIDEO_FLIP_METHOD_TRANS:
687 for (y = 0; y < dh; y++) {
688 for (x = 0; x < dw; x += 2) {
691 /* u/v must be calculated using the offset of the even column */
692 gint even_y = (y & ~1);
694 u = s[x * src_stride + even_y * bpp + u_offset];
696 u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
697 v = s[x * src_stride + even_y * bpp + v_offset];
699 v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;
701 d[y * dest_stride + x * bpp + u_offset] = u;
702 d[y * dest_stride + x * bpp + v_offset] = v;
703 d[y * dest_stride + x * bpp + y_offset] =
704 s[x * src_stride + y * bpp + y_offset];
706 d[y * dest_stride + (x + 1) * bpp + y_offset] =
707 s[(x + 1) * src_stride + y * bpp + y_offset];
711 case GST_VIDEO_FLIP_METHOD_OTHER:
712 for (y = 0; y < dh; y++) {
713 for (x = 0; x < dw; x += 2) {
716 /* u/v must be calculated using the offset of the even column */
717 gint even_y = ((sw - 1 - y) & ~1);
719 u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
721 u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
723 v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
725 v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
728 d[y * dest_stride + x * bpp + u_offset] = u;
729 d[y * dest_stride + x * bpp + v_offset] = v;
730 d[y * dest_stride + x * bpp + y_offset] =
731 s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
733 d[y * dest_stride + (x + 1) * bpp + y_offset] =
734 s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
739 case GST_VIDEO_FLIP_METHOD_IDENTITY:
740 g_assert_not_reached ();
743 g_assert_not_reached ();
750 gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
751 GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
753 GstVideoFlip *vf = GST_VIDEO_FLIP (vfilter);
754 gboolean ret = FALSE;
758 if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_INFO_FORMAT (out_info))
761 /* Check that they are correct */
762 switch (vf->method) {
763 case GST_VIDEO_FLIP_METHOD_90R:
764 case GST_VIDEO_FLIP_METHOD_90L:
765 case GST_VIDEO_FLIP_METHOD_TRANS:
766 case GST_VIDEO_FLIP_METHOD_OTHER:
767 if ((in_info->width != out_info->height) ||
768 (in_info->height != out_info->width)) {
769 GST_ERROR_OBJECT (vf, "we are inverting width and height but caps "
770 "are not correct : %dx%d to %dx%d", in_info->width,
771 in_info->height, out_info->width, out_info->height);
775 case GST_VIDEO_FLIP_METHOD_IDENTITY:
778 case GST_VIDEO_FLIP_METHOD_180:
779 case GST_VIDEO_FLIP_METHOD_HORIZ:
780 case GST_VIDEO_FLIP_METHOD_VERT:
781 if ((in_info->width != out_info->width) ||
782 (in_info->height != out_info->height)) {
783 GST_ERROR_OBJECT (vf, "we are keeping width and height but caps "
784 "are not correct : %dx%d to %dx%d", in_info->width,
785 in_info->height, out_info->width, out_info->height);
790 g_assert_not_reached ();
796 switch (GST_VIDEO_INFO_FORMAT (in_info)) {
797 case GST_VIDEO_FORMAT_I420:
798 case GST_VIDEO_FORMAT_YV12:
799 case GST_VIDEO_FORMAT_Y444:
800 vf->process = gst_video_flip_planar_yuv;
802 case GST_VIDEO_FORMAT_YUY2:
803 case GST_VIDEO_FORMAT_UYVY:
804 case GST_VIDEO_FORMAT_YVYU:
805 vf->process = gst_video_flip_y422;
807 case GST_VIDEO_FORMAT_AYUV:
808 case GST_VIDEO_FORMAT_ARGB:
809 case GST_VIDEO_FORMAT_ABGR:
810 case GST_VIDEO_FORMAT_RGBA:
811 case GST_VIDEO_FORMAT_BGRA:
812 case GST_VIDEO_FORMAT_xRGB:
813 case GST_VIDEO_FORMAT_xBGR:
814 case GST_VIDEO_FORMAT_RGBx:
815 case GST_VIDEO_FORMAT_BGRx:
816 case GST_VIDEO_FORMAT_RGB:
817 case GST_VIDEO_FORMAT_BGR:
818 vf->process = gst_video_flip_packed_simple;
825 return ret && (vf->process != NULL);
828 GST_ERROR_OBJECT (vf, "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT,
834 gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
836 GstVideoFlip *videoflip = GST_VIDEO_FLIP (trans);
837 GstClockTime timestamp, stream_time;
839 timestamp = GST_BUFFER_TIMESTAMP (in);
841 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
843 GST_DEBUG_OBJECT (videoflip, "sync to %" GST_TIME_FORMAT,
844 GST_TIME_ARGS (timestamp));
846 if (GST_CLOCK_TIME_IS_VALID (stream_time))
847 gst_object_sync_values (GST_OBJECT (videoflip), stream_time);
851 gst_video_flip_transform_frame (GstVideoFilter * vfilter,
852 GstVideoFrame * in_frame, GstVideoFrame * out_frame)
854 GstVideoFlip *videoflip = GST_VIDEO_FLIP (vfilter);
856 if (G_UNLIKELY (videoflip->process == NULL))
859 GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
860 video_flip_methods[videoflip->method].value_nick);
862 GST_OBJECT_LOCK (videoflip);
863 videoflip->process (videoflip, out_frame, in_frame);
864 GST_OBJECT_UNLOCK (videoflip);
870 GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
871 return GST_FLOW_NOT_NEGOTIATED;
876 gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
878 GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
879 gdouble new_x, new_y, x, y;
880 GstStructure *structure;
882 GstVideoInfo *out_info = &GST_VIDEO_FILTER (trans)->out_info;
884 GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
886 switch (GST_EVENT_TYPE (event)) {
887 case GST_EVENT_NAVIGATION:
889 GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
891 structure = (GstStructure *) gst_event_get_structure (event);
892 if (gst_structure_get_double (structure, "pointer_x", &x) &&
893 gst_structure_get_double (structure, "pointer_y", &y)) {
894 GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
895 switch (vf->method) {
896 case GST_VIDEO_FLIP_METHOD_90R:
898 new_y = out_info->width - x;
900 case GST_VIDEO_FLIP_METHOD_90L:
901 new_x = out_info->height - y;
904 case GST_VIDEO_FLIP_METHOD_OTHER:
905 new_x = out_info->height - y;
906 new_y = out_info->width - x;
908 case GST_VIDEO_FLIP_METHOD_TRANS:
912 case GST_VIDEO_FLIP_METHOD_180:
913 new_x = out_info->width - x;
914 new_y = out_info->height - y;
916 case GST_VIDEO_FLIP_METHOD_HORIZ:
917 new_x = out_info->width - x;
920 case GST_VIDEO_FLIP_METHOD_VERT:
922 new_y = out_info->height - y;
929 GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
930 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
931 "pointer_y", G_TYPE_DOUBLE, new_y, NULL);
938 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
944 gst_video_flip_set_property (GObject * object, guint prop_id,
945 const GValue * value, GParamSpec * pspec)
947 GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
952 GstVideoFlipMethod method;
954 method = g_value_get_enum (value);
955 GST_OBJECT_LOCK (videoflip);
956 if (method != videoflip->method) {
957 GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
959 GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
960 video_flip_methods[videoflip->method].value_nick,
961 video_flip_methods[method].value_nick);
963 videoflip->method = method;
964 GST_OBJECT_UNLOCK (videoflip);
966 gst_base_transform_set_passthrough (btrans,
967 method == GST_VIDEO_FLIP_METHOD_IDENTITY);
968 gst_base_transform_reconfigure (btrans);
970 GST_OBJECT_UNLOCK (videoflip);
975 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
981 gst_video_flip_get_property (GObject * object, guint prop_id, GValue * value,
984 GstVideoFlip *videoflip = GST_VIDEO_FLIP (object);
988 g_value_set_enum (value, videoflip->method);
991 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
997 gst_video_flip_class_init (GstVideoFlipClass * klass)
999 GObjectClass *gobject_class = (GObjectClass *) klass;
1000 GstElementClass *gstelement_class = (GstElementClass *) klass;
1001 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
1002 GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
1004 GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
1006 gobject_class->set_property = gst_video_flip_set_property;
1007 gobject_class->get_property = gst_video_flip_get_property;
1009 g_object_class_install_property (gobject_class, PROP_METHOD,
1010 g_param_spec_enum ("method", "method", "method",
1011 GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
1012 GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1014 gst_element_class_set_details_simple (gstelement_class, "Video flipper",
1015 "Filter/Effect/Video",
1016 "Flips and rotates video", "David Schleef <ds@schleef.org>");
1018 gst_element_class_add_pad_template (gstelement_class,
1019 gst_static_pad_template_get (&gst_video_flip_sink_template));
1020 gst_element_class_add_pad_template (gstelement_class,
1021 gst_static_pad_template_get (&gst_video_flip_src_template));
1023 trans_class->transform_caps =
1024 GST_DEBUG_FUNCPTR (gst_video_flip_transform_caps);
1025 trans_class->before_transform =
1026 GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
1027 trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
1029 vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info);
1030 vfilter_class->transform_frame =
1031 GST_DEBUG_FUNCPTR (gst_video_flip_transform_frame);
1035 gst_video_flip_init (GstVideoFlip * videoflip)
1037 videoflip->method = PROP_METHOD_DEFAULT;
1038 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip), TRUE);