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);
60 static GstElementClass *parent_class = NULL;
62 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
65 gst_videoflip_method_get_type(void)
67 static GType videoflip_method_type = 0;
68 static GEnumValue videoflip_methods[] = {
69 { GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)" },
70 { GST_VIDEOFLIP_METHOD_90R, "1", "Rotate right 90 degrees" },
71 { GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees" },
72 { GST_VIDEOFLIP_METHOD_90L, "3", "Rotate left 90 degrees" },
73 { GST_VIDEOFLIP_METHOD_HORIZ, "4", "Flip horizontally" },
74 { GST_VIDEOFLIP_METHOD_VERT, "5", "Flip vertically" },
75 { GST_VIDEOFLIP_METHOD_TRANS, "6", "Flip across upper left/lower right diagonal" },
76 { GST_VIDEOFLIP_METHOD_OTHER, "7", "Flip across upper right/lower left diagonal" },
79 if(!videoflip_method_type){
80 videoflip_method_type = g_enum_register_static("GstVideoflipMethod",
83 return videoflip_method_type;
86 static GstPadTemplate *
87 gst_videoflip_src_template_factory(void)
89 static GstPadTemplate *templ = NULL;
92 /* well, actually RGB too, but since there's no RGB format anyway */
93 GstCaps *caps = GST_CAPS_NEW("src","video/x-raw-yuv",
94 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
95 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
96 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
98 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
100 templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
105 static GstPadTemplate *
106 gst_videoflip_sink_template_factory(void)
108 static GstPadTemplate *templ = NULL;
111 GstCaps *caps = GST_CAPS_NEW("sink","video/x-raw-yuv",
112 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
113 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
114 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
116 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
118 templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
124 gst_videoflip_get_type (void)
126 static GType videoflip_type = 0;
128 if (!videoflip_type) {
129 static const GTypeInfo videoflip_info = {
130 sizeof(GstVideoflipClass),
131 gst_videoflip_base_init,
133 (GClassInitFunc)gst_videoflip_class_init,
136 sizeof(GstVideoflip),
138 (GInstanceInitFunc)gst_videoflip_init,
140 videoflip_type = g_type_register_static(GST_TYPE_ELEMENT, "GstVideoflip", &videoflip_info, 0);
142 return videoflip_type;
146 gst_videoflip_base_init (gpointer g_class)
148 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
150 gst_element_class_set_details (element_class, &videoflip_details);
152 gst_element_class_add_pad_template (element_class, GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory));
153 gst_element_class_add_pad_template (element_class, GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory));
156 gst_videoflip_class_init (GstVideoflipClass *klass)
158 GObjectClass *gobject_class;
159 GstElementClass *gstelement_class;
161 gobject_class = (GObjectClass*)klass;
162 gstelement_class = (GstElementClass*)klass;
164 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_METHOD,
165 g_param_spec_enum("method","method","method",
166 GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
169 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
171 gobject_class->set_property = gst_videoflip_set_property;
172 gobject_class->get_property = gst_videoflip_get_property;
177 gst_videoflip_get_capslist(void)
179 static GstCaps *capslist = NULL;
184 gst_caps_ref(capslist);
188 for(i=0;i<videoflip_n_formats;i++){
189 caps = videoflip_get_caps(videoflip_formats + i);
190 capslist = gst_caps_append(capslist, caps);
193 gst_caps_ref(capslist);
198 gst_videoflip_sink_getcaps (GstPad *pad, GstCaps *caps)
200 GstVideoflip *videoflip;
201 GstCaps *capslist = NULL;
206 GST_DEBUG ("gst_videoflip_src_link");
207 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
209 /* get list of peer's caps */
210 if(pad == videoflip->srcpad){
211 peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
213 peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
216 /* FIXME videoflip doesn't allow passthru of video formats it
217 * doesn't understand. */
218 /* Look through our list of caps and find those that match with
219 * the peer's formats. Create a list of them. */
220 for(i=0;i<videoflip_n_formats;i++){
221 GstCaps *fromcaps = videoflip_get_caps(videoflip_formats + i);
222 if(gst_caps_is_always_compatible(fromcaps, peercaps)){
223 capslist = gst_caps_append(capslist, fromcaps);
225 gst_caps_unref (fromcaps);
227 gst_caps_unref (peercaps);
229 sizecaps = GST_CAPS_NEW("videoflip_size","video/x-raw-yuv",
230 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
231 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
232 "framerate", GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
234 caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
235 gst_caps_unref (sizecaps);
241 static GstPadLinkReturn
242 gst_videoflip_src_link (GstPad *pad, GstCaps *caps)
244 GstVideoflip *videoflip;
245 GstPadLinkReturn ret;
248 GST_DEBUG ("gst_videoflip_src_link");
249 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
251 if (!GST_CAPS_IS_FIXED (caps)) {
252 return GST_PAD_LINK_DELAYED;
255 gst_caps_debug(caps,"ack");
257 videoflip->format = videoflip_find_by_caps (caps);
258 g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
260 gst_caps_get_int (caps, "width", &videoflip->to_width);
261 gst_caps_get_int (caps, "height", &videoflip->to_height);
263 GST_DEBUG ("width %d height %d",videoflip->to_width,videoflip->to_height);
265 peercaps = gst_caps_copy(caps);
267 gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT));
268 gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
270 ret = gst_pad_try_set_caps (videoflip->srcpad, peercaps);
272 gst_caps_unref(peercaps);
274 if(ret==GST_PAD_LINK_OK){
275 caps = gst_pad_get_caps (videoflip->srcpad);
277 gst_caps_get_int (caps, "width", &videoflip->from_width);
278 gst_caps_get_int (caps, "height", &videoflip->from_height);
279 gst_videoflip_setup(videoflip);
285 static GstPadLinkReturn
286 gst_videoflip_sink_link (GstPad *pad, GstCaps *caps)
288 GstVideoflip *videoflip;
289 GstPadLinkReturn ret;
292 GST_DEBUG ("gst_videoflip_src_link");
293 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
295 if (!GST_CAPS_IS_FIXED (caps)) {
296 return GST_PAD_LINK_DELAYED;
299 videoflip->format = videoflip_find_by_caps (caps);
300 gst_caps_debug(caps,"ack");
301 g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
303 gst_caps_get_int (caps, "width", &videoflip->from_width);
304 gst_caps_get_int (caps, "height", &videoflip->from_height);
306 gst_videoflip_setup(videoflip);
308 peercaps = gst_caps_copy(caps);
310 gst_caps_set(peercaps, "width", GST_PROPS_INT (videoflip->to_width));
311 gst_caps_set(peercaps, "height", GST_PROPS_INT (videoflip->to_height));
313 ret = gst_pad_try_set_caps (videoflip->srcpad, peercaps);
315 gst_caps_unref(peercaps);
317 if(ret==GST_PAD_LINK_OK){
318 caps = gst_pad_get_caps (videoflip->srcpad);
320 gst_caps_get_int (caps, "width", &videoflip->to_width);
321 gst_caps_get_int (caps, "height", &videoflip->to_height);
322 gst_videoflip_setup(videoflip);
329 gst_videoflip_init (GstVideoflip *videoflip)
331 GST_DEBUG ("gst_videoflip_init");
332 videoflip->sinkpad = gst_pad_new_from_template (
333 GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory),
335 gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->sinkpad);
336 gst_pad_set_chain_function(videoflip->sinkpad,gst_videoflip_chain);
337 gst_pad_set_link_function(videoflip->sinkpad,gst_videoflip_sink_link);
338 gst_pad_set_getcaps_function(videoflip->sinkpad,gst_videoflip_sink_getcaps);
340 videoflip->srcpad = gst_pad_new_from_template (
341 GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory),
343 gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->srcpad);
344 gst_pad_set_link_function(videoflip->srcpad,gst_videoflip_src_link);
345 //gst_pad_set_getcaps_function(videoflip->srcpad,gst_videoflip_getcaps);
347 videoflip->inited = FALSE;
348 videoflip->force_size = FALSE;
353 gst_videoflip_chain (GstPad *pad, GstData *_data)
355 GstBuffer *buf = GST_BUFFER (_data);
356 GstVideoflip *videoflip;
361 GST_DEBUG ("gst_videoflip_chain");
363 g_return_if_fail (pad != NULL);
364 g_return_if_fail (GST_IS_PAD (pad));
365 g_return_if_fail (buf != NULL);
367 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
368 g_return_if_fail (videoflip->inited);
370 data = GST_BUFFER_DATA(buf);
371 size = GST_BUFFER_SIZE(buf);
373 if(videoflip->passthru){
374 gst_pad_push(videoflip->srcpad, GST_DATA (buf));
378 GST_DEBUG ("gst_videoflip_chain: got buffer of %ld bytes in '%s'",size,
379 GST_OBJECT_NAME (videoflip));
381 GST_DEBUG ("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
383 videoflip->from_width, videoflip->from_height,
384 videoflip->to_width, videoflip->to_height,
385 size, videoflip->from_buf_size,
386 videoflip->to_buf_size);
388 g_return_if_fail (size == videoflip->from_buf_size);
390 outbuf = gst_buffer_new();
391 /* FIXME: handle bufferpools */
392 GST_BUFFER_SIZE(outbuf) = videoflip->to_buf_size;
393 GST_BUFFER_DATA(outbuf) = g_malloc (videoflip->to_buf_size);
394 GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
396 g_return_if_fail(videoflip->format);
397 GST_DEBUG ("format %s",videoflip->format->fourcc);
398 g_return_if_fail(videoflip->format->scale);
400 videoflip->format->scale(videoflip, GST_BUFFER_DATA(outbuf), data);
402 GST_DEBUG ("gst_videoflip_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
403 GST_OBJECT_NAME (videoflip));
405 gst_pad_push(videoflip->srcpad, GST_DATA (outbuf));
407 gst_buffer_unref(buf);
411 gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
415 /* it's not null if we got it, but it might not be ours */
416 g_return_if_fail(GST_IS_VIDEOFLIP(object));
417 src = GST_VIDEOFLIP(object);
419 GST_DEBUG ("gst_videoflip_set_property");
422 src->method = g_value_get_enum (value);
430 gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
434 /* it's not null if we got it, but it might not be ours */
435 g_return_if_fail(GST_IS_VIDEOFLIP(object));
436 src = GST_VIDEOFLIP(object);
440 g_value_set_enum (value, src->method);
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
450 plugin_init (GstPlugin *plugin)
452 return gst_element_register (plugin, "videoflip", GST_RANK_NONE, GST_TYPE_VIDEOFLIP);