VideoFilter inherits from
[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 <gstvideofilter.h>
41
42 #include <string.h>
43 #include <math.h>
44
45 #include <gst/video/video.h>
46
47 #define GST_TYPE_AGINGTV \
48   (gst_agingtv_get_type())
49 #define GST_AGINGTV(obj) \
50   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AGINGTV,GstAgingTV))
51 #define GST_AGINGTV_CLASS(klass) \
52   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AGINGTV,GstAgingTVClass))
53 #define GST_IS_AGINGTV(obj) \
54   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AGINGTV))
55 #define GST_IS_AGINGTV_CLASS(obj) \
56   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGINGTV))
57
58 #define SCRATCH_MAX 20
59 typedef struct _scratch
60 {
61   gint life;
62   gint x;
63   gint dx;
64   gint init;
65 }
66 scratch;
67
68 static int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
69 static int dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
70
71 typedef struct _GstAgingTV GstAgingTV;
72 typedef struct _GstAgingTVClass GstAgingTVClass;
73
74 struct _GstAgingTV
75 {
76   GstVideofilter videofilter;
77
78   gint width, height;
79   gint aging_mode;
80
81   scratch scratches[SCRATCH_MAX];
82   gint scratch_lines;
83
84   gint dust_interval;
85   gint pits_interval;
86
87 };
88
89 struct _GstAgingTVClass
90 {
91   GstVideofilterClass parent_class;
92 };
93
94 GType gst_agingtv_get_type (void);
95
96 static GstElementDetails agingtv_details = GST_ELEMENT_DETAILS ("AgingTV",
97     "Filter/Effect/Video",
98     "AgingTV adds age to video input using scratches and dust",
99     "Sam Lantinga <slouken@devolution.com>");
100
101 static GstStaticPadTemplate gst_agingtv_src_template =
102 GST_STATIC_PAD_TEMPLATE ("src",
103     GST_PAD_SRC,
104     GST_PAD_ALWAYS,
105     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
106     );
107
108 static GstStaticPadTemplate gst_agingtv_sink_template =
109 GST_STATIC_PAD_TEMPLATE ("sink",
110     GST_PAD_SINK,
111     GST_PAD_ALWAYS,
112     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
113     );
114
115 static GstVideofilterClass *parent_class = NULL;
116
117 static gboolean
118 gst_agingtv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
119     GstCaps * outcaps)
120 {
121   GstAgingTV *filter = GST_AGINGTV (btrans);
122   GstStructure *structure;
123   gboolean ret = FALSE;
124
125   structure = gst_caps_get_structure (incaps, 0);
126
127   if (gst_structure_get_int (structure, "width", &filter->width) &&
128       gst_structure_get_int (structure, "height", &filter->height)) {
129     ret = TRUE;
130   }
131
132   return ret;
133 }
134
135 static gboolean
136 gst_agingtv_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
137     guint * size)
138 {
139   GstAgingTV *filter;
140   GstStructure *structure;
141   gboolean ret = FALSE;
142   gint width, height;
143
144   filter = GST_AGINGTV (btrans);
145
146   structure = gst_caps_get_structure (caps, 0);
147
148   if (gst_structure_get_int (structure, "width", &width) &&
149       gst_structure_get_int (structure, "height", &height)) {
150     *size = width * height * 32 / 8;
151     ret = TRUE;
152     GST_DEBUG_OBJECT (filter, "our frame size is %d bytes (%dx%d)", *size,
153         width, height);
154   }
155
156   return ret;
157 }
158
159 static unsigned int
160 fastrand (void)
161 {
162   static unsigned int fastrand_val;
163
164   return (fastrand_val = fastrand_val * 1103515245 + 12345);
165 }
166
167
168 static void
169 coloraging (guint32 * src, guint32 * dest, gint video_area)
170 {
171   guint32 a, b;
172   gint i;
173
174   for (i = video_area; i; i--) {
175     a = *src++;
176     b = (a & 0xfcfcfc) >> 2;
177     *dest++ = a - b + 0x181818 + ((fastrand () >> 8) & 0x101010);
178   }
179 }
180
181
182 static void
183 scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
184     gint height)
185 {
186   gint i, y, y1, y2;
187   guint32 *p, a, b;
188   scratch *scratch;
189
190   for (i = 0; i < scratch_lines; i++) {
191     scratch = &scratches[i];
192
193     if (scratch->life) {
194       scratch->x = scratch->x + scratch->dx;
195
196       if (scratch->x < 0 || scratch->x > width * 256) {
197         scratch->life = 0;
198         break;
199       }
200       p = dest + (scratch->x >> 8);
201       if (scratch->init) {
202         y1 = scratch->init;
203         scratch->init = 0;
204       } else {
205         y1 = 0;
206       }
207       scratch->life--;
208       if (scratch->life) {
209         y2 = height;
210       } else {
211         y2 = fastrand () % height;
212       }
213       for (y = y1; y < y2; y++) {
214         a = *p & 0xfefeff;
215         a += 0x202020;
216         b = a & 0x1010100;
217         *p = a | (b - (b >> 8));
218         p += width;
219       }
220     } else {
221       if ((fastrand () & 0xf0000000) == 0) {
222         scratch->life = 2 + (fastrand () >> 27);
223         scratch->x = fastrand () % (width * 256);
224         scratch->dx = ((int) fastrand ()) >> 23;
225         scratch->init = (fastrand () % (height - 1)) + 1;
226       }
227     }
228   }
229 }
230
231 static void
232 dusts (guint32 * dest, gint width, gint height, gint dust_interval,
233     gint area_scale)
234 {
235   int i, j;
236   int dnum;
237   int d, len;
238   guint x, y;
239
240   if (dust_interval == 0) {
241     if ((fastrand () & 0xf0000000) == 0) {
242       dust_interval = fastrand () >> 29;
243     }
244     return;
245   }
246   dnum = area_scale * 4 + (fastrand () >> 27);
247
248   for (i = 0; i < dnum; i++) {
249     x = fastrand () % width;
250     y = fastrand () % height;
251     d = fastrand () >> 29;
252     len = fastrand () % area_scale + 5;
253     for (j = 0; j < len; j++) {
254       dest[y * width + x] = 0x101010;
255       y += dy[d];
256       x += dx[d];
257
258       if (y >= height || x >= width)
259         break;
260
261       d = (d + fastrand () % 3 - 1) & 7;
262     }
263   }
264   dust_interval--;
265 }
266
267 static void
268 pits (guint32 * dest, gint width, gint height, gint area_scale,
269     gint pits_interval)
270 {
271   int i, j;
272   int pnum, size, pnumscale;
273   guint x, y;
274
275   pnumscale = area_scale * 2;
276   if (pits_interval) {
277     pnum = pnumscale + (fastrand () % pnumscale);
278
279     pits_interval--;
280   } else {
281     pnum = fastrand () % pnumscale;
282
283     if ((fastrand () & 0xf8000000) == 0) {
284       pits_interval = (fastrand () >> 28) + 20;
285     }
286   }
287   for (i = 0; i < pnum; i++) {
288     x = fastrand () % (width - 1);
289     y = fastrand () % (height - 1);
290
291     size = fastrand () >> 28;
292
293     for (j = 0; j < size; j++) {
294       x = x + fastrand () % 3 - 1;
295       y = y + fastrand () % 3 - 1;
296
297       if (y >= height || x >= width)
298         break;
299
300       dest[y * width + x] = 0xc0c0c0;
301     }
302   }
303 }
304
305 static GstFlowReturn
306 gst_agingtv_transform (GstBaseTransform * trans, GstBuffer * in,
307     GstBuffer * out)
308 {
309   GstAgingTV *agingtv = GST_AGINGTV (trans);
310   gint width = agingtv->width;
311   gint height = agingtv->height;
312   int video_size = width * height;
313   guint32 *src = (guint32 *) GST_BUFFER_DATA (in);
314   guint32 *dest = (guint32 *) GST_BUFFER_DATA (out);
315   gint area_scale = width * height / 64 / 480;
316   GstFlowReturn ret = GST_FLOW_OK;
317
318   gst_buffer_stamp (out, in);
319
320   if (area_scale <= 0)
321     area_scale = 1;
322
323   coloraging (src, dest, video_size);
324   scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
325   pits (dest, width, height, area_scale, agingtv->pits_interval);
326   if (area_scale > 1)
327     dusts (dest, width, height, agingtv->dust_interval, area_scale);
328
329   return ret;
330 }
331
332 static void
333 gst_agingtv_base_init (gpointer g_class)
334 {
335   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
336
337   gst_element_class_set_details (element_class, &agingtv_details);
338
339   gst_element_class_add_pad_template (element_class,
340       gst_static_pad_template_get (&gst_agingtv_sink_template));
341   gst_element_class_add_pad_template (element_class,
342       gst_static_pad_template_get (&gst_agingtv_src_template));
343 }
344
345 static void
346 gst_agingtv_class_init (gpointer klass, gpointer class_data)
347 {
348   GObjectClass *gobject_class;
349   GstElementClass *element_class;
350   GstBaseTransformClass *trans_class;
351
352   gobject_class = (GObjectClass *) klass;
353   element_class = (GstElementClass *) klass;
354   trans_class = (GstBaseTransformClass *) klass;
355
356   parent_class = g_type_class_peek_parent (klass);
357
358   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_agingtv_set_caps);
359   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_agingtv_get_unit_size);
360   trans_class->transform = GST_DEBUG_FUNCPTR (gst_agingtv_transform);
361 }
362
363 static void
364 gst_agingtv_init (GTypeInstance * instance, gpointer g_class)
365 {
366 }
367
368 GType
369 gst_agingtv_get_type (void)
370 {
371   static GType agingtv_type = 0;
372
373   if (!agingtv_type) {
374     static const GTypeInfo agingtv_info = {
375       sizeof (GstAgingTVClass),
376       gst_agingtv_base_init,
377       NULL,
378       gst_agingtv_class_init,
379       NULL,
380       NULL,
381       sizeof (GstAgingTV),
382       0,
383       gst_agingtv_init,
384     };
385
386     agingtv_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
387         "GstAgingTV", &agingtv_info, 0);
388   }
389   return agingtv_type;
390 }