2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 /*#define DEBUG_ENABLED */
25 #include <gstvideoflip.h>
26 #include <videoflip.h>
30 /* elementfactory information */
31 static GstElementDetails videoflip_details = GST_ELEMENT_DETAILS (
33 "Filter/Effect/Video",
35 "Wim Taymans <wim.taymans@chello.be>"
38 /* GstVideoflip signals and args */
50 static void gst_videoflip_base_init (gpointer g_class);
51 static void gst_videoflip_class_init (GstVideoflipClass *klass);
52 static void gst_videoflip_init (GstVideoflip *videoflip);
54 static void gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
55 static void gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
57 static void gst_videoflip_chain (GstPad *pad, GstData *_data);
58 static GstCaps * gst_videoflip_get_capslist(void);
61 static GstElementClass *parent_class = NULL;
63 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
66 gst_videoflip_method_get_type(void)
68 static GType videoflip_method_type = 0;
69 static GEnumValue videoflip_methods[] = {
70 { GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)" },
71 { GST_VIDEOFLIP_METHOD_90R, "1", "Rotate right 90 degrees" },
72 { GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees" },
73 { GST_VIDEOFLIP_METHOD_90L, "3", "Rotate left 90 degrees" },
74 { GST_VIDEOFLIP_METHOD_HORIZ, "4", "Flip horizontally" },
75 { GST_VIDEOFLIP_METHOD_VERT, "5", "Flip vertically" },
76 { GST_VIDEOFLIP_METHOD_TRANS, "6", "Flip across upper left/lower right diagonal" },
77 { GST_VIDEOFLIP_METHOD_OTHER, "7", "Flip across upper right/lower left diagonal" },
80 if(!videoflip_method_type){
81 videoflip_method_type = g_enum_register_static("GstVideoflipMethod",
84 return videoflip_method_type;
87 static GstPadTemplate *
88 gst_videoflip_src_template_factory(void)
90 /* well, actually RGB too, but since there's no RGB format anyway */
91 GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
92 "width = (int) [ 0, MAX ], "
93 "height = (int) [ 0, MAX ], "
94 "framerate = (double) [ 0, MAX ]");
96 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
98 return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
101 static GstPadTemplate *
102 gst_videoflip_sink_template_factory(void)
104 GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
105 "width = (int) [ 0, MAX ], "
106 "height = (int) [ 0, MAX ], "
107 "framerate = (double) [ 0, MAX ]");
109 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
111 return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
115 gst_videoflip_get_type (void)
117 static GType videoflip_type = 0;
119 if (!videoflip_type) {
120 static const GTypeInfo videoflip_info = {
121 sizeof(GstVideoflipClass),
122 gst_videoflip_base_init,
124 (GClassInitFunc)gst_videoflip_class_init,
127 sizeof(GstVideoflip),
129 (GInstanceInitFunc)gst_videoflip_init,
131 videoflip_type = g_type_register_static(GST_TYPE_ELEMENT, "GstVideoflip", &videoflip_info, 0);
133 return videoflip_type;
137 gst_videoflip_base_init (gpointer g_class)
139 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
141 gst_element_class_set_details (element_class, &videoflip_details);
143 gst_element_class_add_pad_template (element_class,
144 gst_videoflip_sink_template_factory ());
145 gst_element_class_add_pad_template (element_class,
146 gst_videoflip_src_template_factory ());
149 gst_videoflip_class_init (GstVideoflipClass *klass)
151 GObjectClass *gobject_class;
152 GstElementClass *gstelement_class;
154 gobject_class = (GObjectClass*)klass;
155 gstelement_class = (GstElementClass*)klass;
157 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_METHOD,
158 g_param_spec_enum("method","method","method",
159 GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
162 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
164 gobject_class->set_property = gst_videoflip_set_property;
165 gobject_class->get_property = gst_videoflip_get_property;
170 gst_videoflip_get_capslist(void)
173 GstStructure *structure;
176 caps = gst_caps_new_empty ();
177 for(i=0;i<videoflip_n_formats;i++){
178 structure = videoflip_get_cap (videoflip_formats + i);
179 gst_caps_append_structure (caps, structure);
186 gst_videoflip_sink_getcaps (GstPad *pad)
188 GstVideoflip *videoflip;
189 GstCaps *capslist = NULL;
195 GST_DEBUG ("gst_videoflip_sink_getcaps");
196 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
198 /* get list of peer's caps */
199 if(pad == videoflip->srcpad){
200 peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
202 peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
205 /* FIXME videoflip doesn't allow passthru of video formats it
206 * doesn't understand. */
207 /* Look through our list of caps and find those that match with
208 * the peer's formats. Create a list of them. */
209 for(i=0;i<videoflip_n_formats;i++){
210 GstCaps *fromcaps = gst_caps_new_full(videoflip_get_cap(
211 videoflip_formats + i), NULL);
212 if(gst_caps_is_always_compatible(fromcaps, peercaps)){
213 gst_caps_append(capslist, fromcaps);
216 gst_caps_free (peercaps);
218 sizecaps = gst_caps_from_string ("video/x-raw-yuv, "
219 "width = (int) [ 0, MAX ], "
220 "height = (int) [ 0, MAX ], "
221 "framerate = (double) [ 0, MAX ]");
223 caps = gst_caps_intersect(capslist, sizecaps);
224 gst_caps_free (sizecaps);
230 static GstPadLinkReturn
231 gst_videoflip_src_link (GstPad *pad, const GstCaps *caps)
233 GstVideoflip *videoflip;
234 GstStructure *structure;
237 GST_DEBUG ("gst_videoflip_src_link");
238 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
240 structure = gst_caps_get_structure (caps, 0);
242 videoflip->format = videoflip_find_by_caps (caps);
243 g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
245 ret = gst_structure_get_int (structure, "width", &videoflip->to_width);
246 ret &= gst_structure_get_int (structure, "height", &videoflip->to_height);
248 if (!ret) return GST_PAD_LINK_REFUSED;
250 return GST_PAD_LINK_OK;
253 static GstPadLinkReturn
254 gst_videoflip_sink_link (GstPad *pad, const GstCaps *caps)
256 GstVideoflip *videoflip;
257 GstStructure *structure;
260 GST_DEBUG ("gst_videoflip_sink_link");
261 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
263 structure = gst_caps_get_structure (caps, 0);
265 videoflip->format = videoflip_find_by_caps (caps);
266 g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
268 ret = gst_structure_get_int (structure, "width", &videoflip->from_width);
269 ret &= gst_structure_get_int (structure, "height", &videoflip->from_height);
271 if (!ret) return GST_PAD_LINK_REFUSED;
273 return GST_PAD_LINK_OK;
277 gst_videoflip_init (GstVideoflip *videoflip)
279 GST_DEBUG ("gst_videoflip_init");
280 videoflip->sinkpad = gst_pad_new_from_template (
281 gst_videoflip_sink_template_factory(),
283 gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->sinkpad);
284 gst_pad_set_chain_function(videoflip->sinkpad,gst_videoflip_chain);
285 gst_pad_set_link_function(videoflip->sinkpad,gst_videoflip_sink_link);
286 gst_pad_set_getcaps_function(videoflip->sinkpad,gst_videoflip_sink_getcaps);
288 videoflip->srcpad = gst_pad_new_from_template (
289 gst_videoflip_src_template_factory(),
291 gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->srcpad);
292 gst_pad_set_link_function(videoflip->srcpad,gst_videoflip_src_link);
293 //gst_pad_set_getcaps_function(videoflip->srcpad,gst_videoflip_getcaps);
295 videoflip->inited = FALSE;
296 videoflip->force_size = FALSE;
301 gst_videoflip_chain (GstPad *pad, GstData *_data)
303 GstBuffer *buf = GST_BUFFER (_data);
304 GstVideoflip *videoflip;
309 GST_DEBUG ("gst_videoflip_chain");
311 g_return_if_fail (pad != NULL);
312 g_return_if_fail (GST_IS_PAD (pad));
313 g_return_if_fail (buf != NULL);
315 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
316 g_return_if_fail (videoflip->inited);
318 data = GST_BUFFER_DATA(buf);
319 size = GST_BUFFER_SIZE(buf);
321 if(videoflip->passthru){
322 gst_pad_push(videoflip->srcpad, GST_DATA (buf));
326 GST_DEBUG ("gst_videoflip_chain: got buffer of %ld bytes in '%s'",size,
327 GST_OBJECT_NAME (videoflip));
329 GST_DEBUG ("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
331 videoflip->from_width, videoflip->from_height,
332 videoflip->to_width, videoflip->to_height,
333 size, videoflip->from_buf_size,
334 videoflip->to_buf_size);
336 g_return_if_fail (size == videoflip->from_buf_size);
338 outbuf = gst_buffer_new();
339 /* FIXME: handle bufferpools */
340 GST_BUFFER_SIZE(outbuf) = videoflip->to_buf_size;
341 GST_BUFFER_DATA(outbuf) = g_malloc (videoflip->to_buf_size);
342 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
344 g_return_if_fail(videoflip->format);
345 GST_DEBUG ("format %s",videoflip->format->fourcc);
346 g_return_if_fail(videoflip->format->scale);
348 videoflip->format->scale(videoflip, GST_BUFFER_DATA(outbuf), data);
350 GST_DEBUG ("gst_videoflip_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
351 GST_OBJECT_NAME (videoflip));
353 gst_pad_push(videoflip->srcpad, GST_DATA (outbuf));
355 gst_buffer_unref(buf);
359 gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
363 /* it's not null if we got it, but it might not be ours */
364 g_return_if_fail(GST_IS_VIDEOFLIP(object));
365 src = GST_VIDEOFLIP(object);
367 GST_DEBUG ("gst_videoflip_set_property");
370 src->method = g_value_get_enum (value);
378 gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
382 /* it's not null if we got it, but it might not be ours */
383 g_return_if_fail(GST_IS_VIDEOFLIP(object));
384 src = GST_VIDEOFLIP(object);
388 g_value_set_enum (value, src->method);
391 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
398 plugin_init (GstPlugin *plugin)
400 return gst_element_register (plugin, "videoflip", GST_RANK_NONE, GST_TYPE_VIDEOFLIP);