1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 *
4 * EffecTV:
5 * Copyright (C) 2001 FUKUCHI Kentarou
6 *
7 * Inspired by Adrian Likin's script for the GIMP.
8 * EffecTV is free software. This library is free software;
9 * you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 /**
26 * SECTION:element-shagadelictv
27 * @title: shagadelictv
28 *
29 * Oh behave, ShagedelicTV makes images shagadelic!
30 *
31 * ## Example launch line
32 * |[
33 * gst-launch-1.0 -v videotestsrc ! shagadelictv ! videoconvert ! autovideosink
34 * ]| This pipeline shows the effect of shagadelictv on a test stream.
35 *
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <math.h>
43 #include <string.h>
44
45 #include "gstshagadelic.h"
46 #include "gsteffectv.h"
47
48 #ifndef M_PI
49 #define M_PI 3.14159265358979323846
50 #endif
51
52 #define gst_shagadelictv_parent_class parent_class
53 G_DEFINE_TYPE (GstShagadelicTV, gst_shagadelictv, GST_TYPE_VIDEO_FILTER);
54 GST_ELEMENT_REGISTER_DEFINE (shagadelictv, "shagadelictv",
55 GST_RANK_NONE, GST_TYPE_SHAGADELICTV);
56
57 static void gst_shagadelic_initialize (GstShagadelicTV * filter,
58 GstVideoInfo * in_info);
59
60 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
61 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("BGRx")
62 #else
63 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("xRGB")
64 #endif
65
66 static GstStaticPadTemplate gst_shagadelictv_src_template =
67 GST_STATIC_PAD_TEMPLATE ("src",
68 GST_PAD_SRC,
69 GST_PAD_ALWAYS,
70 GST_STATIC_CAPS (CAPS_STR)
71 );
72
73 static GstStaticPadTemplate gst_shagadelictv_sink_template =
74 GST_STATIC_PAD_TEMPLATE ("sink",
75 GST_PAD_SINK,
76 GST_PAD_ALWAYS,
77 GST_STATIC_CAPS (CAPS_STR)
78 );
79
80 static gboolean
gst_shagadelictv_set_info(GstVideoFilter * vfilter,GstCaps * incaps,GstVideoInfo * in_info,GstCaps * outcaps,GstVideoInfo * out_info)81 gst_shagadelictv_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
82 GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
83 {
84 GstShagadelicTV *filter = GST_SHAGADELICTV (vfilter);
85 gint width, height, area;
86
87 width = GST_VIDEO_INFO_WIDTH (in_info);
88 height = GST_VIDEO_INFO_HEIGHT (in_info);
89
90 area = width * height;
91
92 g_free (filter->ripple);
93 g_free (filter->spiral);
94 filter->ripple = (guint8 *) g_malloc (area * 4);
95 filter->spiral = (guint8 *) g_malloc (area);
96
97 gst_shagadelic_initialize (filter, in_info);
98
99 return TRUE;
100 }
101
102 static void
gst_shagadelic_initialize(GstShagadelicTV * filter,GstVideoInfo * info)103 gst_shagadelic_initialize (GstShagadelicTV * filter, GstVideoInfo * info)
104 {
105 int i, x, y;
106 #ifdef PS2
107 float xx, yy;
108 #else
109 double xx, yy;
110 #endif
111 gint width, height;
112
113 width = GST_VIDEO_INFO_WIDTH (info);
114 height = GST_VIDEO_INFO_HEIGHT (info);
115
116 i = 0;
117 for (y = 0; y < height * 2; y++) {
118 yy = y - height;
119 yy *= yy;
120
121 for (x = 0; x < width * 2; x++) {
122 xx = x - width;
123 #ifdef PS2
124 filter->ripple[i++] = ((unsigned int) (sqrtf (xx * xx + yy) * 8)) & 255;
125 #else
126 filter->ripple[i++] = ((unsigned int) (sqrt (xx * xx + yy) * 8)) & 255;
127 #endif
128 }
129 }
130
131 i = 0;
132 for (y = 0; y < height; y++) {
133 yy = y - height / 2;
134
135 for (x = 0; x < width; x++) {
136 xx = x - width / 2;
137 #ifdef PS2
138 filter->spiral[i++] = ((unsigned int)
139 ((atan2f (xx,
140 yy) / ((float) M_PI) * 256 * 9) + (sqrtf (xx * xx +
141 yy * yy) * 5))) & 255;
142 #else
143 filter->spiral[i++] = ((unsigned int)
144 ((atan2 (xx, yy) / M_PI * 256 * 9) + (sqrt (xx * xx +
145 yy * yy) * 5))) & 255;
146 #endif
147 /* Here is another Swinger!
148 * ((atan2(xx, yy)/M_PI*256) + (sqrt(xx*xx+yy*yy)*10))&255;
149 */
150 }
151 }
152 filter->rx = fastrand () % width;
153 filter->ry = fastrand () % height;
154 filter->bx = fastrand () % width;
155 filter->by = fastrand () % height;
156 filter->rvx = -2;
157 filter->rvy = -2;
158 filter->bvx = 2;
159 filter->bvy = 2;
160 filter->phase = 0;
161 }
162
163 static GstFlowReturn
gst_shagadelictv_transform_frame(GstVideoFilter * vfilter,GstVideoFrame * in_frame,GstVideoFrame * out_frame)164 gst_shagadelictv_transform_frame (GstVideoFilter * vfilter,
165 GstVideoFrame * in_frame, GstVideoFrame * out_frame)
166 {
167 GstShagadelicTV *filter = GST_SHAGADELICTV (vfilter);
168 guint32 *src, *dest;
169 gint x, y;
170 guint32 v;
171 guint8 r, g, b;
172 gint width, height;
173
174 src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
175 dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
176
177 width = GST_VIDEO_FRAME_WIDTH (in_frame);
178 height = GST_VIDEO_FRAME_HEIGHT (in_frame);
179
180 for (y = 0; y < height; y++) {
181 for (x = 0; x < width; x++) {
182 v = *src++ | 0x1010100;
183 v = (v - 0x707060) & 0x1010100;
184 v -= v >> 8;
185 /* Try another Babe!
186 * v = *src++;
187 * *dest++ = v & ((r<<16)|(g<<8)|b);
188 */
189 r = ((gint8) (filter->ripple[(filter->ry + y) * width * 2 + filter->rx +
190 x] + filter->phase * 2)) >> 7;
191 g = ((gint8) (filter->spiral[y * width + x] + filter->phase * 3)) >> 7;
192 b = ((gint8) (filter->ripple[(filter->by + y) * width * 2 + filter->bx +
193 x] - filter->phase)) >> 7;
194 *dest++ = v & ((r << 16) | (g << 8) | b);
195 }
196 }
197
198 filter->phase -= 8;
199 if ((filter->rx + filter->rvx) < 0 || (filter->rx + filter->rvx) >= width)
200 filter->rvx = -filter->rvx;
201 if ((filter->ry + filter->rvy) < 0 || (filter->ry + filter->rvy) >= height)
202 filter->rvy = -filter->rvy;
203 if ((filter->bx + filter->bvx) < 0 || (filter->bx + filter->bvx) >= width)
204 filter->bvx = -filter->bvx;
205 if ((filter->by + filter->bvy) < 0 || (filter->by + filter->bvy) >= height)
206 filter->bvy = -filter->bvy;
207 filter->rx += filter->rvx;
208 filter->ry += filter->rvy;
209 filter->bx += filter->bvx;
210 filter->by += filter->bvy;
211
212 return GST_FLOW_OK;
213 }
214
215 static void
gst_shagadelictv_finalize(GObject * object)216 gst_shagadelictv_finalize (GObject * object)
217 {
218 GstShagadelicTV *filter = GST_SHAGADELICTV (object);
219
220 g_free (filter->ripple);
221 filter->ripple = NULL;
222
223 g_free (filter->spiral);
224 filter->spiral = NULL;
225
226 G_OBJECT_CLASS (parent_class)->finalize (object);
227 }
228
229 static void
gst_shagadelictv_class_init(GstShagadelicTVClass * klass)230 gst_shagadelictv_class_init (GstShagadelicTVClass * klass)
231 {
232 GObjectClass *gobject_class = (GObjectClass *) klass;
233 GstElementClass *gstelement_class = (GstElementClass *) klass;
234 GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
235
236 gobject_class->finalize = gst_shagadelictv_finalize;
237
238 gst_element_class_set_static_metadata (gstelement_class, "ShagadelicTV",
239 "Filter/Effect/Video",
240 "Oh behave, ShagedelicTV makes images shagadelic!",
241 "Wim Taymans <wim.taymans@chello.be>");
242
243 gst_element_class_add_static_pad_template (gstelement_class,
244 &gst_shagadelictv_sink_template);
245 gst_element_class_add_static_pad_template (gstelement_class,
246 &gst_shagadelictv_src_template);
247
248 vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_shagadelictv_set_info);
249 vfilter_class->transform_frame =
250 GST_DEBUG_FUNCPTR (gst_shagadelictv_transform_frame);
251 }
252
253 static void
gst_shagadelictv_init(GstShagadelicTV * filter)254 gst_shagadelictv_init (GstShagadelicTV * filter)
255 {
256 filter->ripple = NULL;
257 filter->spiral = NULL;
258 }
259