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