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 ! ffmpegcolorspace ! autovideosink
37 * ]| This pipeline shows the effect of agingtv on a test stream.
49 #include "gsteffectv.h"
51 #include <gst/video/video.h>
52 #include <gst/controller/gstcontroller.h>
54 static const gint dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
55 static const gint dy[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
66 #define DEFAULT_SCRATCH_LINES 7
67 #define DEFAULT_COLOR_AGING TRUE
68 #define DEFAULT_PITS TRUE
69 #define DEFAULT_DUSTS TRUE
71 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
72 #define CAPS_STR GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_RGBx
74 #define CAPS_STR GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR
77 static GstStaticPadTemplate gst_agingtv_src_template =
78 GST_STATIC_PAD_TEMPLATE ("src",
81 GST_STATIC_CAPS (CAPS_STR)
84 static GstStaticPadTemplate gst_agingtv_sink_template =
85 GST_STATIC_PAD_TEMPLATE ("sink",
88 GST_STATIC_CAPS (CAPS_STR)
91 GST_BOILERPLATE (GstAgingTV, gst_agingtv, GstVideoFilter,
92 GST_TYPE_VIDEO_FILTER);
95 gst_agingtv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
98 GstAgingTV *filter = GST_AGINGTV (btrans);
99 GstStructure *structure;
100 gboolean ret = FALSE;
102 structure = gst_caps_get_structure (incaps, 0);
104 GST_OBJECT_LOCK (filter);
105 if (gst_structure_get_int (structure, "width", &filter->width) &&
106 gst_structure_get_int (structure, "height", &filter->height)) {
109 GST_OBJECT_UNLOCK (filter);
115 coloraging (guint32 * src, guint32 * dest, gint video_area, gint * c)
121 c_tmp -= (gint) (fastrand ()) >> 28;
127 for (i = 0; i < video_area; i++) {
129 b = (a & 0xfcfcfc) >> 2;
131 a - b + (c_tmp | (c_tmp << 8) | (c_tmp << 16)) +
132 ((fastrand () >> 8) & 0x101010);
139 scratching (scratch * scratches, gint scratch_lines, guint32 * dest, gint width,
146 for (i = 0; i < scratch_lines; i++) {
147 scratch = &scratches[i];
150 scratch->x = scratch->x + scratch->dx;
152 if (scratch->x < 0 || scratch->x > width * 256) {
156 p = dest + (scratch->x >> 8);
167 y2 = fastrand () % height;
169 for (y = y1; y < y2; y++) {
173 *p = a | (b - (b >> 8));
177 if ((fastrand () & 0xf0000000) == 0) {
178 scratch->life = 2 + (fastrand () >> 27);
179 scratch->x = fastrand () % (width * 256);
180 scratch->dx = ((int) fastrand ()) >> 23;
181 scratch->init = (fastrand () % (height - 1)) + 1;
188 dusts (guint32 * dest, gint width, gint height, gint * dust_interval,
196 if (*dust_interval == 0) {
197 if ((fastrand () & 0xf0000000) == 0) {
198 *dust_interval = fastrand () >> 29;
202 dnum = area_scale * 4 + (fastrand () >> 27);
204 for (i = 0; i < dnum; i++) {
205 x = fastrand () % width;
206 y = fastrand () % height;
207 d = fastrand () >> 29;
208 len = fastrand () % area_scale + 5;
209 for (j = 0; j < len; j++) {
210 dest[y * width + x] = 0x101010;
214 if (y >= height || x >= width)
217 d = (d + fastrand () % 3 - 1) & 7;
220 *dust_interval = *dust_interval - 1;
224 pits (guint32 * dest, gint width, gint height, gint area_scale,
225 gint * pits_interval)
228 gint pnum, size, pnumscale;
231 pnumscale = area_scale * 2;
232 if (*pits_interval) {
233 pnum = pnumscale + (fastrand () % pnumscale);
235 *pits_interval = *pits_interval - 1;
237 pnum = fastrand () % pnumscale;
239 if ((fastrand () & 0xf8000000) == 0) {
240 *pits_interval = (fastrand () >> 28) + 20;
243 for (i = 0; i < pnum; i++) {
244 x = fastrand () % (width - 1);
245 y = fastrand () % (height - 1);
247 size = fastrand () >> 28;
249 for (j = 0; j < size; j++) {
250 x = x + fastrand () % 3 - 1;
251 y = y + fastrand () % 3 - 1;
253 if (y >= height || x >= width)
256 dest[y * width + x] = 0xc0c0c0;
262 gst_agingtv_get_property (GObject * object, guint prop_id,
263 GValue * value, GParamSpec * pspec)
265 GstAgingTV *agingtv = GST_AGINGTV (object);
267 GST_OBJECT_LOCK (agingtv);
269 case PROP_SCRATCH_LINES:
270 g_value_set_uint (value, agingtv->scratch_lines);
272 case PROP_COLOR_AGING:
273 g_value_set_boolean (value, agingtv->color_aging);
276 g_value_set_boolean (value, agingtv->pits);
279 g_value_set_boolean (value, agingtv->dusts);
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284 GST_OBJECT_UNLOCK (agingtv);
288 gst_agingtv_set_property (GObject * object, guint prop_id,
289 const GValue * value, GParamSpec * pspec)
291 GstAgingTV *agingtv = GST_AGINGTV (object);
294 case PROP_SCRATCH_LINES:
295 agingtv->scratch_lines = g_value_get_uint (value);
297 case PROP_COLOR_AGING:
298 agingtv->color_aging = g_value_get_boolean (value);
301 agingtv->pits = g_value_get_boolean (value);
304 agingtv->dusts = g_value_get_boolean (value);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
312 gst_agingtv_start (GstBaseTransform * trans)
314 GstAgingTV *agingtv = GST_AGINGTV (trans);
316 agingtv->coloraging_state = 0x18;
317 agingtv->dust_interval = 0;
318 agingtv->pits_interval = 0;
320 memset (agingtv->scratches, 0, sizeof (agingtv->scratches));
326 gst_agingtv_transform (GstBaseTransform * trans, GstBuffer * in,
329 GstAgingTV *agingtv = GST_AGINGTV (trans);
330 gint width, height, video_size;
331 guint32 *src = (guint32 *) GST_BUFFER_DATA (in);
332 guint32 *dest = (guint32 *) GST_BUFFER_DATA (out);
334 GstFlowReturn ret = GST_FLOW_OK;
335 GstClockTime timestamp, stream_time;
337 timestamp = GST_BUFFER_TIMESTAMP (in);
339 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
341 GST_DEBUG_OBJECT (agingtv, "sync to %" GST_TIME_FORMAT,
342 GST_TIME_ARGS (timestamp));
344 if (GST_CLOCK_TIME_IS_VALID (stream_time))
345 gst_object_sync_values (G_OBJECT (agingtv), stream_time);
347 GST_OBJECT_LOCK (agingtv);
348 width = agingtv->width;
349 height = agingtv->height;
350 video_size = width * height;
352 area_scale = width * height / 64 / 480;
356 if (agingtv->color_aging)
357 coloraging (src, dest, video_size, &agingtv->coloraging_state);
359 memcpy (dest, src, GST_BUFFER_SIZE (in));
361 scratching (agingtv->scratches, agingtv->scratch_lines, dest, width, height);
363 pits (dest, width, height, area_scale, &agingtv->pits_interval);
364 if (area_scale > 1 && agingtv->dusts)
365 dusts (dest, width, height, &agingtv->dust_interval, area_scale);
366 GST_OBJECT_UNLOCK (agingtv);
372 gst_agingtv_base_init (gpointer g_class)
374 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
376 gst_element_class_set_details_simple (element_class, "AgingTV effect",
377 "Filter/Effect/Video",
378 "AgingTV adds age to video input using scratches and dust",
379 "Sam Lantinga <slouken@devolution.com>");
381 gst_element_class_add_static_pad_template (element_class,
382 &gst_agingtv_sink_template);
383 gst_element_class_add_static_pad_template (element_class,
384 &gst_agingtv_src_template);
388 gst_agingtv_class_init (GstAgingTVClass * klass)
390 GObjectClass *gobject_class = (GObjectClass *) klass;
391 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
393 gobject_class->set_property = gst_agingtv_set_property;
394 gobject_class->get_property = gst_agingtv_get_property;
396 g_object_class_install_property (gobject_class, PROP_SCRATCH_LINES,
397 g_param_spec_uint ("scratch-lines", "Scratch Lines",
398 "Number of scratch lines", 0, SCRATCH_MAX, DEFAULT_SCRATCH_LINES,
399 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
401 g_object_class_install_property (gobject_class, PROP_COLOR_AGING,
402 g_param_spec_boolean ("color-aging", "Color Aging",
403 "Color Aging", DEFAULT_COLOR_AGING,
404 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
406 g_object_class_install_property (gobject_class, PROP_PITS,
407 g_param_spec_boolean ("pits", "Pits",
408 "Pits", DEFAULT_PITS,
409 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
411 g_object_class_install_property (gobject_class, PROP_DUSTS,
412 g_param_spec_boolean ("dusts", "Dusts",
413 "Dusts", DEFAULT_DUSTS,
414 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
416 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_agingtv_set_caps);
417 trans_class->transform = GST_DEBUG_FUNCPTR (gst_agingtv_transform);
418 trans_class->start = GST_DEBUG_FUNCPTR (gst_agingtv_start);
422 gst_agingtv_init (GstAgingTV * agingtv, GstAgingTVClass * klass)
424 agingtv->scratch_lines = DEFAULT_SCRATCH_LINES;
425 agingtv->color_aging = DEFAULT_COLOR_AGING;
426 agingtv->pits = DEFAULT_PITS;
427 agingtv->dusts = DEFAULT_DUSTS;