VideoFilter inherits from
[platform/upstream/gstreamer.git] / gst / effectv / gstvertigo.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * EffecTV:
5  * Copyright (C) 2001 FUKUCHI Kentarou
6  *
7  * EffecTV is free software. This library is free software;
8  * you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <gstvideofilter.h>
30
31 #include <math.h>
32 #include <string.h>
33
34 #include <gst/video/video.h>
35
36 #define GST_TYPE_VERTIGOTV \
37   (gst_vertigotv_get_type())
38 #define GST_VERTIGOTV(obj) \
39   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VERTIGOTV,GstVertigoTV))
40 #define GST_VERTIGOTV_CLASS(klass) \
41   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VERTIGOTV,GstVertigoTVClass))
42 #define GST_IS_VERTIGOTV(obj) \
43   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VERTIGOTV))
44 #define GST_IS_VERTIGOTV_CLASS(obj) \
45   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VERTIGOTV))
46
47 typedef struct _GstVertigoTV GstVertigoTV;
48 typedef struct _GstVertigoTVClass GstVertigoTVClass;
49
50 struct _GstVertigoTV
51 {
52   GstVideofilter videofilter;
53
54   gint width, height;
55   guint32 *buffer;
56   guint32 *current_buffer, *alt_buffer;
57   gint dx, dy;
58   gint sx, sy;
59   gdouble phase;
60   gdouble phase_increment;
61   gdouble zoomrate;
62 };
63
64 struct _GstVertigoTVClass
65 {
66   GstVideofilterClass parent_class;
67 };
68
69 GType gst_vertigotv_get_type (void);
70
71 /* Filter signals and args */
72 enum
73 {
74   ARG_0,
75   ARG_SPEED,
76   ARG_ZOOM_SPEED
77 };
78
79 static GstElementDetails vertigotv_details = GST_ELEMENT_DETAILS ("VertigoTV",
80     "Filter/Effect/Video",
81     "A loopback alpha blending effector with rotating and scaling",
82     "Wim Taymans <wim.taymans@chello.be>");
83
84 static GstStaticPadTemplate gst_vertigotv_src_template =
85 GST_STATIC_PAD_TEMPLATE ("src",
86     GST_PAD_SRC,
87     GST_PAD_ALWAYS,
88     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
89     );
90
91 static GstStaticPadTemplate gst_vertigotv_sink_template =
92 GST_STATIC_PAD_TEMPLATE ("sink",
93     GST_PAD_SINK,
94     GST_PAD_ALWAYS,
95     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
96     );
97
98 static GstVideofilterClass *parent_class = NULL;
99
100 static gboolean
101 gst_vertigotv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
102     GstCaps * outcaps)
103 {
104   GstVertigoTV *filter = GST_VERTIGOTV (btrans);
105   GstStructure *structure;
106   gboolean ret = FALSE;
107
108   structure = gst_caps_get_structure (incaps, 0);
109
110   if (gst_structure_get_int (structure, "width", &filter->width) &&
111       gst_structure_get_int (structure, "height", &filter->height)) {
112     gint area = filter->width * filter->height;
113
114     g_free (filter->buffer);
115     filter->buffer = (guint32 *) g_malloc (area * 2 * sizeof (guint32));
116
117     memset (filter->buffer, 0, area * 2 * sizeof (guint32));
118     filter->current_buffer = filter->buffer;
119     filter->alt_buffer = filter->buffer + area;
120     filter->phase = 0;
121
122     ret = TRUE;
123   }
124
125   return ret;
126 }
127
128 static gboolean
129 gst_vertigotv_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
130     guint * size)
131 {
132   GstVertigoTV *filter;
133   GstStructure *structure;
134   gboolean ret = FALSE;
135   gint width, height;
136
137   filter = GST_VERTIGOTV (btrans);
138
139   structure = gst_caps_get_structure (caps, 0);
140
141   if (gst_structure_get_int (structure, "width", &width) &&
142       gst_structure_get_int (structure, "height", &height)) {
143     *size = width * height * 32 / 8;
144     ret = TRUE;
145     GST_DEBUG_OBJECT (filter, "our frame size is %d bytes (%dx%d)", *size,
146         width, height);
147   }
148
149   return ret;
150 }
151
152 static void
153 gst_vertigotv_set_parms (GstVertigoTV * filter)
154 {
155   double vx, vy;
156   double t;
157   double x, y;
158   double dizz;
159
160   dizz = sin (filter->phase) * 10 + sin (filter->phase * 1.9 + 5) * 5;
161
162   x = filter->width / 2;
163   y = filter->height / 2;
164
165   t = (x * x + y * y) * filter->zoomrate;
166
167   if (filter->width > filter->height) {
168     if (dizz >= 0) {
169       if (dizz > x)
170         dizz = x;
171       vx = (x * (x - dizz) + y * y) / t;
172     } else {
173       if (dizz < -x)
174         dizz = -x;
175       vx = (x * (x + dizz) + y * y) / t;
176     }
177     vy = (dizz * y) / t;
178   } else {
179     if (dizz >= 0) {
180       if (dizz > y)
181         dizz = y;
182       vx = (x * x + y * (y - dizz)) / t;
183     } else {
184       if (dizz < -y)
185         dizz = -y;
186       vx = (x * x + y * (y + dizz)) / t;
187     }
188     vy = (dizz * x) / t;
189   }
190   filter->dx = vx * 65536;
191   filter->dy = vy * 65536;
192   filter->sx = (-vx * x + vy * y + x + cos (filter->phase * 5) * 2) * 65536;
193   filter->sy = (-vx * y - vy * x + y + sin (filter->phase * 6) * 2) * 65536;
194
195   filter->phase += filter->phase_increment;
196   if (filter->phase > 5700000)
197     filter->phase = 0;
198 }
199
200 static GstFlowReturn
201 gst_vertigotv_transform (GstBaseTransform * trans, GstBuffer * in,
202     GstBuffer * out)
203 {
204   GstVertigoTV *filter;
205   guint32 *src, *dest, *p;
206   guint32 v;
207   gint x, y, ox, oy, i, width, height, area;
208   GstFlowReturn ret = GST_FLOW_OK;
209
210   filter = GST_VERTIGOTV (trans);
211
212   gst_buffer_stamp (out, in);
213
214   src = (guint32 *) GST_BUFFER_DATA (in);
215   dest = (guint32 *) GST_BUFFER_DATA (out);
216
217   width = filter->width;
218   height = filter->height;
219   area = width * height;
220
221   gst_vertigotv_set_parms (filter);
222   p = filter->alt_buffer;
223
224   for (y = height; y > 0; y--) {
225     ox = filter->sx;
226     oy = filter->sy;
227
228     for (x = width; x > 0; x--) {
229       i = (oy >> 16) * width + (ox >> 16);
230       if (i < 0)
231         i = 0;
232       if (i >= area)
233         i = area;
234
235       v = filter->current_buffer[i] & 0xfcfcff;
236       v = (v * 3) + ((*src++) & 0xfcfcff);
237
238       *p++ = (v >> 2);
239       ox += filter->dx;
240       oy += filter->dy;
241     }
242     filter->sx -= filter->dy;
243     filter->sy += filter->dx;
244   }
245
246   memcpy (dest, filter->alt_buffer, area * sizeof (guint32));
247
248   p = filter->current_buffer;
249   filter->current_buffer = filter->alt_buffer;
250   filter->alt_buffer = p;
251
252   return ret;
253 }
254
255 static void
256 gst_vertigotv_set_property (GObject * object, guint prop_id,
257     const GValue * value, GParamSpec * pspec)
258 {
259   GstVertigoTV *filter;
260
261   g_return_if_fail (GST_IS_VERTIGOTV (object));
262
263   filter = GST_VERTIGOTV (object);
264
265   switch (prop_id) {
266     case ARG_SPEED:
267       filter->phase_increment = g_value_get_float (value);
268       break;
269     case ARG_ZOOM_SPEED:
270       filter->zoomrate = g_value_get_float (value);
271       break;
272     default:
273       break;
274   }
275 }
276
277 static void
278 gst_vertigotv_get_property (GObject * object, guint prop_id, GValue * value,
279     GParamSpec * pspec)
280 {
281   GstVertigoTV *filter;
282
283   g_return_if_fail (GST_IS_VERTIGOTV (object));
284
285   filter = GST_VERTIGOTV (object);
286
287   switch (prop_id) {
288     case ARG_SPEED:
289       g_value_set_float (value, filter->phase_increment);
290       break;
291     case ARG_ZOOM_SPEED:
292       g_value_set_float (value, filter->zoomrate);
293       break;
294     default:
295       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
296       break;
297   }
298 }
299
300 static void
301 gst_vertigotv_base_init (gpointer g_class)
302 {
303   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
304
305   gst_element_class_set_details (element_class, &vertigotv_details);
306
307   gst_element_class_add_pad_template (element_class,
308       gst_static_pad_template_get (&gst_vertigotv_sink_template));
309   gst_element_class_add_pad_template (element_class,
310       gst_static_pad_template_get (&gst_vertigotv_src_template));
311 }
312
313 static void
314 gst_vertigotv_class_init (gpointer klass, gpointer class_data)
315 {
316   GObjectClass *gobject_class;
317   GstElementClass *element_class;
318   GstBaseTransformClass *trans_class;
319
320   gobject_class = (GObjectClass *) klass;
321   element_class = (GstElementClass *) klass;
322   trans_class = (GstBaseTransformClass *) klass;
323
324   parent_class = g_type_class_peek_parent (klass);
325
326   gobject_class->set_property = gst_vertigotv_set_property;
327   gobject_class->get_property = gst_vertigotv_get_property;
328
329   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SPEED,
330       g_param_spec_float ("speed", "Speed", "Control the speed of movement",
331           0.01, 100.0, 0.02, G_PARAM_READWRITE));
332   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ZOOM_SPEED,
333       g_param_spec_float ("zoom_speed", "Zoom Speed",
334           "Control the rate of zooming", 1.01, 1.1, 1.01, G_PARAM_READWRITE));
335
336   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_vertigotv_set_caps);
337   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_vertigotv_get_unit_size);
338   trans_class->transform = GST_DEBUG_FUNCPTR (gst_vertigotv_transform);
339 }
340
341 static void
342 gst_vertigotv_init (GTypeInstance * instance, gpointer g_class)
343 {
344   GstVertigoTV *filter = GST_VERTIGOTV (instance);
345
346   filter->buffer = NULL;
347   filter->phase = 0.0;
348   filter->phase_increment = 0.02;
349   filter->zoomrate = 1.01;
350 }
351
352 GType
353 gst_vertigotv_get_type (void)
354 {
355   static GType vertigotv_type = 0;
356
357   if (!vertigotv_type) {
358     static const GTypeInfo vertigotv_info = {
359       sizeof (GstVertigoTVClass),
360       gst_vertigotv_base_init,
361       NULL,
362       (GClassInitFunc) gst_vertigotv_class_init,
363       NULL,
364       NULL,
365       sizeof (GstVertigoTV),
366       0,
367       (GInstanceInitFunc) gst_vertigotv_init,
368     };
369
370     vertigotv_type =
371         g_type_register_static (GST_TYPE_VIDEOFILTER, "GstVertigoTV",
372         &vertigotv_info, 0);
373   }
374   return vertigotv_type;
375 }