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