d44a5a0b17574d94f6b6b0380d2fccbb16646e95
[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 #include <math.h>
29 #include <string.h>
30 #include <gst/gst.h>
31 #include <gstvideofilter.h>
32
33 #define GST_TYPE_VERTIGOTV \
34   (gst_vertigotv_get_type())
35 #define GST_VERTIGOTV(obj) \
36   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VERTIGOTV,GstVertigoTV))
37 #define GST_VERTIGOTV_CLASS(klass) \
38   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VERTIGOTV,GstVertigoTVClass))
39 #define GST_IS_VERTIGOTV(obj) \
40   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VERTIGOTV))
41 #define GST_IS_VERTIGOTV_CLASS(obj) \
42   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VERTIGOTV))
43
44 typedef struct _GstVertigoTV GstVertigoTV;
45 typedef struct _GstVertigoTVClass GstVertigoTVClass;
46
47 struct _GstVertigoTV
48 {
49   GstVideofilter videofilter;
50
51   gint width, height;
52   guint32 *buffer;
53   guint32 *current_buffer, *alt_buffer;
54   gint dx, dy;
55   gint sx, sy;
56   gdouble phase;
57   gdouble phase_increment;
58   gdouble zoomrate;
59 };
60
61 struct _GstVertigoTVClass
62 {
63   GstVideofilterClass parent_class;
64
65   void (*reset) (GstElement * element);
66 };
67
68 /* Filter signals and args */
69 enum
70 {
71   /* FILL ME */
72   RESET_SIGNAL,
73   LAST_SIGNAL
74 };
75
76 enum
77 {
78   ARG_0,
79   ARG_SPEED,
80   ARG_ZOOM_SPEED
81 };
82
83 static void gst_vertigotv_base_init (gpointer g_class);
84 static void gst_vertigotv_class_init (GstVertigoTVClass * klass,
85     gpointer class_data);
86 static void gst_vertigotv_init (GTypeInstance * instance, gpointer g_class);
87 static void gst_vertigotv_setup (GstVideofilter * videofilter);
88
89 static void gst_vertigotv_reset_handler (GstElement * element);
90
91 static void gst_vertigotv_set_property (GObject * object, guint prop_id,
92     const GValue * value, GParamSpec * pspec);
93 static void gst_vertigotv_get_property (GObject * object, guint prop_id,
94     GValue * value, GParamSpec * pspec);
95 static void gst_vertigotv_rgb32 (GstVideofilter * videofilter, void *d,
96     void *s);
97
98 static guint gst_vertigotv_signals[LAST_SIGNAL] = { 0 };
99
100 GType
101 gst_vertigotv_get_type (void)
102 {
103   static GType vertigotv_type = 0;
104
105   if (!vertigotv_type) {
106     static const GTypeInfo vertigotv_info = {
107       sizeof (GstVertigoTVClass),
108       gst_vertigotv_base_init,
109       NULL,
110       (GClassInitFunc) gst_vertigotv_class_init,
111       NULL,
112       NULL,
113       sizeof (GstVertigoTV),
114       0,
115       (GInstanceInitFunc) gst_vertigotv_init,
116     };
117
118     vertigotv_type =
119         g_type_register_static (GST_TYPE_VIDEOFILTER, "GstVertigoTV",
120         &vertigotv_info, 0);
121   }
122   return vertigotv_type;
123 }
124
125 static GstVideofilterFormat gst_vertigotv_formats[] = {
126   {"RGB ", 32, gst_vertigotv_rgb32, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000,
127       0xff000000}
128 };
129
130 static void
131 gst_vertigotv_base_init (gpointer g_class)
132 {
133   /* elementfactory information */
134   static GstElementDetails vertigotv_details = GST_ELEMENT_DETAILS ("VertigoTV",
135       "Filter/Effect/Video",
136       "A loopback alpha blending effector with rotating and scaling",
137       "Wim Taymans <wim.taymans@chello.be>");
138   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
140   int i;
141
142   gst_element_class_set_details (element_class, &vertigotv_details);
143
144   for (i = 0; i < G_N_ELEMENTS (gst_vertigotv_formats); i++) {
145     gst_videofilter_class_add_format (videofilter_class,
146         gst_vertigotv_formats + i);
147   }
148
149   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
150 }
151
152 static void
153 gst_vertigotv_class_init (GstVertigoTVClass * klass, gpointer class_data)
154 {
155   GObjectClass *gobject_class;
156   GstElementClass *gstelement_class;
157   GstVideofilterClass *videofilter_class;
158
159   gobject_class = (GObjectClass *) klass;
160   gstelement_class = (GstElementClass *) klass;
161   videofilter_class = GST_VIDEOFILTER_CLASS (klass);
162
163   gst_vertigotv_signals[RESET_SIGNAL] =
164       g_signal_new ("reset-parms",
165       G_TYPE_FROM_CLASS (klass),
166       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
167       G_STRUCT_OFFSET (GstVertigoTVClass, reset),
168       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
169
170   klass->reset = gst_vertigotv_reset_handler;
171
172   gobject_class->set_property = gst_vertigotv_set_property;
173   gobject_class->get_property = gst_vertigotv_get_property;
174
175   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SPEED,
176       g_param_spec_float ("speed", "Speed", "Control the speed of movement",
177           0.01, 100.0, 0.02, G_PARAM_READWRITE));
178   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ZOOM_SPEED,
179       g_param_spec_float ("zoom_speed", "Zoom Speed",
180           "Control the rate of zooming", 1.01, 1.1, 1.01, G_PARAM_READWRITE));
181
182   videofilter_class->setup = gst_vertigotv_setup;
183 }
184
185 static void
186 gst_vertigotv_reset_handler (GstElement * element)
187 {
188   GstVertigoTV *filter = GST_VERTIGOTV (element);
189
190   filter->phase = 0.0;
191   filter->phase_increment = 0.02;
192   filter->zoomrate = 1.01;
193 }
194
195 static void
196 gst_vertigotv_setup (GstVideofilter * videofilter)
197 {
198   GstVertigoTV *filter;
199   gint area;
200   int width = gst_videofilter_get_input_width (videofilter);
201   int height = gst_videofilter_get_input_height (videofilter);
202
203   g_return_if_fail (GST_IS_VERTIGOTV (videofilter));
204   filter = GST_VERTIGOTV (videofilter);
205
206   filter->width = width;
207   filter->height = height;
208
209   area = width * height;
210
211   g_free (filter->buffer);
212   filter->buffer = (guint32 *) g_malloc (area * 2 * sizeof (guint32));
213
214   memset (filter->buffer, 0, area * 2 * sizeof (guint32));
215   filter->current_buffer = filter->buffer;
216   filter->alt_buffer = filter->buffer + area;
217   filter->phase = 0;
218 }
219
220 static void
221 gst_vertigotv_init (GTypeInstance * instance, gpointer g_class)
222 {
223   GstVertigoTV *filter = GST_VERTIGOTV (instance);
224
225   filter->buffer = NULL;
226   filter->phase = 0.0;
227   filter->phase_increment = 0.02;
228   filter->zoomrate = 1.01;
229 }
230
231 static void
232 gst_vertigotv_set_parms (GstVertigoTV * filter)
233 {
234   double vx, vy;
235   double t;
236   double x, y;
237   double dizz;
238
239   dizz = sin (filter->phase) * 10 + sin (filter->phase * 1.9 + 5) * 5;
240
241   x = filter->width / 2;
242   y = filter->height / 2;
243
244   t = (x * x + y * y) * filter->zoomrate;
245
246   if (filter->width > filter->height) {
247     if (dizz >= 0) {
248       if (dizz > x)
249         dizz = x;
250       vx = (x * (x - dizz) + y * y) / t;
251     } else {
252       if (dizz < -x)
253         dizz = -x;
254       vx = (x * (x + dizz) + y * y) / t;
255     }
256     vy = (dizz * y) / t;
257   } else {
258     if (dizz >= 0) {
259       if (dizz > y)
260         dizz = y;
261       vx = (x * x + y * (y - dizz)) / t;
262     } else {
263       if (dizz < -y)
264         dizz = -y;
265       vx = (x * x + y * (y + dizz)) / t;
266     }
267     vy = (dizz * x) / t;
268   }
269   filter->dx = vx * 65536;
270   filter->dy = vy * 65536;
271   filter->sx = (-vx * x + vy * y + x + cos (filter->phase * 5) * 2) * 65536;
272   filter->sy = (-vx * y - vy * x + y + sin (filter->phase * 6) * 2) * 65536;
273
274   filter->phase += filter->phase_increment;
275   if (filter->phase > 5700000)
276     filter->phase = 0;
277 }
278
279 static void
280 gst_vertigotv_rgb32 (GstVideofilter * videofilter, void *d, void *s)
281 {
282   GstVertigoTV *filter;
283   guint32 *src, *dest;
284   guint32 *p;
285   guint32 v;
286   gint x, y;
287   gint ox, oy;
288   gint i;
289   gint width, height, area;
290
291   filter = GST_VERTIGOTV (videofilter);
292
293   src = (guint32 *) s;
294   dest = (guint32 *) d;
295
296   width = filter->width;
297   height = filter->height;
298   area = width * height;
299
300   gst_vertigotv_set_parms (filter);
301   p = filter->alt_buffer;
302
303   for (y = height; y > 0; y--) {
304     ox = filter->sx;
305     oy = filter->sy;
306
307     for (x = width; x > 0; x--) {
308       i = (oy >> 16) * width + (ox >> 16);
309       if (i < 0)
310         i = 0;
311       if (i >= area)
312         i = area;
313
314       v = filter->current_buffer[i] & 0xfcfcff;
315       v = (v * 3) + ((*src++) & 0xfcfcff);
316
317       *p++ = (v >> 2);
318       ox += filter->dx;
319       oy += filter->dy;
320     }
321     filter->sx -= filter->dy;
322     filter->sy += filter->dx;
323   }
324
325   memcpy (dest, filter->alt_buffer, area * sizeof (guint32));
326
327   p = filter->current_buffer;
328   filter->current_buffer = filter->alt_buffer;
329   filter->alt_buffer = p;
330 }
331
332 static void
333 gst_vertigotv_set_property (GObject * object, guint prop_id,
334     const GValue * value, GParamSpec * pspec)
335 {
336   GstVertigoTV *filter;
337
338   g_return_if_fail (GST_IS_VERTIGOTV (object));
339
340   filter = GST_VERTIGOTV (object);
341
342   switch (prop_id) {
343     case ARG_SPEED:
344       filter->phase_increment = g_value_get_float (value);
345       break;
346     case ARG_ZOOM_SPEED:
347       filter->zoomrate = g_value_get_float (value);
348       break;
349     default:
350       break;
351   }
352 }
353
354 static void
355 gst_vertigotv_get_property (GObject * object, guint prop_id, GValue * value,
356     GParamSpec * pspec)
357 {
358   GstVertigoTV *filter;
359
360   g_return_if_fail (GST_IS_VERTIGOTV (object));
361
362   filter = GST_VERTIGOTV (object);
363
364   switch (prop_id) {
365     case ARG_SPEED:
366       g_value_set_float (value, filter->phase_increment);
367       break;
368     case ARG_ZOOM_SPEED:
369       g_value_set_float (value, filter->zoomrate);
370       break;
371     default:
372       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373       break;
374   }
375 }