2
* Copyright (C) 2006 Mark Nauwelaerts <mnauw@users.sourceforge.net>
5
* Copyright (C) Chad Page - October 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-smooth
27
* Performs "single-frame" smoothing, that is, it only works with the current
28
* frame, it does not need the next or the previous frame.
29
* Usually smoothing is done by taking the data of previous frames into account
30
* to see which parts of the picture can be "safely" smoothed, this filter only
33
* <title>History</title>
37
* transcode smooth filter [Chad Page]
49
#include "plugin-tc.h"
53
#define GST_TYPE_SMOOTH \
54
(gst_smooth_get_type())
55
#define GST_SMOOTH(obj) \
56
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOOTH,GstSmooth))
57
#define GST_SMOOTH_CLASS(klass) \
58
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOOTH,GstSmoothClass))
59
#define GST_IS_SMOOTH(obj) \
60
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOOTH))
61
#define GST_IS_SMOOTH_CLASS(klass) \
62
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOOTH))
64
typedef struct _GstSmooth GstSmooth;
65
typedef struct _GstSmoothClass GstSmoothClass;
70
GstVideoFilter videofilter;
74
/* denoise parameters */
76
guint chroma_diff, luma_diff, search_range;
79
struct _GstSmoothClass
81
GstVideoFilterClass parent_class;
84
GST_DEBUG_CATEGORY_STATIC (smooth_debug);
85
#define GST_CAT_DEFAULT smooth_debug
87
/* signals and args */
104
#define DEFAULT_BLEND_FACTOR 0.25
105
#define DEFAULT_CHROMA_DIFF 6
106
#define DEFAULT_LUMA_DIFF 8
107
#define DEFAULT_SEARCH_RANGE 4
108
#define MAX_BLEND_FACTOR 1.0
109
#define MAX_CHROMA_DIFF 16
110
#define MAX_LUMA_DIFF 16
111
#define MAX_SEARCH_RANGE 16
114
static GstElementDetails smooth_details =
115
GST_ELEMENT_DETAILS ("Smooth",
116
"Filter/Effect/Video",
117
"Smoothing (single frame)",
118
"Mark Nauwelaerts <mnauw@users.sourceforge.net>,\n"
121
static GstStaticPadTemplate gst_smooth_src_template =
122
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
125
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
128
static GstStaticPadTemplate gst_smooth_sink_template =
129
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
132
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
135
static GstFlowReturn gst_smooth_transform (GstBaseTransform * btrans,
136
GstBuffer * in, GstBuffer * out);
137
static gboolean gst_smooth_start (GstBaseTransform * btrans);
138
static gboolean gst_smooth_stop (GstBaseTransform * btrans);
140
static void gst_smooth_set_property (GObject * object, guint prop_id,
141
const GValue * value, GParamSpec * pspec);
142
static void gst_smooth_get_property (GObject * object, guint prop_id,
143
GValue * value, GParamSpec * pspec);
145
GST_BOILERPLATE (GstSmooth, gst_smooth, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
147
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE (GstSmooth, gst_smooth);
149
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_smooth);
152
gst_smooth_base_init (gpointer g_class)
154
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
156
gst_element_class_set_details (element_class, &smooth_details);
158
gst_element_class_add_pad_template (element_class,
159
gst_static_pad_template_get (&gst_smooth_sink_template));
160
gst_element_class_add_pad_template (element_class,
161
gst_static_pad_template_get (&gst_smooth_src_template));
165
gst_smooth_class_init (GstSmoothClass * g_class)
167
GObjectClass *gobject_class;
168
GstBaseTransformClass *trans_class;
170
gobject_class = G_OBJECT_CLASS (g_class);
171
trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
173
GST_DEBUG_CATEGORY_INIT (smooth_debug, "smooth", 0, "smooth");
175
gobject_class->set_property = gst_smooth_set_property;
176
gobject_class->get_property = gst_smooth_get_property;
178
g_object_class_install_property (gobject_class, PROP_BLEND_FACTOR,
179
g_param_spec_float ("blend-factor", "Blend Factor", "Blend Factor",
180
0, MAX_BLEND_FACTOR, DEFAULT_BLEND_FACTOR,
181
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
183
g_object_class_install_property (gobject_class, PROP_CHROMA_DIFF,
184
g_param_spec_uint ("chroma-diff", "Chroma Difference", "Maximum Chroma Difference",
185
0, MAX_CHROMA_DIFF, DEFAULT_CHROMA_DIFF,
186
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
188
g_object_class_install_property (gobject_class, PROP_LUMA_DIFF,
189
g_param_spec_uint ("luma-diff", "Luma Difference", "Maximum Luma Difference",
190
0, MAX_LUMA_DIFF, DEFAULT_LUMA_DIFF,
191
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
193
g_object_class_install_property (gobject_class, PROP_SEARCH_RANGE,
194
g_param_spec_uint ("search-range", "Search Range", "Search Range",
195
0, MAX_SEARCH_RANGE, DEFAULT_SEARCH_RANGE,
196
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
198
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_smooth_set_caps);
199
trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_smooth_get_unit_size);
200
trans_class->transform = GST_DEBUG_FUNCPTR (gst_smooth_transform);
201
trans_class->start = GST_DEBUG_FUNCPTR (gst_smooth_start);
202
trans_class->stop = GST_DEBUG_FUNCPTR (gst_smooth_stop);
206
gst_smooth_init (GstSmooth * filter, GstSmoothClass * g_class)
208
filter->blend_factor = DEFAULT_BLEND_FACTOR;
209
filter->chroma_diff = DEFAULT_CHROMA_DIFF;
210
filter->luma_diff = DEFAULT_LUMA_DIFF;
211
filter->search_range = DEFAULT_SEARCH_RANGE;
215
gst_smooth (guint8 * src, guint8 * buf, gint width, gint height, gint maxdiff,
216
gint maxldiff, gint maxdist, gfloat level)
218
gint x, y, pu, cpu, cdiff;
219
gint xa, ya, oval, ldiff;
220
guint8 *bufcr, *bufcb;
221
guint8 *tbufcr, *tbufcb, *ltbuf;
222
gfloat dist, ratio, nval;
225
tbufcr = ltbuf + GST_VIDEO_I420_U_OFFSET (width, height);
226
tbufcb = ltbuf + GST_VIDEO_I420_V_OFFSET (width, height);
228
bufcr = buf + GST_VIDEO_I420_U_OFFSET (width, height);
229
bufcb = buf + GST_VIDEO_I420_V_OFFSET (width, height);
231
/* First pass - horizontal */
232
for (y = 0; y < (height); y++) {
233
for (x = 0; x < width; x++) {
234
pu = ((y >> 1) * (width >> 1)) + (x >> 1);
235
nval = ((gfloat) buf[x + (y * width)]);
236
oval = buf[x + (y * width)];
237
for (xa = x - maxdist; (xa <= (x + maxdist)) && (xa < width); xa++) {
240
if ((xa == x) && (xa < width - 1))
242
cpu = ((y >> 1) * (width >> 1)) + (xa >> 1);
243
cdiff = abs (tbufcr[pu] - tbufcr[cpu]);
244
cdiff += abs (tbufcb[pu] - tbufcb[cpu]);
246
/* If color difference not too great,
247
* average the pixel according to distance */
248
ldiff = abs(ltbuf[xa + (y * width)] - oval);
249
if ((cdiff < maxdiff) && (ldiff < maxldiff)) {
251
ratio = level / dist;
252
nval = nval * (1 - ratio);
253
nval += ((gfloat) ltbuf[xa + (y * width)]) * ratio;
256
buf[x + (y * width)] = (guint8) (nval + 0.5);
260
/* Second pass - vertical lines */
261
for (y = 0; y < (height); y++) {
262
for (x = 0; x < width; x++) {
263
pu = ((y >> 1) * (width >> 1)) + (x >> 1);
264
nval = ((gfloat) buf[x + (y * width)]);
265
oval = buf[x + (y * width)];
266
for (ya = y - maxdist; (ya <= (y + maxdist)) && (ya < height); ya++) {
269
if ((ya == y) && (ya < height - 1))
271
cpu = ((ya >> 1) * (width >> 1)) + (x >> 1);
272
cdiff = abs (tbufcr[pu] - tbufcr[cpu]);
273
cdiff += abs (tbufcb[pu] - tbufcb[cpu]);
275
/* If color difference not too great,
276
* average the pixel according to distance */
277
ldiff = abs (ltbuf[x + (ya * width)] - oval);
278
if ((cdiff < maxdiff) && (ldiff < maxldiff)) {
280
ratio = level / dist;
281
nval = nval * (1 - ratio);
282
nval += ((gfloat) ltbuf[x + (ya * width)]) * ratio;
285
buf[x + (y * width)] = (guint8) (nval + 0.5);
291
gst_smooth_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
296
gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
298
filter = GST_SMOOTH (btrans);
300
src = (guint8 *) GST_BUFFER_DATA (in);
301
dest = (guint8 *) GST_BUFFER_DATA (out);
303
oil_memcpy (dest, src, GST_VIDEO_I420_SIZE (filter->width, filter->height));
305
gst_smooth (src, dest, GST_VIDEO_I420_Y_ROWSTRIDE (filter->width),
306
filter->height, filter->chroma_diff, filter->luma_diff,
307
filter->search_range, filter->blend_factor);
313
gst_smooth_start (GstBaseTransform * btrans)
320
gst_smooth_stop (GstBaseTransform * btrans)
327
gst_smooth_set_property (GObject * object, guint prop_id,
328
const GValue * value, GParamSpec * pspec)
332
g_return_if_fail (GST_IS_SMOOTH (object));
333
src = GST_SMOOTH (object);
336
case PROP_BLEND_FACTOR:
337
src->blend_factor = g_value_get_float (value);
339
case PROP_CHROMA_DIFF:
340
src->chroma_diff = g_value_get_uint (value);
343
src->luma_diff = g_value_get_uint (value);
345
case PROP_SEARCH_RANGE:
346
src->search_range = g_value_get_uint (value);
349
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355
gst_smooth_get_property (GObject * object, guint prop_id, GValue * value,
360
g_return_if_fail (GST_IS_SMOOTH (object));
361
src = GST_SMOOTH (object);
364
case PROP_BLEND_FACTOR:
365
g_value_set_float (value, src->blend_factor);
367
case PROP_CHROMA_DIFF:
368
g_value_set_uint (value, src->chroma_diff);
371
g_value_set_uint (value, src->luma_diff);
373
case PROP_SEARCH_RANGE:
374
g_value_set_uint (value, src->search_range);
377
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);