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., 51 Franklin St, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 * SECTION:element-agingtv
31 * AgingTV ages a video stream in realtime, changes the colors and adds
34 * ## Example launch line
36 * gst-launch-1.0 -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);
89 GST_ELEMENT_REGISTER_DEFINE (agingtv, "agingtv", GST_RANK_NONE,
93 coloraging (guint32 * src, guint32 * dest, gint video_area, gint * c)
99 c_tmp -= (gint) (fastrand ()) >> 28;
105 for (i = 0; i < video_area; i++) {
107 b = (a & 0xfcfcfc) >> 2;
109 a - b + (c_tmp | (c_tmp << 8) | (c_tmp << 16)) +
110 ((fastrand () >> 8) & 0x101010);
117 scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
124 for (i = 0; i < scratch_lines; i++) {
125 scratch = &scratches[i];
128 scratch->x = scratch->x + scratch->dx;
130 if (scratch->x < 0 || scratch->x > width * 256) {
134 p = dest + (scratch->x >> 8);
145 y2 = fastrand () % height;
147 for (y = y1; y < y2; y++) {
151 *p = a | (b - (b >> 8));
155 if ((fastrand () & 0xf0000000) == 0) {
156 scratch->life = 2 + (fastrand () >> 27);
157 scratch->x = fastrand () % (width * 256);
158 scratch->dx = ((int) fastrand ()) >> 23;
159 scratch->init = (fastrand () % (height - 1)) + 1;
166 dusts (guint32 * dest, gint width, gint height, gint * dust_interval,
174 if (*dust_interval == 0) {
175 if ((fastrand () & 0xf0000000) == 0) {
176 *dust_interval = fastrand () >> 29;
180 dnum = area_scale * 4 + (fastrand () >> 27);
182 for (i = 0; i < dnum; i++) {
183 x = fastrand () % width;
184 y = fastrand () % height;
185 d = fastrand () >> 29;
186 len = fastrand () % area_scale + 5;
187 for (j = 0; j < len; j++) {
188 dest[y * width + x] = 0x101010;
192 if (y >= height || x >= width)
195 d = (d + fastrand () % 3 - 1) & 7;
198 *dust_interval = *dust_interval - 1;
202 pits (guint32 * dest, gint width, gint height, gint area_scale,
203 gint * pits_interval)
206 gint pnum, size, pnumscale;
209 pnumscale = area_scale * 2;
210 if (*pits_interval) {
211 pnum = pnumscale + (fastrand () % pnumscale);
213 *pits_interval = *pits_interval - 1;
215 pnum = fastrand () % pnumscale;
217 if ((fastrand () & 0xf8000000) == 0) {
218 *pits_interval = (fastrand () >> 28) + 20;
221 for (i = 0; i < pnum; i++) {
222 x = fastrand () % (width - 1);
223 y = fastrand () % (height - 1);
225 size = fastrand () >> 28;
227 for (j = 0; j < size; j++) {
228 x = x + fastrand () % 3 - 1;
229 y = y + fastrand () % 3 - 1;
231 if (y >= height || x >= width)
234 dest[y * width + x] = 0xc0c0c0;
240 gst_agingtv_get_property (GObject * object, guint prop_id,
241 GValue * value, GParamSpec * pspec)
243 GstAgingTV *agingtv = GST_AGINGTV (object);
245 GST_OBJECT_LOCK (agingtv);
247 case PROP_SCRATCH_LINES:
248 g_value_set_uint (value, agingtv->scratch_lines);
250 case PROP_COLOR_AGING:
251 g_value_set_boolean (value, agingtv->color_aging);
254 g_value_set_boolean (value, agingtv->pits);
257 g_value_set_boolean (value, agingtv->dusts);
260 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262 GST_OBJECT_UNLOCK (agingtv);
266 gst_agingtv_set_property (GObject * object, guint prop_id,
267 const GValue * value, GParamSpec * pspec)
269 GstAgingTV *agingtv = GST_AGINGTV (object);
272 case PROP_SCRATCH_LINES:
273 agingtv->scratch_lines = g_value_get_uint (value);
275 case PROP_COLOR_AGING:
276 agingtv->color_aging = g_value_get_boolean (value);
279 agingtv->pits = g_value_get_boolean (value);
282 agingtv->dusts = g_value_get_boolean (value);
285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 gst_agingtv_start (GstBaseTransform * trans)
292 GstAgingTV *agingtv = GST_AGINGTV (trans);
294 agingtv->coloraging_state = 0x18;
295 agingtv->dust_interval = 0;
296 agingtv->pits_interval = 0;
298 memset (agingtv->scratches, 0, sizeof (agingtv->scratches));
304 gst_agingtv_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
305 GstVideoFrame * out_frame)
307 GstAgingTV *agingtv = GST_AGINGTV (filter);
309 GstClockTime timestamp, stream_time;
310 gint width, height, stride, video_size;
313 timestamp = GST_BUFFER_TIMESTAMP (in_frame->buffer);
315 gst_segment_to_stream_time (&GST_BASE_TRANSFORM (filter)->segment,
316 GST_FORMAT_TIME, timestamp);
318 GST_DEBUG_OBJECT (agingtv, "sync to %" GST_TIME_FORMAT,
319 GST_TIME_ARGS (timestamp));
321 if (GST_CLOCK_TIME_IS_VALID (stream_time))
322 gst_object_sync_values (GST_OBJECT (agingtv), stream_time);
324 width = GST_VIDEO_FRAME_WIDTH (in_frame);
325 height = GST_VIDEO_FRAME_HEIGHT (in_frame);
326 stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0);
327 video_size = stride * height / 4;
329 src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
330 dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
332 area_scale = width * height / 64 / 480;
336 if (agingtv->color_aging)
337 coloraging (src, dest, video_size, &agingtv->coloraging_state);
339 memcpy (dest, src, stride * height);
341 scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
343 pits (dest, width, height, area_scale, &agingtv->pits_interval);
344 if (area_scale > 1 && agingtv->dusts)
345 dusts (dest, width, height, &agingtv->dust_interval, area_scale);
351 gst_agingtv_class_init (GstAgingTVClass * klass)
353 GObjectClass *gobject_class = (GObjectClass *) klass;
354 GstElementClass *gstelement_class = (GstElementClass *) klass;
355 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
356 GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
358 gobject_class->set_property = gst_agingtv_set_property;
359 gobject_class->get_property = gst_agingtv_get_property;
361 g_object_class_install_property (gobject_class, PROP_SCRATCH_LINES,
362 g_param_spec_uint ("scratch-lines", "Scratch Lines",
363 "Number of scratch lines", 0, SCRATCH_MAX, DEFAULT_SCRATCH_LINES,
364 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
366 g_object_class_install_property (gobject_class, PROP_COLOR_AGING,
367 g_param_spec_boolean ("color-aging", "Color Aging",
368 "Color Aging", DEFAULT_COLOR_AGING,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
371 g_object_class_install_property (gobject_class, PROP_PITS,
372 g_param_spec_boolean ("pits", "Pits",
373 "Pits", DEFAULT_PITS,
374 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
376 g_object_class_install_property (gobject_class, PROP_DUSTS,
377 g_param_spec_boolean ("dusts", "Dusts",
378 "Dusts", DEFAULT_DUSTS,
379 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
381 gst_element_class_set_static_metadata (gstelement_class, "AgingTV effect",
382 "Filter/Effect/Video",
383 "AgingTV adds age to video input using scratches and dust",
384 "Sam Lantinga <slouken@devolution.com>");
386 gst_element_class_add_static_pad_template (gstelement_class,
387 &gst_agingtv_sink_template);
388 gst_element_class_add_static_pad_template (gstelement_class,
389 &gst_agingtv_src_template);
391 trans_class->start = GST_DEBUG_FUNCPTR (gst_agingtv_start);
393 vfilter_class->transform_frame =
394 GST_DEBUG_FUNCPTR (gst_agingtv_transform_frame);
398 gst_agingtv_init (GstAgingTV * agingtv)
400 agingtv->scratch_lines = DEFAULT_SCRATCH_LINES;
401 agingtv->color_aging = DEFAULT_COLOR_AGING;
402 agingtv->pits = DEFAULT_PITS;
403 agingtv->dusts = DEFAULT_DUSTS;