97bef9006cb48baf2ecf15fc5eff810fccfe6c79
[platform/upstream/gstreamer.git] / gst / effectv / gstaging.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  *
5  * EffecTV - Realtime Digital Video Effector
6  * Copyright (C) 2001 FUKUCHI Kentarou
7  *
8  * This library is free software; 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  * This file was (probably) generated from gstvideotemplate.c,
26  * gstvideotemplate.c,v 1.11 2004/01/07 08:56:45 ds Exp 
27  */
28
29 /* From main.c of warp-1.1:
30  *
31  *      Simple DirectMedia Layer demo
32  *      Realtime picture 'gooing'
33  *      by sam lantinga slouken@devolution.com
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <gst/gst.h>
41 #include <gstvideofilter.h>
42 #include <string.h>
43 #include <math.h>
44
45 #define GST_TYPE_AGINGTV \
46   (gst_agingtv_get_type())
47 #define GST_AGINGTV(obj) \
48   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGINGTV,GstAgingTV))
49 #define GST_AGINGTV_CLASS(klass) \
50   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGINGTV,GstAgingTVClass))
51 #define GST_IS_AGINGTV(obj) \
52   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGINGTV))
53 #define GST_IS_AGINGTV_CLASS(obj) \
54   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGINGTV))
55
56 #define SCRATCH_MAX 20
57 typedef struct _scratch
58 {
59   gint life;
60   gint x;
61   gint dx;
62   gint init;
63 }
64 scratch;
65
66 static int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
67 static int dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
68
69 typedef struct _GstAgingTV GstAgingTV;
70 typedef struct _GstAgingTVClass GstAgingTVClass;
71
72 struct _GstAgingTV
73 {
74   GstVideofilter videofilter;
75
76   gint width, height;
77   gint aging_mode;
78
79   scratch scratches[SCRATCH_MAX];
80   gint scratch_lines;
81
82   gint dust_interval;
83   gint pits_interval;
84
85 };
86
87 struct _GstAgingTVClass
88 {
89   GstVideofilterClass parent_class;
90 };
91
92 /* GstAgingTV signals and args */
93 enum
94 {
95   /* FILL ME */
96   LAST_SIGNAL
97 };
98
99 enum
100 {
101   ARG_0
102       /* FILL ME */
103 };
104
105 static void gst_agingtv_base_init (gpointer g_class);
106 static void gst_agingtv_class_init (gpointer g_class, gpointer class_data);
107 static void gst_agingtv_init (GTypeInstance * instance, gpointer g_class);
108 static void gst_agingtv_setup (GstVideofilter * videofilter);
109
110 static void gst_agingtv_set_property (GObject * object, guint prop_id,
111     const GValue * value, GParamSpec * pspec);
112 static void gst_agingtv_get_property (GObject * object, guint prop_id,
113     GValue * value, GParamSpec * pspec);
114 static void gst_agingtv_rgb32 (GstVideofilter * videofilter, void *d, void *s);
115
116 GType
117 gst_agingtv_get_type (void)
118 {
119   static GType agingtv_type = 0;
120
121   if (!agingtv_type) {
122     static const GTypeInfo agingtv_info = {
123       sizeof (GstAgingTVClass),
124       gst_agingtv_base_init,
125       NULL,
126       gst_agingtv_class_init,
127       NULL,
128       NULL,
129       sizeof (GstAgingTV),
130       0,
131       gst_agingtv_init,
132     };
133
134     agingtv_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
135         "GstAgingTV", &agingtv_info, 0);
136   }
137   return agingtv_type;
138 }
139
140 static GstVideofilterFormat gst_agingtv_formats[] = {
141   {"RGB ", 32, gst_agingtv_rgb32, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000,
142       0xff000000}
143 };
144
145 static void
146 gst_agingtv_base_init (gpointer g_class)
147 {
148   static GstElementDetails agingtv_details = GST_ELEMENT_DETAILS ("AgingTV",
149       "Filter/Effect/Video",
150       "AgingTV adds age to video input using scratches and dust",
151       "Sam Lantinga <slouken@devolution.com>");
152   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
153   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
154   int i;
155
156   gst_element_class_set_details (element_class, &agingtv_details);
157
158   for (i = 0; i < G_N_ELEMENTS (gst_agingtv_formats); i++) {
159     gst_videofilter_class_add_format (videofilter_class,
160         gst_agingtv_formats + i);
161   }
162
163   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
164 }
165
166 static void
167 gst_agingtv_class_init (gpointer g_class, gpointer class_data)
168 {
169   GObjectClass *gobject_class;
170   GstVideofilterClass *videofilter_class;
171
172   gobject_class = G_OBJECT_CLASS (g_class);
173   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
174
175   gobject_class->set_property = gst_agingtv_set_property;
176   gobject_class->get_property = gst_agingtv_get_property;
177
178 #if 0
179   g_object_class_install_property (gobject_class, ARG_METHOD,
180       g_param_spec_enum ("method", "method", "method",
181           GST_TYPE_AGINGTV_METHOD, GST_AGINGTV_METHOD_1, G_PARAM_READWRITE));
182 #endif
183
184   videofilter_class->setup = gst_agingtv_setup;
185 }
186
187 static void
188 gst_agingtv_init (GTypeInstance * instance, gpointer g_class)
189 {
190   GstAgingTV *agingtv = GST_AGINGTV (instance);
191   GstVideofilter *videofilter;
192
193   GST_DEBUG ("gst_agingtv_init");
194
195   videofilter = GST_VIDEOFILTER (agingtv);
196
197   /* do stuff */
198 }
199
200 static void
201 gst_agingtv_setup (GstVideofilter * videofilter)
202 {
203   GstAgingTV *agingtv;
204   int width = gst_videofilter_get_input_width (videofilter);
205   int height = gst_videofilter_get_input_height (videofilter);
206
207   g_return_if_fail (GST_IS_AGINGTV (videofilter));
208   agingtv = GST_AGINGTV (videofilter);
209
210   /* if any setup needs to be done, do it here */
211
212   agingtv->width = width;
213   agingtv->height = height;
214 }
215
216 static unsigned int
217 fastrand (void)
218 {
219   static unsigned int fastrand_val;
220
221   return (fastrand_val = fastrand_val * 1103515245 + 12345);
222 }
223
224
225 static void
226 coloraging (guint32 * src, guint32 * dest, gint video_area)
227 {
228   guint32 a, b;
229   gint i;
230
231   for (i = video_area; i; i--) {
232     a = *src++;
233     b = (a & 0xfcfcfc) >> 2;
234     *dest++ = a - b + 0x181818 + ((fastrand () >> 8) & 0x101010);
235   }
236 }
237
238
239 static void
240 scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
241     gint height)
242 {
243   gint i, y, y1, y2;
244   guint32 *p, a, b;
245   scratch *scratch;
246
247   for (i = 0; i < scratch_lines; i++) {
248     scratch = &scratches[i];
249
250     if (scratch->life) {
251       scratch->x = scratch->x + scratch->dx;
252
253       if (scratch->x < 0 || scratch->x > width * 256) {
254         scratch->life = 0;
255         break;
256       }
257       p = dest + (scratch->x >> 8);
258       if (scratch->init) {
259         y1 = scratch->init;
260         scratch->init = 0;
261       } else {
262         y1 = 0;
263       }
264       scratch->life--;
265       if (scratch->life) {
266         y2 = height;
267       } else {
268         y2 = fastrand () % height;
269       }
270       for (y = y1; y < y2; y++) {
271         a = *p & 0xfefeff;
272         a += 0x202020;
273         b = a & 0x1010100;
274         *p = a | (b - (b >> 8));
275         p += width;
276       }
277     } else {
278       if ((fastrand () & 0xf0000000) == 0) {
279         scratch->life = 2 + (fastrand () >> 27);
280         scratch->x = fastrand () % (width * 256);
281         scratch->dx = ((int) fastrand ()) >> 23;
282         scratch->init = (fastrand () % (height - 1)) + 1;
283       }
284     }
285   }
286 }
287
288 static void
289 dusts (guint32 * dest, gint width, gint height, gint dust_interval,
290     gint area_scale)
291 {
292   int i, j;
293   int dnum;
294   int d, len;
295   guint x, y;
296
297   if (dust_interval == 0) {
298     if ((fastrand () & 0xf0000000) == 0) {
299       dust_interval = fastrand () >> 29;
300     }
301     return;
302   }
303   dnum = area_scale * 4 + (fastrand () >> 27);
304
305   for (i = 0; i < dnum; i++) {
306     x = fastrand () % width;
307     y = fastrand () % height;
308     d = fastrand () >> 29;
309     len = fastrand () % area_scale + 5;
310     for (j = 0; j < len; j++) {
311       dest[y * width + x] = 0x101010;
312       y += dy[d];
313       x += dx[d];
314
315       if (y >= height || x >= width)
316         break;
317
318       d = (d + fastrand () % 3 - 1) & 7;
319     }
320   }
321   dust_interval--;
322 }
323
324 static void
325 pits (guint32 * dest, gint width, gint height, gint area_scale,
326     gint pits_interval)
327 {
328   int i, j;
329   int pnum, size, pnumscale;
330   guint x, y;
331
332   pnumscale = area_scale * 2;
333   if (pits_interval) {
334     pnum = pnumscale + (fastrand () % pnumscale);
335
336     pits_interval--;
337   } else {
338     pnum = fastrand () % pnumscale;
339
340     if ((fastrand () & 0xf8000000) == 0) {
341       pits_interval = (fastrand () >> 28) + 20;
342     }
343   }
344   for (i = 0; i < pnum; i++) {
345     x = fastrand () % (width - 1);
346     y = fastrand () % (height - 1);
347
348     size = fastrand () >> 28;
349
350     for (j = 0; j < size; j++) {
351       x = x + fastrand () % 3 - 1;
352       y = y + fastrand () % 3 - 1;
353
354       if (y >= height || x >= width)
355         break;
356
357       dest[y * width + x] = 0xc0c0c0;
358     }
359   }
360 }
361
362 static void
363 gst_agingtv_rgb32 (GstVideofilter * videofilter, void *d, void *s)
364 {
365   GstAgingTV *agingtv;
366   int width = gst_videofilter_get_input_width (videofilter);
367   int height = gst_videofilter_get_input_height (videofilter);
368   int video_size = width * height;
369   guint32 *src = s;
370   guint32 *dest = d;
371   gint area_scale = width * height / 64 / 480;
372
373   if (area_scale <= 0)
374     area_scale = 1;
375
376   g_return_if_fail (GST_IS_AGINGTV (videofilter));
377   agingtv = GST_AGINGTV (videofilter);
378
379   coloraging (src, dest, video_size);
380   scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
381   pits (dest, width, height, area_scale, agingtv->pits_interval);
382   if (area_scale > 1)
383     dusts (dest, width, height, agingtv->dust_interval, area_scale);
384
385 }
386
387 static void
388 gst_agingtv_set_property (GObject * object, guint prop_id, const GValue * value,
389     GParamSpec * pspec)
390 {
391   GstAgingTV *src;
392
393   g_return_if_fail (GST_IS_AGINGTV (object));
394   src = GST_AGINGTV (object);
395
396   GST_DEBUG ("gst_agingtv_set_property");
397   switch (prop_id) {
398 #if 0
399     case ARG_METHOD:
400       src->method = g_value_get_enum (value);
401       break;
402 #endif
403     default:
404       break;
405   }
406 }
407
408 static void
409 gst_agingtv_get_property (GObject * object, guint prop_id, GValue * value,
410     GParamSpec * pspec)
411 {
412   GstAgingTV *src;
413
414   g_return_if_fail (GST_IS_AGINGTV (object));
415   src = GST_AGINGTV (object);
416
417   switch (prop_id) {
418 #if 0
419     case ARG_METHOD:
420       g_value_set_enum (value, src->method);
421       break;
422 #endif
423     default:
424       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
425       break;
426   }
427 }