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