+ checking in plugin category changes
[platform/upstream/gst-plugins-good.git] / gst / effectv / gstrev.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 - Realtime Digital Video Effector
8  * Copyright (C) 2001 FUKUCHI Kentarou
9  *
10  * revTV based on Rutt-Etra Video Synthesizer 1974?
11
12  * (c)2002 Ed Tannenbaum
13  *
14  * This effect acts like a waveform monitor on each line.
15  * It was originally done by deflecting the electron beam on a monitor using
16  * additional electromagnets on the yoke of a b/w CRT. 
17  * Here it is emulated digitally.
18
19  * Experimaental tapes were made with this system by Bill and 
20  * Louise Etra and Woody and Steina Vasulka
21
22  * The line spacing can be controlled using the 1 and 2 Keys.
23  * The gain is controlled using the 3 and 4 keys.
24  * The update rate is controlled using the 0 and - keys.
25  
26  * EffecTV is free software. This library is free software;
27  * you can redistribute it and/or
28  * modify it under the terms of the GNU Library General Public
29  * License as published by the Free Software Foundation; either
30  * version 2 of the License, or (at your option) any later version.
31  *
32  * This library is distributed in the hope that it will be useful,
33  * but WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
35  * Library General Public License for more details.
36  *
37  * You should have received a copy of the GNU Library General Public
38  * License along with this library; if not, write to the
39  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
40  * Boston, MA 02111-1307, USA.
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 #include <math.h>
47 #include <string.h>
48 #include <gst/gst.h>
49 #include "gsteffectv.h"
50
51 #define GST_TYPE_REVTV \
52   (gst_revtv_get_type())
53 #define GST_REVTV(obj) \
54   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_REVTV,GstRevTV))
55 #define GST_REVTV_CLASS(klass) \
56   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstRevTV))
57 #define GST_IS_REVTV(obj) \
58   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_REVTV))
59 #define GST_IS_REVTV_CLASS(obj) \
60   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_REVTV))
61
62 #define THE_COLOR 0xffffffff
63
64 typedef struct _GstRevTV GstRevTV;
65 typedef struct _GstRevTVClass GstRevTVClass;
66
67 struct _GstRevTV
68 {
69   GstElement element;
70
71   GstPad *sinkpad, *srcpad;
72
73   gint width, height;
74   gint vgrabtime;
75   gint vgrab;
76   gint linespace;
77   gint vscale;
78 };
79
80 struct _GstRevTVClass
81 {
82   GstElementClass parent_class;
83
84   void (*reset) (GstElement *element);
85 };
86
87 /* elementfactory information */
88 static GstElementDetails gst_revtv_details = GST_ELEMENT_DETAILS (
89   "RevTV",
90   "Filter/Effect/Video",
91   "A video waveform monitor for each line of video processed",
92   "Wim Taymans <wim.taymans@chello.be>"
93 );
94
95
96 /* Filter signals and args */
97 enum
98 {
99   /* FILL ME */
100   LAST_SIGNAL
101 };
102
103 enum
104 {
105   ARG_0,
106   ARG_DELAY,
107   ARG_LINESPACE,
108   ARG_GAIN,
109 };
110
111 static void     gst_revtv_base_init             (gpointer g_class);
112 static void     gst_revtv_class_init            (GstRevTVClass * klass);
113 static void     gst_revtv_init                  (GstRevTV * filter);
114
115 static void     gst_revtv_set_property          (GObject * object, guint prop_id,
116                                                  const GValue * value, GParamSpec * pspec);
117 static void     gst_revtv_get_property          (GObject * object, guint prop_id,
118                                                  GValue * value, GParamSpec * pspec);
119
120 static void     gst_revtv_chain                 (GstPad * pad, GstData *_data);
121
122 static GstElementClass *parent_class = NULL;
123 /* static guint gst_revtv_signals[LAST_SIGNAL] = { 0 }; */
124
125 GType gst_revtv_get_type (void)
126 {
127   static GType revtv_type = 0;
128
129   if (!revtv_type) {
130     static const GTypeInfo revtv_info = {
131       sizeof (GstRevTVClass), 
132       gst_revtv_base_init,
133       NULL,
134       (GClassInitFunc) gst_revtv_class_init,
135       NULL,
136       NULL,
137       sizeof (GstRevTV),
138       0,
139       (GInstanceInitFunc) gst_revtv_init,
140     };
141
142     revtv_type = g_type_register_static (GST_TYPE_ELEMENT, "GstRevTV", &revtv_info, 0);
143   }
144   return revtv_type;
145 }
146
147 static void
148 gst_revtv_base_init (gpointer g_class)
149 {
150   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
151
152   gst_element_class_add_pad_template (element_class, gst_effectv_src_factory ());
153   gst_element_class_add_pad_template (element_class, gst_effectv_sink_factory ());
154  
155   gst_element_class_set_details (element_class, &gst_revtv_details);
156 }
157
158 static void
159 gst_revtv_class_init (GstRevTVClass * klass)
160 {
161   GObjectClass *gobject_class;
162   GstElementClass *gstelement_class;
163
164   gobject_class = (GObjectClass *) klass;
165   gstelement_class = (GstElementClass *) klass;
166
167   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
168
169   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DELAY,
170     g_param_spec_int ("delay","Delay","Delay in frames between updates",
171                         1, 100, 1, G_PARAM_READWRITE));
172   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LINESPACE,
173     g_param_spec_int ("linespace","Linespace","Control line spacing",
174                         1, 100, 6, G_PARAM_READWRITE));
175   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GAIN,
176     g_param_spec_int ("gain","Gain","Control gain",
177                         1, 200, 50, G_PARAM_READWRITE));
178
179   gobject_class->set_property = gst_revtv_set_property;
180   gobject_class->get_property = gst_revtv_get_property;
181 }
182
183 static GstPadLinkReturn
184 gst_revtv_sinkconnect (GstPad * pad, GstCaps * caps)
185 {
186   GstRevTV *filter;
187
188   filter = GST_REVTV (gst_pad_get_parent (pad));
189
190   if (!GST_CAPS_IS_FIXED (caps))
191     return GST_PAD_LINK_DELAYED;
192
193   gst_caps_get_int (caps, "width", &filter->width);
194   gst_caps_get_int (caps, "height", &filter->height);
195
196   return gst_pad_try_set_caps (filter->srcpad, gst_caps_ref (caps));
197 }
198
199 static void
200 gst_revtv_init (GstRevTV * filter)
201 {
202   filter->sinkpad = gst_pad_new_from_template (gst_effectv_sink_factory (), "sink");
203   gst_pad_set_chain_function (filter->sinkpad, gst_revtv_chain);
204   gst_pad_set_link_function (filter->sinkpad, gst_revtv_sinkconnect);
205   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
206
207   filter->srcpad = gst_pad_new_from_template (gst_effectv_src_factory (), "src");
208   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
209
210   filter->vgrabtime = 1;
211   filter->vgrab = 0;
212   filter->linespace = 6;
213   filter->vscale = 50;
214 }
215
216
217 static void
218 gst_revtv_chain (GstPad * pad, GstData *_data)
219 {
220   GstBuffer *buf = GST_BUFFER (_data);
221   GstRevTV *filter;
222   guint32 *src, *dest;
223   GstBuffer *outbuf;
224   gint width, height, area;
225   guint32 *nsrc;
226   gint y, x, R, G, B, yval;
227
228   filter = GST_REVTV (gst_pad_get_parent (pad));
229
230   src = (guint32 *) GST_BUFFER_DATA (buf);
231
232   width = filter->width;
233   height = filter->height;
234   area = width * height;
235
236   outbuf = gst_buffer_new ();
237   GST_BUFFER_SIZE (outbuf) = area * sizeof(guint32);
238   dest = (guint32 *) GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
239   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
240
241   // draw the offset lines
242   for (y = 0; y < height ; y += filter->linespace){
243     for (x = 0; x <= width; x++) {
244       nsrc = src + (y * width) + x;
245
246       // Calc Y Value for curpix
247       R = ((*nsrc) & 0xff0000) >> (16 - 1);
248       G = ((*nsrc) & 0xff00) >> (8 - 2);
249       B =  (*nsrc) & 0xff;
250
251       yval = y - ((short) (R + G + B) / filter->vscale) ;
252
253       if (yval > 0) {
254         dest[x + (yval * width)] = THE_COLOR;
255       }
256     }
257   }
258   
259   gst_buffer_unref (buf);
260
261   gst_pad_push (filter->srcpad, GST_DATA (outbuf));
262 }
263
264 static void
265 gst_revtv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
266 {
267   GstRevTV *filter;
268
269   /* it's not null if we got it, but it might not be ours */
270   g_return_if_fail (GST_IS_REVTV (object));
271
272   filter = GST_REVTV (object);
273
274   switch (prop_id) {
275     case ARG_DELAY:
276       filter->vgrabtime = g_value_get_int (value);
277       break;
278     case ARG_LINESPACE:
279       filter->linespace = g_value_get_int (value);
280       break;
281     case ARG_GAIN:
282       filter->vscale = g_value_get_int (value);
283       break;
284     default:
285       break;
286   }
287 }
288
289 static void
290 gst_revtv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
291 {
292   GstRevTV *filter;
293
294   /* it's not null if we got it, but it might not be ours */
295   g_return_if_fail (GST_IS_REVTV (object));
296
297   filter = GST_REVTV (object);
298
299   switch (prop_id) {
300     case ARG_DELAY:
301       g_value_set_int (value, filter->vgrabtime);
302       break;
303     case ARG_LINESPACE:
304       g_value_set_int (value, filter->linespace);
305       break;
306     case ARG_GAIN:
307       g_value_set_int (value, filter->vscale);
308       break;
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312   }
313 }