controller: port to new controller location and api
[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  * SECTION:element-vertigotv
26  *
27  * VertigoTV is a loopback alpha blending effector with rotating and scaling.
28  *
29  * <refsect2>
30  * <title>Example launch line</title>
31  * |[
32  * gst-launch -v videotestsrc ! vertigotv ! videoconvert ! autovideosink
33  * ]| This pipeline shows the effect of vertigotv on a test stream.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <math.h>
42 #include <string.h>
43
44 #include "gstvertigo.h"
45
46 #define gst_vertigotv_parent_class parent_class
47 G_DEFINE_TYPE (GstVertigoTV, gst_vertigotv, GST_TYPE_VIDEO_FILTER);
48
49 /* Filter signals and args */
50 enum
51 {
52   PROP_0,
53   PROP_SPEED,
54   PROP_ZOOM_SPEED
55 };
56
57 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
58 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ RGBx, BGRx }")
59 #else
60 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR }")
61 #endif
62
63 static GstStaticPadTemplate gst_vertigotv_src_template =
64 GST_STATIC_PAD_TEMPLATE ("src",
65     GST_PAD_SRC,
66     GST_PAD_ALWAYS,
67     GST_STATIC_CAPS (CAPS_STR)
68     );
69
70 static GstStaticPadTemplate gst_vertigotv_sink_template =
71 GST_STATIC_PAD_TEMPLATE ("sink",
72     GST_PAD_SINK,
73     GST_PAD_ALWAYS,
74     GST_STATIC_CAPS (CAPS_STR)
75     );
76
77 static gboolean
78 gst_vertigotv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
79     GstCaps * outcaps)
80 {
81   GstVertigoTV *filter = GST_VERTIGOTV (btrans);
82   GstVideoInfo info;
83   gint area, width, height;
84
85   if (!gst_video_info_from_caps (&info, incaps))
86     goto invalid_caps;
87
88   filter->info = info;
89
90   width = GST_VIDEO_INFO_WIDTH (&info);
91   height = GST_VIDEO_INFO_HEIGHT (&info);
92
93   area = width * height;
94
95   g_free (filter->buffer);
96   filter->buffer = (guint32 *) g_malloc0 (area * 2 * sizeof (guint32));
97
98   filter->current_buffer = filter->buffer;
99   filter->alt_buffer = filter->buffer + area;
100   filter->phase = 0;
101
102   return TRUE;
103
104   /* ERRORS */
105 invalid_caps:
106   {
107     GST_DEBUG_OBJECT (filter, "invalid caps received");
108     return FALSE;
109   }
110 }
111
112 static void
113 gst_vertigotv_set_parms (GstVertigoTV * filter)
114 {
115   double vx, vy;
116   double t;
117   double x, y;
118   double dizz;
119   gint width, height;
120
121   dizz = sin (filter->phase) * 10 + sin (filter->phase * 1.9 + 5) * 5;
122
123   width = GST_VIDEO_INFO_WIDTH (&filter->info);
124   height = GST_VIDEO_INFO_HEIGHT (&filter->info);
125
126   x = width / 2;
127   y = height / 2;
128
129   t = (x * x + y * y) * filter->zoomrate;
130
131   if (width > height) {
132     if (dizz >= 0) {
133       if (dizz > x)
134         dizz = x;
135       vx = (x * (x - dizz) + y * y) / t;
136     } else {
137       if (dizz < -x)
138         dizz = -x;
139       vx = (x * (x + dizz) + y * y) / t;
140     }
141     vy = (dizz * y) / t;
142   } else {
143     if (dizz >= 0) {
144       if (dizz > y)
145         dizz = y;
146       vx = (x * x + y * (y - dizz)) / t;
147     } else {
148       if (dizz < -y)
149         dizz = -y;
150       vx = (x * x + y * (y + dizz)) / t;
151     }
152     vy = (dizz * x) / t;
153   }
154   filter->dx = vx * 65536;
155   filter->dy = vy * 65536;
156   filter->sx = (-vx * x + vy * y + x + cos (filter->phase * 5) * 2) * 65536;
157   filter->sy = (-vx * y - vy * x + y + sin (filter->phase * 6) * 2) * 65536;
158
159   filter->phase += filter->phase_increment;
160   if (filter->phase > 5700000)
161     filter->phase = 0;
162 }
163
164 static GstFlowReturn
165 gst_vertigotv_transform (GstBaseTransform * trans, GstBuffer * in,
166     GstBuffer * out)
167 {
168   GstVertigoTV *filter = GST_VERTIGOTV (trans);
169   guint32 *src, *dest, *p;
170   guint32 v;
171   gint x, y, ox, oy, i, width, height, area, sstride, dstride;
172   GstClockTime timestamp, stream_time;
173   GstVideoFrame in_frame, out_frame;
174
175   timestamp = GST_BUFFER_TIMESTAMP (in);
176   stream_time =
177       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
178
179   GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
180       GST_TIME_ARGS (timestamp));
181
182   if (GST_CLOCK_TIME_IS_VALID (stream_time))
183     gst_object_sync_values (GST_OBJECT (filter), stream_time);
184
185   if (!gst_video_frame_map (&in_frame, &filter->info, in, GST_MAP_READ))
186     goto invalid_in;
187
188   if (!gst_video_frame_map (&out_frame, &filter->info, out, GST_MAP_WRITE))
189     goto invalid_out;
190
191   src = GST_VIDEO_FRAME_PLANE_DATA (&in_frame, 0);
192   sstride = GST_VIDEO_FRAME_PLANE_STRIDE (&in_frame, 0);
193   dest = GST_VIDEO_FRAME_PLANE_DATA (&out_frame, 0);
194   dstride = GST_VIDEO_FRAME_PLANE_STRIDE (&out_frame, 0);
195
196   width = GST_VIDEO_FRAME_WIDTH (&in_frame);
197   height = GST_VIDEO_FRAME_HEIGHT (&in_frame);
198
199   area = width * height;
200
201   sstride /= 4;
202   dstride /= 4;
203
204   gst_vertigotv_set_parms (filter);
205   p = filter->alt_buffer;
206
207   for (y = 0; y < height; y++) {
208     ox = filter->sx;
209     oy = filter->sy;
210
211     for (x = 0; x < width; x++) {
212       i = (oy >> 16) * width + (ox >> 16);
213       if (i < 0)
214         i = 0;
215       if (i >= area)
216         i = area;
217
218       v = filter->current_buffer[i] & 0xfcfcff;
219       v = (v * 3) + (src[x] & 0xfcfcff);
220
221       *p++ = dest[x] = (v >> 2);
222       ox += filter->dx;
223       oy += filter->dy;
224     }
225     filter->sx -= filter->dy;
226     filter->sy += filter->dx;
227
228     src += sstride;
229     dest += dstride;
230   }
231
232   p = filter->current_buffer;
233   filter->current_buffer = filter->alt_buffer;
234   filter->alt_buffer = p;
235
236   return GST_FLOW_OK;
237
238   /* ERRORS */
239 invalid_in:
240   {
241     GST_DEBUG_OBJECT (filter, "invalid input frame");
242     return GST_FLOW_ERROR;
243   }
244 invalid_out:
245   {
246     GST_DEBUG_OBJECT (filter, "invalid output frame");
247     gst_video_frame_unmap (&in_frame);
248     return GST_FLOW_ERROR;
249   }
250
251 }
252
253 static gboolean
254 gst_vertigotv_start (GstBaseTransform * trans)
255 {
256   GstVertigoTV *filter = GST_VERTIGOTV (trans);
257
258   filter->phase = 0.0;
259
260   return TRUE;
261 }
262
263 static void
264 gst_vertigotv_set_property (GObject * object, guint prop_id,
265     const GValue * value, GParamSpec * pspec)
266 {
267   GstVertigoTV *filter = GST_VERTIGOTV (object);
268
269   GST_OBJECT_LOCK (filter);
270   switch (prop_id) {
271     case PROP_SPEED:
272       filter->phase_increment = g_value_get_float (value);
273       break;
274     case PROP_ZOOM_SPEED:
275       filter->zoomrate = g_value_get_float (value);
276       break;
277     default:
278       break;
279   }
280   GST_OBJECT_UNLOCK (filter);
281 }
282
283 static void
284 gst_vertigotv_get_property (GObject * object, guint prop_id, GValue * value,
285     GParamSpec * pspec)
286 {
287   GstVertigoTV *filter = GST_VERTIGOTV (object);
288
289   switch (prop_id) {
290     case PROP_SPEED:
291       g_value_set_float (value, filter->phase_increment);
292       break;
293     case PROP_ZOOM_SPEED:
294       g_value_set_float (value, filter->zoomrate);
295       break;
296     default:
297       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
298       break;
299   }
300 }
301
302 static void
303 gst_vertigotv_finalize (GObject * object)
304 {
305   GstVertigoTV *filter = GST_VERTIGOTV (object);
306
307   g_free (filter->buffer);
308   filter->buffer = NULL;
309
310   G_OBJECT_CLASS (parent_class)->finalize (object);
311 }
312
313 static void
314 gst_vertigotv_class_init (GstVertigoTVClass * klass)
315 {
316   GObjectClass *gobject_class = (GObjectClass *) klass;
317   GstElementClass *gstelement_class = (GstElementClass *) klass;
318   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
319
320   gobject_class->set_property = gst_vertigotv_set_property;
321   gobject_class->get_property = gst_vertigotv_get_property;
322   gobject_class->finalize = gst_vertigotv_finalize;
323
324   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SPEED,
325       g_param_spec_float ("speed", "Speed", "Control the speed of movement",
326           0.01, 100.0, 0.02, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ZOOM_SPEED,
328       g_param_spec_float ("zoom-speed", "Zoom Speed",
329           "Control the rate of zooming", 1.01, 1.1, 1.01,
330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
331
332   gst_element_class_set_details_simple (gstelement_class, "VertigoTV effect",
333       "Filter/Effect/Video",
334       "A loopback alpha blending effector with rotating and scaling",
335       "Wim Taymans <wim.taymans@gmail.be>");
336
337   gst_element_class_add_pad_template (gstelement_class,
338       gst_static_pad_template_get (&gst_vertigotv_sink_template));
339   gst_element_class_add_pad_template (gstelement_class,
340       gst_static_pad_template_get (&gst_vertigotv_src_template));
341
342   trans_class->start = GST_DEBUG_FUNCPTR (gst_vertigotv_start);
343   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_vertigotv_set_caps);
344   trans_class->transform = GST_DEBUG_FUNCPTR (gst_vertigotv_transform);
345 }
346
347 static void
348 gst_vertigotv_init (GstVertigoTV * filter)
349 {
350   filter->buffer = NULL;
351   filter->phase = 0.0;
352   filter->phase_increment = 0.02;
353   filter->zoomrate = 1.01;
354
355   gst_pad_use_fixed_caps (GST_BASE_TRANSFORM_SRC_PAD (filter));
356   gst_pad_use_fixed_caps (GST_BASE_TRANSFORM_SINK_PAD (filter));
357 }