2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David Schleef <ds@schleef.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * This file was (probably) generated from gstvideoflip.c,
23 * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp
30 #include "gstvideoflip.h"
32 #include <gst/video/video.h>
34 /* GstVideoflip signals and args */
42 GST_DEBUG_CATEGORY (videoflip_debug);
43 #define GST_CAT_DEFAULT videoflip_debug
45 static GstElementDetails videoflip_details =
46 GST_ELEMENT_DETAILS ("Video Flipper",
47 "Filter/Effect/Video",
48 "Flips and rotates video",
49 "David Schleef <ds@schleef.org>");
51 static GstStaticPadTemplate gst_videoflip_src_template =
52 GST_STATIC_PAD_TEMPLATE ("src",
55 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
58 static GstStaticPadTemplate gst_videoflip_sink_template =
59 GST_STATIC_PAD_TEMPLATE ("sink",
62 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
65 static GstVideofilterClass *parent_class = NULL;
67 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
70 gst_videoflip_method_get_type (void)
72 static GType videoflip_method_type = 0;
73 static GEnumValue videoflip_methods[] = {
74 {GST_VIDEOFLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
75 {GST_VIDEOFLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
76 {GST_VIDEOFLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
77 {GST_VIDEOFLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
79 {GST_VIDEOFLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
80 {GST_VIDEOFLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
81 {GST_VIDEOFLIP_METHOD_TRANS,
82 "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
83 {GST_VIDEOFLIP_METHOD_OTHER,
84 "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
88 if (!videoflip_method_type) {
89 videoflip_method_type = g_enum_register_static ("GstVideoflipMethod",
92 return videoflip_method_type;
96 gst_videoflip_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
100 GstStructure *in_s, *out_s;
101 gboolean ret = FALSE;
103 vf = GST_VIDEOFLIP (btrans);
105 in_s = gst_caps_get_structure (incaps, 0);
106 out_s = gst_caps_get_structure (outcaps, 0);
108 if (gst_structure_get_int (in_s, "width", &vf->from_width) &&
109 gst_structure_get_int (in_s, "height", &vf->from_height) &&
110 gst_structure_get_int (out_s, "width", &vf->to_width) &&
111 gst_structure_get_int (out_s, "height", &vf->to_height)) {
112 /* Check that they are correct */
113 switch (vf->method) {
114 case GST_VIDEOFLIP_METHOD_90R:
115 case GST_VIDEOFLIP_METHOD_90L:
116 case GST_VIDEOFLIP_METHOD_TRANS:
117 case GST_VIDEOFLIP_METHOD_OTHER:
118 if ((vf->from_width != vf->to_height) ||
119 (vf->from_height != vf->to_width)) {
120 GST_DEBUG_OBJECT (vf, "we are inverting width and height but caps "
121 "are not correct : %dx%d to %dx%d", vf->from_width,
122 vf->from_height, vf->to_width, vf->to_height);
126 case GST_VIDEOFLIP_METHOD_IDENTITY:
129 case GST_VIDEOFLIP_METHOD_180:
130 case GST_VIDEOFLIP_METHOD_HORIZ:
131 case GST_VIDEOFLIP_METHOD_VERT:
132 if ((vf->from_width != vf->to_width) ||
133 (vf->from_height != vf->to_height)) {
134 GST_DEBUG_OBJECT (vf, "we are keeping width and height but caps "
135 "are not correct : %dx%d to %dx%d", vf->from_width,
136 vf->from_height, vf->to_width, vf->to_height);
141 g_assert_not_reached ();
153 gst_videoflip_transform_caps (GstBaseTransform * trans,
154 GstPadDirection direction, GstCaps * caps)
156 GstVideoflip *videoflip;
158 gint width, height, i;
160 videoflip = GST_VIDEOFLIP (trans);
162 ret = gst_caps_copy (caps);
164 for (i = 0; i < gst_caps_get_size (ret); i++) {
165 GstStructure *structure = gst_caps_get_structure (ret, i);
167 if (gst_structure_get_int (structure, "width", &width) &&
168 gst_structure_get_int (structure, "height", &height)) {
170 switch (videoflip->method) {
171 case GST_VIDEOFLIP_METHOD_90R:
172 case GST_VIDEOFLIP_METHOD_90L:
173 case GST_VIDEOFLIP_METHOD_TRANS:
174 case GST_VIDEOFLIP_METHOD_OTHER:
175 gst_structure_set (structure, "width", G_TYPE_INT, height,
176 "height", G_TYPE_INT, width, NULL);
178 case GST_VIDEOFLIP_METHOD_IDENTITY:
179 case GST_VIDEOFLIP_METHOD_180:
180 case GST_VIDEOFLIP_METHOD_HORIZ:
181 case GST_VIDEOFLIP_METHOD_VERT:
182 gst_structure_set (structure, "width", G_TYPE_INT, width,
183 "height", G_TYPE_INT, height, NULL);
186 g_assert_not_reached ();
192 GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
193 GST_PTR_FORMAT, caps, ret);
199 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
200 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
201 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
203 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
204 #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
205 #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
207 #define GST_VIDEO_I420_SIZE(w,h) (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
210 gst_videoflip_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
213 GstVideoflip *videoflip;
214 GstStructure *structure;
215 gboolean ret = FALSE;
218 videoflip = GST_VIDEOFLIP (btrans);
220 structure = gst_caps_get_structure (caps, 0);
222 if (gst_structure_get_int (structure, "width", &width) &&
223 gst_structure_get_int (structure, "height", &height)) {
224 *size = GST_VIDEO_I420_SIZE (width, height);
226 GST_DEBUG_OBJECT (videoflip, "our frame size is %d bytes (%dx%d)", *size,
234 gst_videoflip_flip (GstVideoflip * videoflip, unsigned char *dest,
235 unsigned char *src, int sw, int sh, int dw, int dh)
237 GstFlowReturn ret = GST_FLOW_OK;
240 switch (videoflip->method) {
241 case GST_VIDEOFLIP_METHOD_90R:
242 for (y = 0; y < dh; y++) {
243 for (x = 0; x < dw; x++) {
244 dest[y * dw + x] = src[(sh - 1 - x) * sw + y];
248 case GST_VIDEOFLIP_METHOD_90L:
249 for (y = 0; y < dh; y++) {
250 for (x = 0; x < dw; x++) {
251 dest[y * dw + x] = src[x * sw + (sw - 1 - y)];
255 case GST_VIDEOFLIP_METHOD_180:
256 for (y = 0; y < dh; y++) {
257 for (x = 0; x < dw; x++) {
258 dest[y * dw + x] = src[(sh - 1 - y) * sw + (sw - 1 - x)];
262 case GST_VIDEOFLIP_METHOD_HORIZ:
263 for (y = 0; y < dh; y++) {
264 for (x = 0; x < dw; x++) {
265 dest[y * dw + x] = src[y * sw + (sw - 1 - x)];
269 case GST_VIDEOFLIP_METHOD_VERT:
270 for (y = 0; y < dh; y++) {
271 for (x = 0; x < dw; x++) {
272 dest[y * dw + x] = src[(sh - 1 - y) * sw + x];
276 case GST_VIDEOFLIP_METHOD_TRANS:
277 for (y = 0; y < dh; y++) {
278 for (x = 0; x < dw; x++) {
279 dest[y * dw + x] = src[x * sw + y];
283 case GST_VIDEOFLIP_METHOD_OTHER:
284 for (y = 0; y < dh; y++) {
285 for (x = 0; x < dw; x++) {
286 dest[y * dw + x] = src[(sh - 1 - x) * sw + (sw - 1 - y)];
291 ret = GST_FLOW_ERROR;
299 gst_videoflip_transform (GstBaseTransform * trans, GstBuffer * in,
302 GstVideoflip *videoflip;
305 GstFlowReturn ret = GST_FLOW_OK;
307 videoflip = GST_VIDEOFLIP (trans);
309 gst_buffer_stamp (out, in);
311 src = GST_BUFFER_DATA (in);
312 dest = GST_BUFFER_DATA (out);
313 sw = videoflip->from_width;
314 sh = videoflip->from_height;
315 dw = videoflip->to_width;
316 dh = videoflip->to_height;
318 GST_LOG_OBJECT (videoflip, "videoflip: scaling planar 4:1:1 %dx%d to %dx%d",
321 ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
322 if (ret != GST_FLOW_OK)
333 ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
334 if (ret != GST_FLOW_OK)
340 ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
347 gst_videoflip_handle_src_event (GstPad * pad, GstEvent * event)
352 GstStructure *structure;
354 vf = GST_VIDEOFLIP (gst_pad_get_parent (pad));
356 GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
358 switch (GST_EVENT_TYPE (event)) {
359 case GST_EVENT_NAVIGATION:
361 GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
363 structure = (GstStructure *) gst_event_get_structure (event);
364 if (gst_structure_get_double (structure, "pointer_x", &x) &&
365 gst_structure_get_double (structure, "pointer_y", &y)) {
366 switch (vf->method) {
367 case GST_VIDEOFLIP_METHOD_90R:
368 case GST_VIDEOFLIP_METHOD_OTHER:
370 y = vf->to_width - x;
372 case GST_VIDEOFLIP_METHOD_90L:
373 case GST_VIDEOFLIP_METHOD_TRANS:
374 x = vf->to_height - y;
377 case GST_VIDEOFLIP_METHOD_180:
378 x = vf->to_width - x;
379 y = vf->to_height - y;
381 case GST_VIDEOFLIP_METHOD_HORIZ:
382 x = vf->to_width - x;
385 case GST_VIDEOFLIP_METHOD_VERT:
387 y = vf->to_height - y;
394 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x,
395 "pointer_y", G_TYPE_DOUBLE, y, NULL);
402 ret = gst_pad_event_default (pad, event);
404 gst_object_unref (vf);
410 gst_videoflip_set_property (GObject * object, guint prop_id,
411 const GValue * value, GParamSpec * pspec)
413 GstVideoflip *videoflip;
414 GstVideofilter *videofilter;
416 g_return_if_fail (GST_IS_VIDEOFLIP (object));
417 videoflip = GST_VIDEOFLIP (object);
418 videofilter = GST_VIDEOFILTER (object);
423 GstVideoflipMethod method;
425 method = g_value_get_enum (value);
426 if (method != videoflip->method) {
427 GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
429 g_mutex_lock (btrans->transform_lock);
430 gst_pad_set_caps (btrans->sinkpad, NULL);
431 gst_pad_set_caps (btrans->srcpad, NULL);
432 g_mutex_unlock (btrans->transform_lock);
433 videoflip->method = method;
438 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444 gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
447 GstVideoflip *videoflip;
449 g_return_if_fail (GST_IS_VIDEOFLIP (object));
450 videoflip = GST_VIDEOFLIP (object);
454 g_value_set_enum (value, videoflip->method);
457 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
463 gst_videoflip_base_init (gpointer g_class)
465 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
467 gst_element_class_set_details (element_class, &videoflip_details);
469 gst_element_class_add_pad_template (element_class,
470 gst_static_pad_template_get (&gst_videoflip_sink_template));
471 gst_element_class_add_pad_template (element_class,
472 gst_static_pad_template_get (&gst_videoflip_src_template));
476 gst_videoflip_class_init (gpointer klass, gpointer class_data)
478 GObjectClass *gobject_class;
479 GstBaseTransformClass *trans_class;
481 gobject_class = (GObjectClass *) klass;
482 trans_class = (GstBaseTransformClass *) klass;
484 parent_class = g_type_class_peek_parent (klass);
486 gobject_class->set_property = gst_videoflip_set_property;
487 gobject_class->get_property = gst_videoflip_get_property;
489 g_object_class_install_property (gobject_class, ARG_METHOD,
490 g_param_spec_enum ("method", "method", "method",
491 GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
494 trans_class->transform_caps =
495 GST_DEBUG_FUNCPTR (gst_videoflip_transform_caps);
496 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_videoflip_set_caps);
497 trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_videoflip_get_unit_size);
498 trans_class->transform = GST_DEBUG_FUNCPTR (gst_videoflip_transform);
502 gst_videoflip_init (GTypeInstance * instance, gpointer g_class)
504 GstVideoflip *videoflip = GST_VIDEOFLIP (instance);
505 GstBaseTransform *btrans = GST_BASE_TRANSFORM (instance);
507 GST_DEBUG_OBJECT (videoflip, "gst_videoflip_init");
509 videoflip->method = GST_VIDEOFLIP_METHOD_90R;
511 gst_pad_set_event_function (btrans->srcpad,
512 GST_DEBUG_FUNCPTR (gst_videoflip_handle_src_event));
516 plugin_init (GstPlugin * plugin)
518 GST_DEBUG_CATEGORY_INIT (videoflip_debug, "videoflip", 0, "videoflip");
520 return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
525 gst_videoflip_get_type (void)
527 static GType videoflip_type = 0;
529 if (!videoflip_type) {
530 static const GTypeInfo videoflip_info = {
531 sizeof (GstVideoflipClass),
532 gst_videoflip_base_init,
534 gst_videoflip_class_init,
537 sizeof (GstVideoflip),
542 videoflip_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
543 "GstVideoflip", &videoflip_info, 0);
545 return videoflip_type;
548 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
551 "Flips and rotates video",
552 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);