plugins part of license field patch
[platform/upstream/gst-plugins-good.git] / gst / effectv / gstaging.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 is free software. * This library is free software;
8  * 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 #include <string.h>
25 #include "gsteffectv.h"
26
27 #define GST_TYPE_AGINGTV \
28   (gst_agingtv_get_type())
29 #define GST_AGINGTV(obj) \
30   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGINGTV,GstAgingTV))
31 #define GST_AGINGTV_CLASS(klass) \
32   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstAgingTV))
33 #define GST_IS_AGINGTV(obj) \
34   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGINGTV))
35 #define GST_IS_AGINGTV_CLASS(obj) \
36   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGINGTV))
37
38 #define SCRATCH_MAX 20
39 typedef struct _scratch
40 {
41   gint life;
42   gint x;
43   gint dx;
44   gint init;
45 } scratch;
46
47 static int dx[8] = { 1, 1, 0, -1, -1, -1,  0, 1};
48 static int dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1};
49
50
51 typedef struct _GstAgingTV GstAgingTV;
52 typedef struct _GstAgingTVClass GstAgingTVClass;
53
54 struct _GstAgingTV
55 {
56   GstElement element;
57
58   GstPad *sinkpad, *srcpad;
59
60   gint width, height;
61   gint video_size;
62   gint area_scale;
63   gint aging_mode;
64
65   scratch scratches[SCRATCH_MAX];
66   gint scratch_lines;
67
68   gint dust_interval;
69   gint pits_interval;
70 };
71
72 struct _GstAgingTVClass
73 {
74   GstElementClass parent_class;
75 };
76
77 /* elementfactory information */
78 GstElementDetails gst_agingtv_details = {
79   "AgingTV",
80   "Filter/Video/Effect",
81   "LGPL",
82   "Aply aging effect on video",
83   VERSION,
84   "Wim Taymans <wim.taymans@chello.be>",
85   "(C) 2001 FUKUCHI Kentarou",
86 };
87
88
89 /* Filter signals and args */
90 enum
91 {
92   /* FILL ME */
93   LAST_SIGNAL
94 };
95
96 enum
97 {
98   ARG_0,
99 };
100
101 static void     gst_agingtv_class_init          (GstAgingTVClass * klass);
102 static void     gst_agingtv_init                (GstAgingTV * filter);
103
104 static void     aging_mode_switch               (GstAgingTV *filter);
105
106 static void     gst_agingtv_set_property        (GObject * object, guint prop_id,
107                                                  const GValue * value, GParamSpec * pspec);
108 static void     gst_agingtv_get_property        (GObject * object, guint prop_id,
109                                                  GValue * value, GParamSpec * pspec);
110
111 static void     gst_agingtv_chain               (GstPad * pad, GstBuffer * buf);
112
113 static GstElementClass *parent_class = NULL;
114 /*static guint gst_agingtv_signals[LAST_SIGNAL] = { 0 }; */
115
116 GType gst_agingtv_get_type (void)
117 {
118   static GType agingtv_type = 0;
119
120   if (!agingtv_type) {
121     static const GTypeInfo agingtv_info = {
122       sizeof (GstAgingTVClass), NULL,
123       NULL,
124       (GClassInitFunc) gst_agingtv_class_init,
125       NULL,
126       NULL,
127       sizeof (GstAgingTV),
128       0,
129       (GInstanceInitFunc) gst_agingtv_init,
130     };
131
132     agingtv_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAgingTV", &agingtv_info, 0);
133   }
134   return agingtv_type;
135 }
136
137 static void
138 gst_agingtv_class_init (GstAgingTVClass * klass)
139 {
140   GObjectClass *gobject_class;
141   GstElementClass *gstelement_class;
142
143   gobject_class = (GObjectClass *) klass;
144   gstelement_class = (GstElementClass *) klass;
145
146   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
147
148   gobject_class->set_property = gst_agingtv_set_property;
149   gobject_class->get_property = gst_agingtv_get_property;
150 }
151
152 static GstPadConnectReturn
153 gst_agingtv_sinkconnect (GstPad * pad, GstCaps * caps)
154 {
155   GstAgingTV *filter;
156
157   filter = GST_AGINGTV (gst_pad_get_parent (pad));
158
159   if (!GST_CAPS_IS_FIXED (caps))
160     return GST_PAD_CONNECT_DELAYED;
161
162   gst_caps_get_int (caps, "width", &filter->width);
163   gst_caps_get_int (caps, "height", &filter->height);
164
165   filter->video_size = filter->width * filter->height;
166   filter->aging_mode = 0;
167   aging_mode_switch (filter);
168
169   return gst_pad_try_set_caps (filter->srcpad, caps);
170 }
171
172 static void
173 gst_agingtv_init (GstAgingTV * filter)
174 {
175   filter->sinkpad = gst_pad_new_from_template (gst_effectv_sink_factory (), "sink");
176   gst_pad_set_chain_function (filter->sinkpad, gst_agingtv_chain);
177   gst_pad_set_connect_function (filter->sinkpad, gst_agingtv_sinkconnect);
178   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
179
180   filter->srcpad = gst_pad_new_from_template (gst_effectv_src_factory (), "src");
181   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
182 }
183
184
185 static unsigned int 
186 fastrand (void)
187 {
188   static unsigned int fastrand_val;
189
190   return (fastrand_val = fastrand_val * 1103515245 + 12345);
191 }
192
193
194 static void 
195 coloraging (guint32 *src, guint32 *dest, gint video_area)
196 {
197   guint32 a, b;
198   gint i;
199
200   for (i = video_area; i; i--) {
201     a = *src++;
202     b = (a & 0xfcfcfc) >> 2;
203     *dest++ = a - b + 0x181818 + ((fastrand () >> 8) & 0x101010);
204   }
205 }
206
207
208 static void 
209 scratching (scratch *scratches, gint scratch_lines, guint32 *dest, gint width, gint height)
210 {
211   gint i, y, y1, y2;
212   guint32 *p, a, b;
213   scratch *scratch;
214
215   for (i = 0; i < scratch_lines; i++) {
216     scratch = &scratches[i];
217
218     if (scratch->life) {
219       scratch->x = scratch->x + scratch->dx;
220       
221       if (scratch->x < 0 || scratch->x > width * 256) {
222         scratch->life = 0;
223         break;
224       }
225       p = dest + (scratch->x >> 8);
226       if (scratch->init) {
227         y1 = scratch->init;
228         scratch->init = 0;
229       } else {
230         y1 = 0;
231       }
232       scratch->life--;
233       if (scratch->life) {
234         y2 = height;
235       } else {
236         y2 = fastrand () % height;
237       }
238       for (y = y1; y < y2; y++) {
239         a = *p & 0xfefeff;
240         a += 0x202020;
241         b = a & 0x1010100;
242         *p = a | (b - (b >> 8));
243         p += width;
244       }
245     } else {
246       if ((fastrand () & 0xf0000000) == 0) {
247         scratch->life = 2 + (fastrand () >> 27);
248         scratch->x = fastrand () % (width * 256);
249         scratch->dx = ((int) fastrand ()) >> 23;
250         scratch->init = (fastrand () % (height - 1)) + 1;
251       }
252     }
253   }
254 }
255
256 static void 
257 dusts (guint32 *dest, gint width, gint height, gint dust_interval, gint area_scale)
258 {
259   int i, j;
260   int dnum;
261   int d, len;
262   guint x, y;
263
264   if (dust_interval == 0) {
265     if ((fastrand () & 0xf0000000) == 0) {
266       dust_interval = fastrand () >> 29;
267     }
268     return;
269   }
270   dnum = area_scale * 4 + (fastrand() >> 27);
271   
272   for (i = 0; i < dnum; i++) {
273     x = fastrand () % width;
274     y = fastrand () % height;
275     d = fastrand () >> 29;
276     len = fastrand () % area_scale + 5;
277     for (j = 0; j < len; j++) {
278       dest[y * width + x] = 0x101010;
279       y += dy[d];
280       x += dx[d];
281
282       if (y >= height || x >= width) break;
283
284       d = (d + fastrand () % 3 - 1) & 7;
285     }
286   }
287   dust_interval--;
288 }
289
290 static void 
291 pits (guint32 *dest, gint width, gint height, gint area_scale, gint pits_interval)
292 {
293   int i, j;
294   int pnum, size, pnumscale;
295   guint x, y;
296
297   pnumscale = area_scale * 2;
298   if (pits_interval) {
299     pnum = pnumscale + (fastrand () % pnumscale);
300
301     pits_interval--;
302   } else {
303     pnum = fastrand () % pnumscale;
304
305     if ((fastrand () & 0xf8000000) == 0) {
306       pits_interval = (fastrand () >> 28) + 20;
307     }
308   }
309   for (i = 0; i < pnum; i++) {
310     x = fastrand () % (width - 1);
311     y = fastrand () % (height - 1);
312
313     size = fastrand () >> 28;
314
315     for (j = 0; j < size; j++) {
316       x = x + fastrand () % 3 - 1;
317       y = y + fastrand () % 3 - 1;
318
319       if (y >= height || x >= width) break;
320
321       dest[y * width + x] = 0xc0c0c0;
322     }
323   }
324 }
325
326 static void 
327 aging_mode_switch (GstAgingTV *filter)
328 {
329   switch (filter->aging_mode) {
330     default:
331     case 0:
332       filter->scratch_lines = 7;
333         /* Most of the parameters are tuned for 640x480 mode */
334         /* area_scale is set to 10 when screen size is 640x480. */
335       filter->area_scale = filter->width * filter->height / 64 / 480;
336   }
337   if (filter->area_scale <= 0)
338     filter->area_scale = 1;
339 }
340
341 static void
342 gst_agingtv_chain (GstPad * pad, GstBuffer * buf)
343 {
344   GstAgingTV *filter;
345   guint32 *src, *dest;
346   GstBuffer *outbuf;
347
348   filter = GST_AGINGTV (gst_pad_get_parent (pad));
349
350   src = (guint32 *) GST_BUFFER_DATA (buf);
351
352   outbuf = gst_buffer_new ();
353   GST_BUFFER_SIZE (outbuf) = (filter->video_size * sizeof (guint32));
354   dest = (guint32 *) GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
355   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
356
357   coloraging (src, dest, filter->video_size);
358   scratching (filter->scratches, filter->scratch_lines, dest, filter->width, filter->height);
359   pits (dest, filter->width, filter->height, filter->area_scale, filter->pits_interval);
360   if(filter->area_scale > 1)
361     dusts (dest, filter->width, filter->height, filter->dust_interval, filter->area_scale);
362   
363   gst_buffer_unref (buf);
364
365   gst_pad_push (filter->srcpad, outbuf);
366 }
367
368 static void
369 gst_agingtv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
370 {
371   GstAgingTV *filter;
372
373   /* it's not null if we got it, but it might not be ours */
374   g_return_if_fail (GST_IS_AGINGTV (object));
375
376   filter = GST_AGINGTV (object);
377
378   switch (prop_id) {
379     default:
380       break;
381   }
382 }
383
384 static void
385 gst_agingtv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
386 {
387   GstAgingTV *filter;
388
389   /* it's not null if we got it, but it might not be ours */
390   g_return_if_fail (GST_IS_AGINGTV (object));
391
392   filter = GST_AGINGTV (object);
393
394   switch (prop_id) {
395     default:
396       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397       break;
398   }
399 }