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 =
32 GST_ELEMENT_DETAILS ("Video scaler",
33 "Filter/Effect/Video",
35 "Wim Taymans <wim.taymans@chello.be>");
37 /* GstVideoflip signals and args */
51 static void gst_videoflip_base_init (gpointer g_class);
52 static void gst_videoflip_class_init (GstVideoflipClass * klass);
53 static void gst_videoflip_init (GstVideoflip * videoflip);
55 static void gst_videoflip_set_property (GObject * object, guint prop_id,
56 const GValue * value, GParamSpec * pspec);
57 static void gst_videoflip_get_property (GObject * object, guint prop_id,
58 GValue * value, GParamSpec * pspec);
60 static void gst_videoflip_chain (GstPad * pad, GstData * _data);
61 static GstCaps *gst_videoflip_get_capslist (void);
64 static GstElementClass *parent_class = NULL;
66 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
69 gst_videoflip_method_get_type (void)
71 static GType videoflip_method_type = 0;
72 static GEnumValue videoflip_methods[] = {
73 {GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)"},
74 {GST_VIDEOFLIP_METHOD_90R, "1", "Rotate right 90 degrees"},
75 {GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees"},
76 {GST_VIDEOFLIP_METHOD_90L, "3", "Rotate left 90 degrees"},
77 {GST_VIDEOFLIP_METHOD_HORIZ, "4", "Flip horizontally"},
78 {GST_VIDEOFLIP_METHOD_VERT, "5", "Flip vertically"},
79 {GST_VIDEOFLIP_METHOD_TRANS, "6",
80 "Flip across upper left/lower right diagonal"},
81 {GST_VIDEOFLIP_METHOD_OTHER, "7",
82 "Flip across upper right/lower left diagonal"},
86 if (!videoflip_method_type) {
87 videoflip_method_type = g_enum_register_static ("GstVideoflipMethod",
90 return videoflip_method_type;
93 static GstPadTemplate *
94 gst_videoflip_src_template_factory (void)
96 /* well, actually RGB too, but since there's no RGB format anyway */
97 GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
98 "width = (int) [ 0, MAX ], "
99 "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
101 caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
103 return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
106 static GstPadTemplate *
107 gst_videoflip_sink_template_factory (void)
109 GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
110 "width = (int) [ 0, MAX ], "
111 "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
113 caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
115 return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
119 gst_videoflip_get_type (void)
121 static GType videoflip_type = 0;
123 if (!videoflip_type) {
124 static const GTypeInfo videoflip_info = {
125 sizeof (GstVideoflipClass),
126 gst_videoflip_base_init,
128 (GClassInitFunc) gst_videoflip_class_init,
131 sizeof (GstVideoflip),
133 (GInstanceInitFunc) gst_videoflip_init,
137 g_type_register_static (GST_TYPE_ELEMENT, "GstVideoflip",
140 return videoflip_type;
144 gst_videoflip_base_init (gpointer g_class)
146 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
148 gst_element_class_set_details (element_class, &videoflip_details);
150 gst_element_class_add_pad_template (element_class,
151 gst_videoflip_sink_template_factory ());
152 gst_element_class_add_pad_template (element_class,
153 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)
180 GstStructure *structure;
183 caps = gst_caps_new_empty ();
184 for (i = 0; i < videoflip_n_formats; i++) {
185 structure = videoflip_get_cap (videoflip_formats + i);
186 gst_caps_append_structure (caps, structure);
193 gst_videoflip_sink_getcaps (GstPad * pad)
195 GstVideoflip *videoflip;
196 GstCaps *capslist = NULL;
202 GST_DEBUG ("gst_videoflip_sink_getcaps");
203 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
205 /* get list of peer's caps */
206 if (pad == videoflip->srcpad) {
207 peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
209 peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
212 /* FIXME videoflip doesn't allow passthru of video formats it
213 * doesn't understand. */
214 /* Look through our list of caps and find those that match with
215 * the peer's formats. Create a list of them. */
216 for (i = 0; i < videoflip_n_formats; i++) {
218 gst_caps_new_full (videoflip_get_cap (videoflip_formats + i), NULL);
219 if (gst_caps_is_always_compatible (fromcaps, peercaps)) {
220 gst_caps_append (capslist, fromcaps);
223 gst_caps_free (peercaps);
225 sizecaps = gst_caps_from_string ("video/x-raw-yuv, "
226 "width = (int) [ 0, MAX ], "
227 "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
229 caps = gst_caps_intersect (capslist, sizecaps);
230 gst_caps_free (sizecaps);
236 static GstPadLinkReturn
237 gst_videoflip_src_link (GstPad * pad, const GstCaps * caps)
239 GstVideoflip *videoflip;
240 GstStructure *structure;
243 GST_DEBUG ("gst_videoflip_src_link");
244 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
246 structure = gst_caps_get_structure (caps, 0);
248 videoflip->format = videoflip_find_by_caps (caps);
249 g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
251 ret = gst_structure_get_int (structure, "width", &videoflip->to_width);
252 ret &= gst_structure_get_int (structure, "height", &videoflip->to_height);
255 return GST_PAD_LINK_REFUSED;
257 return GST_PAD_LINK_OK;
260 static GstPadLinkReturn
261 gst_videoflip_sink_link (GstPad * pad, const GstCaps * caps)
263 GstVideoflip *videoflip;
264 GstStructure *structure;
267 GST_DEBUG ("gst_videoflip_sink_link");
268 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
270 structure = gst_caps_get_structure (caps, 0);
272 videoflip->format = videoflip_find_by_caps (caps);
273 g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
275 ret = gst_structure_get_int (structure, "width", &videoflip->from_width);
276 ret &= gst_structure_get_int (structure, "height", &videoflip->from_height);
279 return GST_PAD_LINK_REFUSED;
281 return GST_PAD_LINK_OK;
285 gst_videoflip_init (GstVideoflip * videoflip)
287 GST_DEBUG ("gst_videoflip_init");
289 gst_pad_new_from_template (gst_videoflip_sink_template_factory (),
291 gst_element_add_pad (GST_ELEMENT (videoflip), videoflip->sinkpad);
292 gst_pad_set_chain_function (videoflip->sinkpad, gst_videoflip_chain);
293 gst_pad_set_link_function (videoflip->sinkpad, gst_videoflip_sink_link);
294 gst_pad_set_getcaps_function (videoflip->sinkpad, gst_videoflip_sink_getcaps);
297 gst_pad_new_from_template (gst_videoflip_src_template_factory (), "src");
298 gst_element_add_pad (GST_ELEMENT (videoflip), videoflip->srcpad);
299 gst_pad_set_link_function (videoflip->srcpad, gst_videoflip_src_link);
300 //gst_pad_set_getcaps_function(videoflip->srcpad,gst_videoflip_getcaps);
302 videoflip->inited = FALSE;
303 videoflip->force_size = FALSE;
308 gst_videoflip_chain (GstPad * pad, GstData * _data)
310 GstBuffer *buf = GST_BUFFER (_data);
311 GstVideoflip *videoflip;
316 GST_DEBUG ("gst_videoflip_chain");
318 g_return_if_fail (pad != NULL);
319 g_return_if_fail (GST_IS_PAD (pad));
320 g_return_if_fail (buf != NULL);
322 videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
323 g_return_if_fail (videoflip->inited);
325 data = GST_BUFFER_DATA (buf);
326 size = GST_BUFFER_SIZE (buf);
328 if (videoflip->passthru) {
329 gst_pad_push (videoflip->srcpad, GST_DATA (buf));
333 GST_DEBUG ("gst_videoflip_chain: got buffer of %ld bytes in '%s'", size,
334 GST_OBJECT_NAME (videoflip));
337 ("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
338 size, videoflip->from_width, videoflip->from_height, videoflip->to_width,
339 videoflip->to_height, size, videoflip->from_buf_size,
340 videoflip->to_buf_size);
342 g_return_if_fail (size == videoflip->from_buf_size);
344 outbuf = gst_buffer_new ();
345 /* FIXME: handle bufferpools */
346 GST_BUFFER_SIZE (outbuf) = videoflip->to_buf_size;
347 GST_BUFFER_DATA (outbuf) = g_malloc (videoflip->to_buf_size);
348 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
350 g_return_if_fail (videoflip->format);
351 GST_DEBUG ("format %s", videoflip->format->fourcc);
352 g_return_if_fail (videoflip->format->scale);
354 videoflip->format->scale (videoflip, GST_BUFFER_DATA (outbuf), data);
356 GST_DEBUG ("gst_videoflip_chain: pushing buffer of %d bytes in '%s'",
357 GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (videoflip));
359 gst_pad_push (videoflip->srcpad, GST_DATA (outbuf));
361 gst_buffer_unref (buf);
365 gst_videoflip_set_property (GObject * object, guint prop_id,
366 const GValue * value, GParamSpec * pspec)
370 /* it's not null if we got it, but it might not be ours */
371 g_return_if_fail (GST_IS_VIDEOFLIP (object));
372 src = GST_VIDEOFLIP (object);
374 GST_DEBUG ("gst_videoflip_set_property");
377 src->method = g_value_get_enum (value);
385 gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
390 /* it's not null if we got it, but it might not be ours */
391 g_return_if_fail (GST_IS_VIDEOFLIP (object));
392 src = GST_VIDEOFLIP (object);
396 g_value_set_enum (value, src->method);
399 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
406 plugin_init (GstPlugin * plugin)
408 return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
412 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
415 "Resizes video", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)