gst-indent
[platform/upstream/gst-plugins-good.git] / gst / videoflip / gstvideoflip.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20
21 /*#define DEBUG_ENABLED */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <gstvideoflip.h>
26 #include <videoflip.h>
27
28
29
30 /* elementfactory information */
31 static GstElementDetails videoflip_details =
32 GST_ELEMENT_DETAILS ("Video scaler",
33     "Filter/Effect/Video",
34     "Resizes video",
35     "Wim Taymans <wim.taymans@chello.be>");
36
37 /* GstVideoflip signals and args */
38 enum
39 {
40   /* FILL ME */
41   LAST_SIGNAL
42 };
43
44 enum
45 {
46   ARG_0,
47   ARG_METHOD,
48   /* FILL ME */
49 };
50
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);
54
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);
59
60 static void gst_videoflip_chain (GstPad * pad, GstData * _data);
61 static GstCaps *gst_videoflip_get_capslist (void);
62
63
64 static GstElementClass *parent_class = NULL;
65
66 #define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
67
68 static GType
69 gst_videoflip_method_get_type (void)
70 {
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"},
83     {0, NULL, NULL},
84   };
85   if (!videoflip_method_type) {
86     videoflip_method_type = g_enum_register_static ("GstVideoflipMethod",
87         videoflip_methods);
88   }
89   return videoflip_method_type;
90 }
91
92 static GstPadTemplate *
93 gst_videoflip_src_template_factory (void)
94 {
95   /* well, actually RGB too, but since there's no RGB format anyway */
96   GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
97       "width = (int) [ 0, MAX ], "
98       "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
99
100   caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
101
102   return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
103 }
104
105 static GstPadTemplate *
106 gst_videoflip_sink_template_factory (void)
107 {
108   GstCaps *caps = gst_caps_from_string ("video/x-raw-yuv, "
109       "width = (int) [ 0, MAX ], "
110       "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
111
112   caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
113
114   return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
115 }
116
117 GType
118 gst_videoflip_get_type (void)
119 {
120   static GType videoflip_type = 0;
121
122   if (!videoflip_type) {
123     static const GTypeInfo videoflip_info = {
124       sizeof (GstVideoflipClass),
125       gst_videoflip_base_init,
126       NULL,
127       (GClassInitFunc) gst_videoflip_class_init,
128       NULL,
129       NULL,
130       sizeof (GstVideoflip),
131       0,
132       (GInstanceInitFunc) gst_videoflip_init,
133     };
134     videoflip_type =
135         g_type_register_static (GST_TYPE_ELEMENT, "GstVideoflip",
136         &videoflip_info, 0);
137   }
138   return videoflip_type;
139 }
140
141 static void
142 gst_videoflip_base_init (gpointer g_class)
143 {
144   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
145
146   gst_element_class_set_details (element_class, &videoflip_details);
147
148   gst_element_class_add_pad_template (element_class,
149       gst_videoflip_sink_template_factory ());
150   gst_element_class_add_pad_template (element_class,
151       gst_videoflip_src_template_factory ());
152 }
153 static void
154 gst_videoflip_class_init (GstVideoflipClass * klass)
155 {
156   GObjectClass *gobject_class;
157   GstElementClass *gstelement_class;
158
159   gobject_class = (GObjectClass *) klass;
160   gstelement_class = (GstElementClass *) klass;
161
162   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
163       g_param_spec_enum ("method", "method", "method",
164           GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
165           G_PARAM_READWRITE));
166
167   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
168
169   gobject_class->set_property = gst_videoflip_set_property;
170   gobject_class->get_property = gst_videoflip_get_property;
171
172 }
173
174 static GstCaps *
175 gst_videoflip_get_capslist (void)
176 {
177   GstCaps *caps;
178   GstStructure *structure;
179   int i;
180
181   caps = gst_caps_new_empty ();
182   for (i = 0; i < videoflip_n_formats; i++) {
183     structure = videoflip_get_cap (videoflip_formats + i);
184     gst_caps_append_structure (caps, structure);
185   }
186
187   return caps;
188 }
189
190 static GstCaps *
191 gst_videoflip_sink_getcaps (GstPad * pad)
192 {
193   GstVideoflip *videoflip;
194   GstCaps *capslist = NULL;
195   GstCaps *peercaps;
196   GstCaps *sizecaps;
197   GstCaps *caps;
198   int i;
199
200   GST_DEBUG ("gst_videoflip_sink_getcaps");
201   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
202
203   /* get list of peer's caps */
204   if (pad == videoflip->srcpad) {
205     peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
206   } else {
207     peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
208   }
209
210   /* FIXME videoflip doesn't allow passthru of video formats it
211    * doesn't understand. */
212   /* Look through our list of caps and find those that match with
213    * the peer's formats.  Create a list of them. */
214   for (i = 0; i < videoflip_n_formats; i++) {
215     GstCaps *fromcaps =
216         gst_caps_new_full (videoflip_get_cap (videoflip_formats + i), NULL);
217     if (gst_caps_is_always_compatible (fromcaps, peercaps)) {
218       gst_caps_append (capslist, fromcaps);
219     }
220   }
221   gst_caps_free (peercaps);
222
223   sizecaps = gst_caps_from_string ("video/x-raw-yuv, "
224       "width = (int) [ 0, MAX ], "
225       "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
226
227   caps = gst_caps_intersect (capslist, sizecaps);
228   gst_caps_free (sizecaps);
229
230   return caps;
231 }
232
233
234 static GstPadLinkReturn
235 gst_videoflip_src_link (GstPad * pad, const GstCaps * caps)
236 {
237   GstVideoflip *videoflip;
238   GstStructure *structure;
239   gboolean ret;
240
241   GST_DEBUG ("gst_videoflip_src_link");
242   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
243
244   structure = gst_caps_get_structure (caps, 0);
245
246   videoflip->format = videoflip_find_by_caps (caps);
247   g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
248
249   ret = gst_structure_get_int (structure, "width", &videoflip->to_width);
250   ret &= gst_structure_get_int (structure, "height", &videoflip->to_height);
251
252   if (!ret)
253     return GST_PAD_LINK_REFUSED;
254
255   return GST_PAD_LINK_OK;
256 }
257
258 static GstPadLinkReturn
259 gst_videoflip_sink_link (GstPad * pad, const GstCaps * caps)
260 {
261   GstVideoflip *videoflip;
262   GstStructure *structure;
263   gboolean ret;
264
265   GST_DEBUG ("gst_videoflip_sink_link");
266   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
267
268   structure = gst_caps_get_structure (caps, 0);
269
270   videoflip->format = videoflip_find_by_caps (caps);
271   g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
272
273   ret = gst_structure_get_int (structure, "width", &videoflip->from_width);
274   ret &= gst_structure_get_int (structure, "height", &videoflip->from_height);
275
276   if (!ret)
277     return GST_PAD_LINK_REFUSED;
278
279   return GST_PAD_LINK_OK;
280 }
281
282 static void
283 gst_videoflip_init (GstVideoflip * videoflip)
284 {
285   GST_DEBUG ("gst_videoflip_init");
286   videoflip->sinkpad =
287       gst_pad_new_from_template (gst_videoflip_sink_template_factory (),
288       "sink");
289   gst_element_add_pad (GST_ELEMENT (videoflip), videoflip->sinkpad);
290   gst_pad_set_chain_function (videoflip->sinkpad, gst_videoflip_chain);
291   gst_pad_set_link_function (videoflip->sinkpad, gst_videoflip_sink_link);
292   gst_pad_set_getcaps_function (videoflip->sinkpad, gst_videoflip_sink_getcaps);
293
294   videoflip->srcpad =
295       gst_pad_new_from_template (gst_videoflip_src_template_factory (), "src");
296   gst_element_add_pad (GST_ELEMENT (videoflip), videoflip->srcpad);
297   gst_pad_set_link_function (videoflip->srcpad, gst_videoflip_src_link);
298   //gst_pad_set_getcaps_function(videoflip->srcpad,gst_videoflip_getcaps);
299
300   videoflip->inited = FALSE;
301   videoflip->force_size = FALSE;
302 }
303
304
305 static void
306 gst_videoflip_chain (GstPad * pad, GstData * _data)
307 {
308   GstBuffer *buf = GST_BUFFER (_data);
309   GstVideoflip *videoflip;
310   guchar *data;
311   gulong size;
312   GstBuffer *outbuf;
313
314   GST_DEBUG ("gst_videoflip_chain");
315
316   g_return_if_fail (pad != NULL);
317   g_return_if_fail (GST_IS_PAD (pad));
318   g_return_if_fail (buf != NULL);
319
320   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
321   g_return_if_fail (videoflip->inited);
322
323   data = GST_BUFFER_DATA (buf);
324   size = GST_BUFFER_SIZE (buf);
325
326   if (videoflip->passthru) {
327     gst_pad_push (videoflip->srcpad, GST_DATA (buf));
328     return;
329   }
330
331   GST_DEBUG ("gst_videoflip_chain: got buffer of %ld bytes in '%s'", size,
332       GST_OBJECT_NAME (videoflip));
333
334   GST_DEBUG
335       ("size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
336       size, videoflip->from_width, videoflip->from_height, videoflip->to_width,
337       videoflip->to_height, size, videoflip->from_buf_size,
338       videoflip->to_buf_size);
339
340   g_return_if_fail (size == videoflip->from_buf_size);
341
342   outbuf = gst_buffer_new ();
343   /* FIXME: handle bufferpools */
344   GST_BUFFER_SIZE (outbuf) = videoflip->to_buf_size;
345   GST_BUFFER_DATA (outbuf) = g_malloc (videoflip->to_buf_size);
346   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
347
348   g_return_if_fail (videoflip->format);
349   GST_DEBUG ("format %s", videoflip->format->fourcc);
350   g_return_if_fail (videoflip->format->scale);
351
352   videoflip->format->scale (videoflip, GST_BUFFER_DATA (outbuf), data);
353
354   GST_DEBUG ("gst_videoflip_chain: pushing buffer of %d bytes in '%s'",
355       GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (videoflip));
356
357   gst_pad_push (videoflip->srcpad, GST_DATA (outbuf));
358
359   gst_buffer_unref (buf);
360 }
361
362 static void
363 gst_videoflip_set_property (GObject * object, guint prop_id,
364     const GValue * value, GParamSpec * pspec)
365 {
366   GstVideoflip *src;
367
368   /* it's not null if we got it, but it might not be ours */
369   g_return_if_fail (GST_IS_VIDEOFLIP (object));
370   src = GST_VIDEOFLIP (object);
371
372   GST_DEBUG ("gst_videoflip_set_property");
373   switch (prop_id) {
374     case ARG_METHOD:
375       src->method = g_value_get_enum (value);
376       break;
377     default:
378       break;
379   }
380 }
381
382 static void
383 gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
384     GParamSpec * pspec)
385 {
386   GstVideoflip *src;
387
388   /* it's not null if we got it, but it might not be ours */
389   g_return_if_fail (GST_IS_VIDEOFLIP (object));
390   src = GST_VIDEOFLIP (object);
391
392   switch (prop_id) {
393     case ARG_METHOD:
394       g_value_set_enum (value, src->method);
395       break;
396     default:
397       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
398       break;
399   }
400 }
401
402
403 static gboolean
404 plugin_init (GstPlugin * plugin)
405 {
406   return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
407       GST_TYPE_VIDEOFLIP);
408 }
409
410 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
411     GST_VERSION_MINOR,
412     "videoflip",
413     "Resizes video", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)