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 /*#define DEBUG_ENABLED */
26 #include <gstvideoflip.h>
34 /* elementfactory information */
35 static GstElementDetails videoflip_details = {
39 "Flips and rotates video",
41 "David Schleef <ds@schleef.org>",
45 /* GstVideoflip signals and args */
57 static void gst_videoflip_class_init (GstVideoflipClass *klass);
58 static void gst_videoflip_init (GstVideoflip *videoflip);
60 static void gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
61 static void gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
63 static void gst_videoflip_planar411(GstVideofilter *videofilter, void *dest, void *src);
64 static void gst_videoflip_setup(GstVideofilter *videofilter);
66 static GstVideoflipClass *this_class = NULL;
67 static GstVideofilterClass *parent_class = NULL;
68 static GstElementClass *element_class = NULL;
70 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
73 gst_videoflip_method_get_type(void)
75 static GType videoflip_method_type = 0;
76 static GEnumValue videoflip_methods[] = {
77 { GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)" },
78 { GST_VIDEOFLIP_METHOD_90R, "1", "Rotate clockwise 90 degrees" },
79 { GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees" },
80 { GST_VIDEOFLIP_METHOD_90L, "3", "Rotate counter-clockwise 90 degrees" },
81 { GST_VIDEOFLIP_METHOD_HORIZ, "4", "Flip horizontally" },
82 { GST_VIDEOFLIP_METHOD_VERT, "5", "Flip vertically" },
83 { GST_VIDEOFLIP_METHOD_TRANS, "6", "Flip across upper left/lower right diagonal" },
84 { GST_VIDEOFLIP_METHOD_OTHER, "7", "Flip across upper right/lower left diagonal" },
87 if(!videoflip_method_type){
88 videoflip_method_type = g_enum_register_static("GstVideoflipMethod",
91 return videoflip_method_type;
95 gst_videoflip_get_type (void)
97 static GType videoflip_type = 0;
99 if (!videoflip_type) {
100 static const GTypeInfo videoflip_info = {
101 sizeof(GstVideoflipClass), NULL,
103 (GClassInitFunc)gst_videoflip_class_init,
106 sizeof(GstVideoflip),
108 (GInstanceInitFunc)gst_videoflip_init,
110 videoflip_type = g_type_register_static(GST_TYPE_VIDEOFILTER, "GstVideoflip", &videoflip_info, 0);
112 return videoflip_type;
115 static GstVideofilterFormat gst_videoflip_formats[] = {
117 { "YV12", 12, gst_videoflip_planar411, },
118 { "I420", 12, gst_videoflip_planar411, },
119 { "IYUV", 12, gst_videoflip_planar411, },
123 gst_videoflip_class_init (GstVideoflipClass *klass)
125 GObjectClass *gobject_class;
126 GstElementClass *gstelement_class;
127 GstVideofilterClass *gstvideofilter_class;
130 gobject_class = (GObjectClass*)klass;
131 gstelement_class = (GstElementClass*)klass;
132 gstvideofilter_class = (GstVideofilterClass *)klass;
134 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_METHOD,
135 g_param_spec_enum("method","method","method",
136 GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
140 parent_class = g_type_class_ref(GST_TYPE_VIDEOFILTER);
141 element_class = g_type_class_ref(GST_TYPE_ELEMENT);
143 gobject_class->set_property = gst_videoflip_set_property;
144 gobject_class->get_property = gst_videoflip_get_property;
146 gstvideofilter_class->setup = gst_videoflip_setup;
148 for(i=0;i<G_N_ELEMENTS(gst_videoflip_formats);i++){
149 gst_videofilter_class_add_format(gstvideofilter_class,
150 gst_videoflip_formats + i);
154 static GstCaps *gst_videoflip_get_capslist(void)
156 GstVideofilterClass *klass;
158 klass = g_type_class_ref(GST_TYPE_VIDEOFILTER);
160 return gst_videofilter_class_get_capslist(klass);
163 static GstPadTemplate *
164 gst_videoflip_src_template_factory(void)
166 static GstPadTemplate *templ = NULL;
169 GstCaps *caps = GST_CAPS_NEW("src","video/x-raw-yuv",
170 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
171 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
172 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
174 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
176 templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
181 static GstPadTemplate *
182 gst_videoflip_sink_template_factory(void)
184 static GstPadTemplate *templ = NULL;
187 GstCaps *caps = GST_CAPS_NEW("sink","video/x-raw-yuv",
188 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
189 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
190 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
192 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
194 templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
200 gst_videoflip_init (GstVideoflip *videoflip)
202 GstVideofilter *videofilter;
204 GST_DEBUG ("gst_videoflip_init");
206 videofilter = GST_VIDEOFILTER(videoflip);
208 videofilter->sinkpad = gst_pad_new_from_template (
209 GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory),
212 videofilter->srcpad = gst_pad_new_from_template (
213 GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory),
216 gst_videofilter_postinit(GST_VIDEOFILTER(videoflip));
220 gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
222 GstVideoflip *videoflip;
224 /* it's not null if we got it, but it might not be ours */
225 g_return_if_fail(GST_IS_VIDEOFLIP(object));
226 videoflip = GST_VIDEOFLIP(object);
228 GST_DEBUG ("gst_videoflip_set_property");
231 videoflip->method = g_value_get_enum (value);
232 /* FIXME is this ok? (threading issues) */
233 gst_videoflip_setup(GST_VIDEOFILTER(videoflip));
241 gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
243 GstVideoflip *videoflip;
245 /* it's not null if we got it, but it might not be ours */
246 g_return_if_fail(GST_IS_VIDEOFLIP(object));
247 videoflip = GST_VIDEOFLIP(object);
251 g_value_set_enum (value, videoflip->method);
254 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259 static gboolean plugin_init (GModule *module, GstPlugin *plugin)
261 GstElementFactory *factory;
263 if(!gst_library_load("gstvideofilter"))
266 /* create an elementfactory for the videoflip element */
267 factory = gst_element_factory_new("videoflip",GST_TYPE_VIDEOFLIP,
269 g_return_val_if_fail(factory != NULL, FALSE);
271 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory));
272 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory));
274 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
279 GstPluginDesc plugin_desc = {
287 static void gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
288 unsigned char *src, int sw, int sh, int dw, int dh);
291 static void gst_videoflip_setup (GstVideofilter *videofilter)
293 int from_width, from_height;
294 GstVideoflip *videoflip;
296 GST_DEBUG("gst_videoflip_setup");
298 videoflip = GST_VIDEOFLIP(videofilter);
300 from_width = gst_videofilter_get_input_width(videofilter);
301 from_height = gst_videofilter_get_input_height(videofilter);
303 if(from_width==0 || from_height==0){
307 switch(videoflip->method){
308 case GST_VIDEOFLIP_METHOD_90R:
309 case GST_VIDEOFLIP_METHOD_90L:
310 case GST_VIDEOFLIP_METHOD_TRANS:
311 case GST_VIDEOFLIP_METHOD_OTHER:
312 gst_videofilter_set_output_size(videofilter, from_height, from_width);
314 case GST_VIDEOFLIP_METHOD_IDENTITY:
315 case GST_VIDEOFLIP_METHOD_180:
316 case GST_VIDEOFLIP_METHOD_HORIZ:
317 case GST_VIDEOFLIP_METHOD_VERT:
318 gst_videofilter_set_output_size(videofilter, from_width, from_height);
321 g_assert_not_reached();
325 GST_DEBUG ("format=%p \"%s\" from %dx%d to %dx%d",
326 videofilter->format, videofilter->format->fourcc,
327 from_width, from_height,
328 videofilter->to_width, videofilter->to_height);
330 if(videoflip->method == GST_VIDEOFLIP_METHOD_IDENTITY){
331 GST_DEBUG ("videoflip: using passthru");
332 videofilter->passthru = TRUE;
334 videofilter->passthru = FALSE;
337 videofilter->from_buf_size = (videofilter->from_width * videofilter->from_height
338 * videofilter->format->depth) / 8;
339 videofilter->to_buf_size = (videofilter->to_width * videofilter->to_height
340 * videofilter->format->depth) / 8;
342 videofilter->inited = TRUE;
345 static void gst_videoflip_planar411(GstVideofilter *videofilter,
346 void *dest, void *src)
348 GstVideoflip *videoflip;
354 g_return_if_fail(GST_IS_VIDEOFLIP(videofilter));
355 videoflip = GST_VIDEOFLIP(videofilter);
357 sw = videofilter->from_width;
358 sh = videofilter->from_height;
359 dw = videofilter->to_width;
360 dh = videofilter->to_height;
362 GST_DEBUG ("videoflip: scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
364 gst_videoflip_flip(videoflip, dest, src, sw, sh, dw, dh);
374 gst_videoflip_flip(videoflip, dest, src, sw, sh, dw, dh);
379 gst_videoflip_flip(videoflip, dest, src, sw, sh, dw, dh);
383 gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
384 unsigned char *src, int sw, int sh, int dw, int dh)
388 switch(videoflip->method){
389 case GST_VIDEOFLIP_METHOD_90R:
392 dest[y*dw + x] = src[(sh - 1 - x)*sw + y];
396 case GST_VIDEOFLIP_METHOD_90L:
399 dest[y*dw + x] = src[x*sw + (sw - 1 - y)];
403 case GST_VIDEOFLIP_METHOD_180:
406 dest[y*dw + x] = src[(sh - 1 - y)*sw + (sw - 1 - x)];
410 case GST_VIDEOFLIP_METHOD_HORIZ:
413 dest[y*dw + x] = src[y*sw + (sw - 1 - x)];
417 case GST_VIDEOFLIP_METHOD_VERT:
420 dest[y*dw + x] = src[(sh - 1 - y)*sw + x];
424 case GST_VIDEOFLIP_METHOD_TRANS:
427 dest[y*dw + x] = src[x*sw + y];
431 case GST_VIDEOFLIP_METHOD_OTHER:
434 dest[y*dw + x] = src[(sh - 1 - x)*sw + (sw - 1 - y)];