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