2
* Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sourceforge.net>
5
* Copyright (C) Mean - 2002
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1307 USA
23
* SECTION:element-stabilize
27
* Light-weight denoising/smoothing using previous and next frames.
29
* <title>History</title>
33
* avidemux stabilize filter [Mean]
45
#include "plugin-ad.h"
48
#define GST_TYPE_SOFTEN \
49
(gst_stabilize_get_type())
50
#define GST_STABILIZE(obj) \
51
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOFTEN,GstStabilize))
52
#define GST_STABILIZE_CLASS(klass) \
53
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SOFTEN,GstStabilizeClass))
54
#define GST_IS_SOFTEN(obj) \
55
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOFTEN))
56
#define GST_IS_SOFTEN_CLASS(klass) \
57
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOFTEN))
59
typedef struct _GstStabilize GstStabilize;
60
typedef struct _GstStabilizeClass GstStabilizeClass;
65
GstVideoFilter videofilter;
69
/* past/future buffers */
73
/* stabilize parameters */
77
struct _GstStabilizeClass
79
GstVideoFilterClass parent_class;
82
GST_DEBUG_CATEGORY_STATIC (smooth_debug);
83
#define GST_CAT_DEFAULT smooth_debug
85
/* signals and args */
99
#define DEFAULT_LUMA_THRESHOLD 30
102
static GstElementDetails smooth_details =
103
GST_ELEMENT_DETAILS ("Soften",
104
"Filter/Effect/Video",
106
"Mark Nauwelaerts <mnauw@users.sourceforge.net>,\n"
109
static GstStaticPadTemplate gst_stabilize_src_template =
110
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
113
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
116
static GstStaticPadTemplate gst_stabilize_sink_template =
117
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
120
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
123
static gboolean gst_stabilize_hook_caps (GstStabilize * filter,
124
GstCaps * incaps, GstCaps * outcaps);
125
static gboolean gst_stabilize_sink_event (GstBaseTransform * btrans,
127
static GstFlowReturn gst_stabilize_transform (GstBaseTransform * btrans,
128
GstBuffer * in, GstBuffer * out);
129
static gboolean gst_stabilize_start (GstBaseTransform * btrans);
130
static gboolean gst_stabilize_stop (GstBaseTransform * btrans);
132
static void gst_stabilize_set_property (GObject * object, guint prop_id,
133
const GValue * value, GParamSpec * pspec);
134
static void gst_stabilize_get_property (GObject * object, guint prop_id,
135
GValue * value, GParamSpec * pspec);
137
GST_BOILERPLATE (GstStabilize, gst_stabilize, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
139
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE_FULL (GstStabilize, gst_stabilize,
140
gst_stabilize_hook_caps);
142
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_stabilize);
145
gst_stabilize_base_init (gpointer g_class)
147
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
149
gst_element_class_set_details (element_class, &smooth_details);
151
gst_element_class_add_pad_template (element_class,
152
gst_static_pad_template_get (&gst_stabilize_sink_template));
153
gst_element_class_add_pad_template (element_class,
154
gst_static_pad_template_get (&gst_stabilize_src_template));
158
gst_stabilize_class_init (GstStabilizeClass * g_class)
160
GObjectClass *gobject_class;
161
GstBaseTransformClass *trans_class;
163
gobject_class = G_OBJECT_CLASS (g_class);
164
trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
166
GST_DEBUG_CATEGORY_INIT (smooth_debug, "smooth", 0, "smooth");
168
gobject_class->set_property = gst_stabilize_set_property;
169
gobject_class->get_property = gst_stabilize_get_property;
171
g_object_class_install_property (gobject_class, PROP_LUMA_THRESHOLD,
172
g_param_spec_uint ("luma-threshold", "Luma Threshold", "Luma Threshold",
173
1, 255, DEFAULT_LUMA_THRESHOLD,
174
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
176
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_stabilize_set_caps);
177
trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_stabilize_get_unit_size);
178
trans_class->transform = GST_DEBUG_FUNCPTR (gst_stabilize_transform);
179
trans_class->event = GST_DEBUG_FUNCPTR (gst_stabilize_sink_event);
180
trans_class->start = GST_DEBUG_FUNCPTR (gst_stabilize_start);
181
trans_class->stop = GST_DEBUG_FUNCPTR (gst_stabilize_stop);
185
gst_stabilize_init (GstStabilize * filter, GstStabilizeClass * g_class)
187
filter->luma_threshold = DEFAULT_LUMA_THRESHOLD;
190
// TODO consider this as a library function
191
/* empties queue and resets frame count */
193
gst_stabilize_flush (GstStabilize * filter, gboolean send)
196
GstBaseTransform *btrans;
199
btrans = GST_BASE_TRANSFORM (filter);
202
for (i = 2; i >= 0; i--) {
203
buf = filter->queue[i];
205
filter->queue[i] = NULL;
207
gst_buffer_set_caps (buf, GST_PAD_CAPS (btrans->srcpad));
208
gst_pad_push (btrans->srcpad, buf);
211
gst_buffer_unref (buf);
217
gst_stabilize_hook_caps (GstStabilize * filter, GstCaps * incaps,
220
gst_stabilize_flush (filter, TRUE);
226
gst_stabilize_sink_event (GstBaseTransform * btrans, GstEvent * event)
228
GstStabilize *filter;
230
filter = GST_STABILIZE (btrans);
232
switch (GST_EVENT_TYPE (event)) {
234
gst_stabilize_flush (filter, TRUE);
240
return GST_BASE_TRANSFORM_CLASS (parent_class)->event (btrans, event);
244
/* see below for specific (loop) context */
245
#define PONDERATE(x) G_STMT_START { \
246
if (distMatrix[*incur][x] < threshold) { \
253
gst_stabilize (guint8 * src, guint8 * dst, guint8 * src_prev, guint8 * src_next,
254
gint width, gint height, gint threshold)
256
guint8 *inprev, *innext, *incur, *nl, *pl, *nc, *pc, *zout;
259
inprev = src_prev + width + 1;
260
innext = src_next + width + 1;
261
incur = src + width + 1;
262
zout = dst + width + 1;
264
for (y = height - 1; y > 1; y--) {
270
for (x = width - 1; x > 1; x--) {
282
*zout = (c * fixMul[coeff]) >> 16;
293
/* proceed to next line */
302
gst_stabilize_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
304
GstStabilize *filter;
307
gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
309
filter = GST_STABILIZE (btrans);
311
filter->queue[filter->count] = gst_buffer_ref (in);
314
if (filter->count < 3)
315
return GST_BASE_TRANSFORM_FLOW_DROPPED;
317
src = (guint8 *) GST_BUFFER_DATA (filter->queue[1]);
318
dest = (guint8 *) GST_BUFFER_DATA (out);
320
oil_memcpy (dest, src, GST_VIDEO_I420_SIZE (filter->width, filter->height));
322
/* only luma is processed */
323
gst_stabilize (src, dest, GST_BUFFER_DATA (filter->queue[0]),
324
GST_BUFFER_DATA (filter->queue[1]),
325
GST_VIDEO_I420_Y_ROWSTRIDE (filter->width), filter->height,
326
filter->luma_threshold);
328
gst_buffer_unref (filter->queue[0]);
329
filter->queue[0] = filter->queue[1];
330
filter->queue[1] = filter->queue[2];
331
filter->queue[2] = NULL;
338
gst_stabilize_start (GstBaseTransform * btrans)
345
gst_stabilize_stop (GstBaseTransform * btrans)
347
GstStabilize *filter = GST_STABILIZE (btrans);
349
gst_stabilize_flush (filter, FALSE);
355
gst_stabilize_set_property (GObject * object, guint prop_id,
356
const GValue * value, GParamSpec * pspec)
360
g_return_if_fail (GST_IS_SOFTEN (object));
361
src = GST_STABILIZE (object);
364
case PROP_LUMA_THRESHOLD:
365
src->luma_threshold = g_value_get_uint (value);
368
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374
gst_stabilize_get_property (GObject * object, guint prop_id, GValue * value,
379
g_return_if_fail (GST_IS_SOFTEN (object));
380
src = GST_STABILIZE (object);
383
case PROP_LUMA_THRESHOLD:
384
g_value_set_uint (value, src->luma_threshold);
387
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);