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., 51 Franklin St, Fifth Floor,
40  * Boston, MA 02110-1301, USA.
41  */
42 
43 /**
44  * SECTION:element-revtv
45  *
46  * RevTV acts like a video waveform monitor for each line of video
47  * processed. This creates a pseudo 3D effect based on the brightness
48  * of the video along each line.
49  *
50  * <refsect2>
51  * <title>Example launch line</title>
52  * |[
53  * gst-launch-1.0 -v videotestsrc ! revtv ! videoconvert ! autovideosink
54  * ]| This pipeline shows the effect of revtv on a test stream.
55  * </refsect2>
56  */
57 
58 #ifdef HAVE_CONFIG_H
59 #include "config.h"
60 #endif
61 
62 #include <math.h>
63 #include <string.h>
64 
65 #include "gstrev.h"
66 
67 #define THE_COLOR 0xffffffff
68 
69 enum
70 {
71   PROP_0,
72   PROP_DELAY,
73   PROP_LINESPACE,
74   PROP_GAIN
75 };
76 
77 #define gst_revtv_parent_class parent_class
78 G_DEFINE_TYPE (GstRevTV, gst_revtv, GST_TYPE_VIDEO_FILTER);
79 
80 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
81 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx }")
82 #else
83 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xBGR, xRGB }")
84 #endif
85 
86 static GstStaticPadTemplate gst_revtv_src_template =
87 GST_STATIC_PAD_TEMPLATE ("src",
88     GST_PAD_SRC,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS (CAPS_STR)
91     );
92 
93 static GstStaticPadTemplate gst_revtv_sink_template =
94 GST_STATIC_PAD_TEMPLATE ("sink",
95     GST_PAD_SINK,
96     GST_PAD_ALWAYS,
97     GST_STATIC_CAPS (CAPS_STR)
98     );
99 
100 static GstFlowReturn
gst_revtv_transform_frame(GstVideoFilter * vfilter,GstVideoFrame * in_frame,GstVideoFrame * out_frame)101 gst_revtv_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame,
102     GstVideoFrame * out_frame)
103 {
104   GstRevTV *filter = GST_REVTV (vfilter);
105   guint32 *src, *dest;
106   gint width, height, sstride, dstride;
107   guint32 *nsrc;
108   gint y, x, R, G, B, yval;
109   gint linespace, vscale;
110   GstClockTime timestamp, stream_time;
111 
112   timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
113   stream_time =
114       gst_segment_to_stream_time (&GST_BASE_TRANSFORM (vfilter)->segment,
115       GST_FORMAT_TIME, timestamp);
116 
117   GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
118       GST_TIME_ARGS (timestamp));
119 
120   if (GST_CLOCK_TIME_IS_VALID (stream_time))
121     gst_object_sync_values (GST_OBJECT (filter), stream_time);
122 
123   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
124   sstride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
125   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
126   dstride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
127 
128   width = GST_VIDEO_FRAME_WIDTH (in_frame);
129   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
130 
131   /* Clear everything to black */
132   memset (dest, 0, dstride * height);
133 
134   GST_OBJECT_LOCK (filter);
135   linespace = filter->linespace;
136   vscale = filter->vscale;
137 
138   /* draw the offset lines */
139   for (y = 0; y < height; y += linespace) {
140     for (x = 0; x <= width; x++) {
141       nsrc = src + (y * sstride / 4) + x;
142 
143       /* Calc Y Value for curpix */
144       R = ((*nsrc) & 0xff0000) >> (16 - 1);
145       G = ((*nsrc) & 0xff00) >> (8 - 2);
146       B = (*nsrc) & 0xff;
147 
148       yval = y - ((short) (R + G + B) / vscale);
149 
150       if (yval > 0) {
151         dest[x + (yval * dstride / 4)] = THE_COLOR;
152       }
153     }
154   }
155   GST_OBJECT_UNLOCK (filter);
156 
157   return GST_FLOW_OK;
158 }
159 
160 static void
gst_revtv_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)161 gst_revtv_set_property (GObject * object, guint prop_id, const GValue * value,
162     GParamSpec * pspec)
163 {
164   GstRevTV *filter = GST_REVTV (object);
165 
166   GST_OBJECT_LOCK (filter);
167   switch (prop_id) {
168     case PROP_DELAY:
169       filter->vgrabtime = g_value_get_int (value);
170       break;
171     case PROP_LINESPACE:
172       filter->linespace = g_value_get_int (value);
173       break;
174     case PROP_GAIN:
175       filter->vscale = g_value_get_int (value);
176       break;
177     default:
178       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179       break;
180   }
181   GST_OBJECT_UNLOCK (filter);
182 }
183 
184 static void
gst_revtv_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)185 gst_revtv_get_property (GObject * object, guint prop_id, GValue * value,
186     GParamSpec * pspec)
187 {
188   GstRevTV *filter = GST_REVTV (object);
189 
190   switch (prop_id) {
191     case PROP_DELAY:
192       g_value_set_int (value, filter->vgrabtime);
193       break;
194     case PROP_LINESPACE:
195       g_value_set_int (value, filter->linespace);
196       break;
197     case PROP_GAIN:
198       g_value_set_int (value, filter->vscale);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202       break;
203   }
204 }
205 
206 static void
gst_revtv_class_init(GstRevTVClass * klass)207 gst_revtv_class_init (GstRevTVClass * klass)
208 {
209   GObjectClass *gobject_class = (GObjectClass *) klass;
210   GstElementClass *gstelement_class = (GstElementClass *) klass;
211   GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
212 
213   gobject_class->set_property = gst_revtv_set_property;
214   gobject_class->get_property = gst_revtv_get_property;
215 
216   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELAY,
217       g_param_spec_int ("delay", "Delay", "Delay in frames between updates",
218           1, 100, 1,
219           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
220   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINESPACE,
221       g_param_spec_int ("linespace", "Linespace", "Control line spacing", 1,
222           100, 6,
223           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
224   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GAIN,
225       g_param_spec_int ("gain", "Gain", "Control gain", 1, 200, 50,
226           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
227 
228   gst_element_class_set_static_metadata (gstelement_class, "RevTV effect",
229       "Filter/Effect/Video",
230       "A video waveform monitor for each line of video processed",
231       "Wim Taymans <wim.taymans@gmail.be>");
232 
233   gst_element_class_add_static_pad_template (gstelement_class,
234       &gst_revtv_sink_template);
235   gst_element_class_add_static_pad_template (gstelement_class,
236       &gst_revtv_src_template);
237 
238   vfilter_class->transform_frame =
239       GST_DEBUG_FUNCPTR (gst_revtv_transform_frame);
240 }
241 
242 static void
gst_revtv_init(GstRevTV * restv)243 gst_revtv_init (GstRevTV * restv)
244 {
245   restv->vgrabtime = 1;
246   restv->vgrab = 0;
247   restv->linespace = 6;
248   restv->vscale = 50;
249 }
250