Way, way, way too many files: Remove crack comment from the 2000 era.
[platform/upstream/gstreamer.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
86   if (!videoflip_method_type) {
87     videoflip_method_type = g_enum_register_static ("GstVideoflipMethod",
88         videoflip_methods);
89   }
90   return videoflip_method_type;
91 }
92
93 static GstPadTemplate *
94 gst_videoflip_src_template_factory (void)
95 {
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 ]");
100
101   caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
102
103   return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
104 }
105
106 static GstPadTemplate *
107 gst_videoflip_sink_template_factory (void)
108 {
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 ]");
112
113   caps = gst_caps_intersect (caps, gst_videoflip_get_capslist ());
114
115   return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
116 }
117
118 GType
119 gst_videoflip_get_type (void)
120 {
121   static GType videoflip_type = 0;
122
123   if (!videoflip_type) {
124     static const GTypeInfo videoflip_info = {
125       sizeof (GstVideoflipClass),
126       gst_videoflip_base_init,
127       NULL,
128       (GClassInitFunc) gst_videoflip_class_init,
129       NULL,
130       NULL,
131       sizeof (GstVideoflip),
132       0,
133       (GInstanceInitFunc) gst_videoflip_init,
134     };
135
136     videoflip_type =
137         g_type_register_static (GST_TYPE_ELEMENT, "GstVideoflip",
138         &videoflip_info, 0);
139   }
140   return videoflip_type;
141 }
142
143 static void
144 gst_videoflip_base_init (gpointer g_class)
145 {
146   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
147
148   gst_element_class_set_details (element_class, &videoflip_details);
149
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 ());
154 }
155 static void
156 gst_videoflip_class_init (GstVideoflipClass * klass)
157 {
158   GObjectClass *gobject_class;
159   GstElementClass *gstelement_class;
160
161   gobject_class = (GObjectClass *) klass;
162   gstelement_class = (GstElementClass *) klass;
163
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,
167           G_PARAM_READWRITE));
168
169   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
170
171   gobject_class->set_property = gst_videoflip_set_property;
172   gobject_class->get_property = gst_videoflip_get_property;
173
174 }
175
176 static GstCaps *
177 gst_videoflip_get_capslist (void)
178 {
179   GstCaps *caps;
180   GstStructure *structure;
181   int i;
182
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);
187   }
188
189   return caps;
190 }
191
192 static GstCaps *
193 gst_videoflip_sink_getcaps (GstPad * pad)
194 {
195   GstVideoflip *videoflip;
196   GstCaps *capslist = NULL;
197   GstCaps *peercaps;
198   GstCaps *sizecaps;
199   GstCaps *caps;
200   int i;
201
202   GST_DEBUG ("gst_videoflip_sink_getcaps");
203   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
204
205   /* get list of peer's caps */
206   if (pad == videoflip->srcpad) {
207     peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
208   } else {
209     peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
210   }
211
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++) {
217     GstCaps *fromcaps =
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);
221     }
222   }
223   gst_caps_free (peercaps);
224
225   sizecaps = gst_caps_from_string ("video/x-raw-yuv, "
226       "width = (int) [ 0, MAX ], "
227       "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]");
228
229   caps = gst_caps_intersect (capslist, sizecaps);
230   gst_caps_free (sizecaps);
231
232   return caps;
233 }
234
235
236 static GstPadLinkReturn
237 gst_videoflip_src_link (GstPad * pad, const GstCaps * caps)
238 {
239   GstVideoflip *videoflip;
240   GstStructure *structure;
241   gboolean ret;
242
243   GST_DEBUG ("gst_videoflip_src_link");
244   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
245
246   structure = gst_caps_get_structure (caps, 0);
247
248   videoflip->format = videoflip_find_by_caps (caps);
249   g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
250
251   ret = gst_structure_get_int (structure, "width", &videoflip->to_width);
252   ret &= gst_structure_get_int (structure, "height", &videoflip->to_height);
253
254   if (!ret)
255     return GST_PAD_LINK_REFUSED;
256
257   return GST_PAD_LINK_OK;
258 }
259
260 static GstPadLinkReturn
261 gst_videoflip_sink_link (GstPad * pad, const GstCaps * caps)
262 {
263   GstVideoflip *videoflip;
264   GstStructure *structure;
265   gboolean ret;
266
267   GST_DEBUG ("gst_videoflip_sink_link");
268   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
269
270   structure = gst_caps_get_structure (caps, 0);
271
272   videoflip->format = videoflip_find_by_caps (caps);
273   g_return_val_if_fail (videoflip->format, GST_PAD_LINK_REFUSED);
274
275   ret = gst_structure_get_int (structure, "width", &videoflip->from_width);
276   ret &= gst_structure_get_int (structure, "height", &videoflip->from_height);
277
278   if (!ret)
279     return GST_PAD_LINK_REFUSED;
280
281   return GST_PAD_LINK_OK;
282 }
283
284 static void
285 gst_videoflip_init (GstVideoflip * videoflip)
286 {
287   GST_DEBUG ("gst_videoflip_init");
288   videoflip->sinkpad =
289       gst_pad_new_from_template (gst_videoflip_sink_template_factory (),
290       "sink");
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);
295
296   videoflip->srcpad =
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);
301
302   videoflip->inited = FALSE;
303   videoflip->force_size = FALSE;
304 }
305
306
307 static void
308 gst_videoflip_chain (GstPad * pad, GstData * _data)
309 {
310   GstBuffer *buf = GST_BUFFER (_data);
311   GstVideoflip *videoflip;
312   guchar *data;
313   gulong size;
314   GstBuffer *outbuf;
315
316   GST_DEBUG ("gst_videoflip_chain");
317
318   g_return_if_fail (pad != NULL);
319   g_return_if_fail (GST_IS_PAD (pad));
320   g_return_if_fail (buf != NULL);
321
322   videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
323   g_return_if_fail (videoflip->inited);
324
325   data = GST_BUFFER_DATA (buf);
326   size = GST_BUFFER_SIZE (buf);
327
328   if (videoflip->passthru) {
329     gst_pad_push (videoflip->srcpad, GST_DATA (buf));
330     return;
331   }
332
333   GST_DEBUG ("gst_videoflip_chain: got buffer of %ld bytes in '%s'", size,
334       GST_OBJECT_NAME (videoflip));
335
336   GST_DEBUG
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);
341
342   g_return_if_fail (size == videoflip->from_buf_size);
343
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);
349
350   g_return_if_fail (videoflip->format);
351   GST_DEBUG ("format %s", videoflip->format->fourcc);
352   g_return_if_fail (videoflip->format->scale);
353
354   videoflip->format->scale (videoflip, GST_BUFFER_DATA (outbuf), data);
355
356   GST_DEBUG ("gst_videoflip_chain: pushing buffer of %d bytes in '%s'",
357       GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (videoflip));
358
359   gst_pad_push (videoflip->srcpad, GST_DATA (outbuf));
360
361   gst_buffer_unref (buf);
362 }
363
364 static void
365 gst_videoflip_set_property (GObject * object, guint prop_id,
366     const GValue * value, GParamSpec * pspec)
367 {
368   GstVideoflip *src;
369
370   g_return_if_fail (GST_IS_VIDEOFLIP (object));
371   src = GST_VIDEOFLIP (object);
372
373   GST_DEBUG ("gst_videoflip_set_property");
374   switch (prop_id) {
375     case ARG_METHOD:
376       src->method = g_value_get_enum (value);
377       break;
378     default:
379       break;
380   }
381 }
382
383 static void
384 gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
385     GParamSpec * pspec)
386 {
387   GstVideoflip *src;
388
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)