2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David Schleef <ds@schleef.org>
4 * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
6 * EffecTV - Realtime Digital Video Effector
7 * Copyright (C) 2001-2002 FUKUCHI Kentarou
9 * AgingTV - film-aging effect.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
28 * SECTION:element-agingtv
30 * AgingTV ages a video stream in realtime, changes the colors and adds
34 * <title>Example launch line</title>
36 * gst-launch -v videotestsrc ! agingtv ! videoconvert ! autovideosink
37 * ]| This pipeline shows the effect of agingtv on a test stream.
49 #include "gsteffectv.h"
51 static const gint dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
52 static const gint dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
63 #define DEFAULT_SCRATCH_LINES 7
64 #define DEFAULT_COLOR_AGING TRUE
65 #define DEFAULT_PITS TRUE
66 #define DEFAULT_DUSTS TRUE
68 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
69 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ BGRx, RGBx }")
71 #define CAPS_STR GST_VIDEO_CAPS_MAKE ("{ xRGB, xBGR }")
74 static GstStaticPadTemplate gst_agingtv_src_template =
75 GST_STATIC_PAD_TEMPLATE ("src",
78 GST_STATIC_CAPS (CAPS_STR)
81 static GstStaticPadTemplate gst_agingtv_sink_template =
82 GST_STATIC_PAD_TEMPLATE ("sink",
85 GST_STATIC_CAPS (CAPS_STR)
88 G_DEFINE_TYPE (GstAgingTV, gst_agingtv, GST_TYPE_VIDEO_FILTER);
91 coloraging (guint32 * src, guint32 * dest, gint video_area, gint * c)
97 c_tmp -= (gint) (fastrand ()) >> 28;
103 for (i = 0; i < video_area; i++) {
105 b = (a & 0xfcfcfc) >> 2;
107 a - b + (c_tmp | (c_tmp << 8) | (c_tmp << 16)) +
108 ((fastrand () >> 8) & 0x101010);
115 scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
122 for (i = 0; i < scratch_lines; i++) {
123 scratch = &scratches[i];
126 scratch->x = scratch->x + scratch->dx;
128 if (scratch->x < 0 || scratch->x > width * 256) {
132 p = dest + (scratch->x >> 8);
143 y2 = fastrand () % height;
145 for (y = y1; y < y2; y++) {
149 *p = a | (b - (b >> 8));
153 if ((fastrand () & 0xf0000000) == 0) {
154 scratch->life = 2 + (fastrand () >> 27);
155 scratch->x = fastrand () % (width * 256);
156 scratch->dx = ((int) fastrand ()) >> 23;
157 scratch->init = (fastrand () % (height - 1)) + 1;
164 dusts (guint32 * dest, gint width, gint height, gint * dust_interval,
172 if (*dust_interval == 0) {
173 if ((fastrand () & 0xf0000000) == 0) {
174 *dust_interval = fastrand () >> 29;
178 dnum = area_scale * 4 + (fastrand () >> 27);
180 for (i = 0; i < dnum; i++) {
181 x = fastrand () % width;
182 y = fastrand () % height;
183 d = fastrand () >> 29;
184 len = fastrand () % area_scale + 5;
185 for (j = 0; j < len; j++) {
186 dest[y * width + x] = 0x101010;
190 if (y >= height || x >= width)
193 d = (d + fastrand () % 3 - 1) & 7;
196 *dust_interval = *dust_interval - 1;
200 pits (guint32 * dest, gint width, gint height, gint area_scale,
201 gint * pits_interval)
204 gint pnum, size, pnumscale;
207 pnumscale = area_scale * 2;
208 if (*pits_interval) {
209 pnum = pnumscale + (fastrand () % pnumscale);
211 *pits_interval = *pits_interval - 1;
213 pnum = fastrand () % pnumscale;
215 if ((fastrand () & 0xf8000000) == 0) {
216 *pits_interval = (fastrand () >> 28) + 20;
219 for (i = 0; i < pnum; i++) {
220 x = fastrand () % (width - 1);
221 y = fastrand () % (height - 1);
223 size = fastrand () >> 28;
225 for (j = 0; j < size; j++) {
226 x = x + fastrand () % 3 - 1;
227 y = y + fastrand () % 3 - 1;
229 if (y >= height || x >= width)
232 dest[y * width + x] = 0xc0c0c0;
238 gst_agingtv_get_property (GObject * object, guint prop_id,
239 GValue * value, GParamSpec * pspec)
241 GstAgingTV *agingtv = GST_AGINGTV (object);
243 GST_OBJECT_LOCK (agingtv);
245 case PROP_SCRATCH_LINES:
246 g_value_set_uint (value, agingtv->scratch_lines);
248 case PROP_COLOR_AGING:
249 g_value_set_boolean (value, agingtv->color_aging);
252 g_value_set_boolean (value, agingtv->pits);
255 g_value_set_boolean (value, agingtv->dusts);
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
260 GST_OBJECT_UNLOCK (agingtv);
264 gst_agingtv_set_property (GObject * object, guint prop_id,
265 const GValue * value, GParamSpec * pspec)
267 GstAgingTV *agingtv = GST_AGINGTV (object);
270 case PROP_SCRATCH_LINES:
271 agingtv->scratch_lines = g_value_get_uint (value);
273 case PROP_COLOR_AGING:
274 agingtv->color_aging = g_value_get_boolean (value);
277 agingtv->pits = g_value_get_boolean (value);
280 agingtv->dusts = g_value_get_boolean (value);
283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
288 gst_agingtv_start (GstBaseTransform * trans)
290 GstAgingTV *agingtv = GST_AGINGTV (trans);
292 agingtv->coloraging_state = 0x18;
293 agingtv->dust_interval = 0;
294 agingtv->pits_interval = 0;
296 memset (agingtv->scratches, 0, sizeof (agingtv->scratches));
302 gst_agingtv_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
303 GstVideoFrame * out_frame)
305 GstAgingTV *agingtv = GST_AGINGTV (filter);
307 GstClockTime timestamp, stream_time;
308 gint width, height, stride, video_size;
311 timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
313 gst_segment_to_stream_time (&GST_BASE_TRANSFORM (filter)->segment,
314 GST_FORMAT_TIME, timestamp);
316 GST_DEBUG_OBJECT (agingtv, "sync to %" GST_TIME_FORMAT,
317 GST_TIME_ARGS (timestamp));
319 if (GST_CLOCK_TIME_IS_VALID (stream_time))
320 gst_object_sync_values (GST_OBJECT (agingtv), stream_time);
322 width = GST_VIDEO_FRAME_WIDTH (in_frame);
323 height = GST_VIDEO_FRAME_HEIGHT (in_frame);
324 stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
325 video_size = stride * height / 4;
327 src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
328 dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
330 area_scale = width * height / 64 / 480;
334 if (agingtv->color_aging)
335 coloraging (src, dest, video_size, &agingtv->coloraging_state);
337 memcpy (dest, src, video_size);
339 scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
341 pits (dest, width, height, area_scale, &agingtv->pits_interval);
342 if (area_scale > 1 && agingtv->dusts)
343 dusts (dest, width, height, &agingtv->dust_interval, area_scale);
349 gst_agingtv_class_init (GstAgingTVClass * klass)
351 GObjectClass *gobject_class = (GObjectClass *) klass;
352 GstElementClass *gstelement_class = (GstElementClass *) klass;
353 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
354 GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
356 gobject_class->set_property = gst_agingtv_set_property;
357 gobject_class->get_property = gst_agingtv_get_property;
359 g_object_class_install_property (gobject_class, PROP_SCRATCH_LINES,
360 g_param_spec_uint ("scratch-lines", "Scratch Lines",
361 "Number of scratch lines", 0, SCRATCH_MAX, DEFAULT_SCRATCH_LINES,
362 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
364 g_object_class_install_property (gobject_class, PROP_COLOR_AGING,
365 g_param_spec_boolean ("color-aging", "Color Aging",
366 "Color Aging", DEFAULT_COLOR_AGING,
367 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
369 g_object_class_install_property (gobject_class, PROP_PITS,
370 g_param_spec_boolean ("pits", "Pits",
371 "Pits", DEFAULT_PITS,
372 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
374 g_object_class_install_property (gobject_class, PROP_DUSTS,
375 g_param_spec_boolean ("dusts", "Dusts",
376 "Dusts", DEFAULT_DUSTS,
377 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
379 gst_element_class_set_static_metadata (gstelement_class, "AgingTV effect",
380 "Filter/Effect/Video",
381 "AgingTV adds age to video input using scratches and dust",
382 "Sam Lantinga <slouken@devolution.com>");
384 gst_element_class_add_pad_template (gstelement_class,
385 gst_static_pad_template_get (&gst_agingtv_sink_template));
386 gst_element_class_add_pad_template (gstelement_class,
387 gst_static_pad_template_get (&gst_agingtv_src_template));
389 trans_class->start = GST_DEBUG_FUNCPTR (gst_agingtv_start);
391 vfilter_class->transform_frame =
392 GST_DEBUG_FUNCPTR (gst_agingtv_transform_frame);
396 gst_agingtv_init (GstAgingTV * agingtv)
398 agingtv->scratch_lines = DEFAULT_SCRATCH_LINES;
399 agingtv->color_aging = DEFAULT_COLOR_AGING;
400 agingtv->pits = DEFAULT_PITS;
401 agingtv->dusts = DEFAULT_DUSTS;