2
* Copyright (C) 2006 Mark Nauwelaerts <mnauw@users.sourceforge.net>
5
* Copyright (C) 1999-2000 Donald A. Graft
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-xsharpen
27
* This filter performs a subtle but useful sharpening effect. The result
28
* is a sharpening effect that not only avoids amplifying noise, but also
29
* tends to reduce it. A welcome side effect is that files processed with
30
* this filter tend to compress to smaller files.
34
* When <link linkend="GstMsharpen--strength">strength</link>
35
* is maximal, mapped pixels are not blended with the original pixel values,
36
* so a full-strength effect is achieved. As the value is reduced, each
37
* mapped pixel is blended with more of the original pixel. At a value of 0,
38
* the original pixels are passed through and there is no sharpening effect.
43
* <link linkend="GstMsharpen--threshold">threshold</link> indicates how
44
* close a pixel must be to the brightest or dimmest pixel to be mapped.
45
* If a pixel is more than threshold away from the brightest or dimmest pixel,
46
* it is not mapped. Thus, as the threshold is reduced, pixels in the mid
47
* range start to be spared.
52
* <title>History</title>
56
* VirtualDub xsharpen filter [Donald A. Graft]
59
* Also available in transcode (xsharpen filter)
71
#include "plugin-vd.h"
76
#define GST_TYPE_XSHARPEN \
77
(gst_xsharpen_get_type())
78
#define GST_XSHARPEN(obj) \
79
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XSHARPEN,GstXsharpen))
80
#define GST_XSHARPEN_CLASS(klass) \
81
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XSHARPEN,GstXsharpenClass))
82
#define GST_IS_XSHARPEN(obj) \
83
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XSHARPEN))
84
#define GST_IS_XSHARPEN_CLASS(klass) \
85
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XSHARPEN))
88
typedef struct _GstXsharpen GstXsharpen;
89
typedef struct _GstXsharpenClass GstXsharpenClass;
93
GstVideoFilter videofilter;
97
guint threshold, strength;
101
struct _GstXsharpenClass
103
GstVideoFilterClass parent_class;
106
GST_DEBUG_CATEGORY_STATIC (xsharpen_debug);
107
#define GST_CAT_DEFAULT xsharpen_debug
110
/* signals and args */
125
#define DEFAULT_THRESHOLD 256
126
#define DEFAULT_STRENGTH 200
128
static GstElementDetails xsharpen_details =
129
GST_ELEMENT_DETAILS ("Deinter",
130
"Filter/Effect/Video",
131
"Sharpen by mapping pixels to the closest of window max or min",
132
"Mark Nauwelaerts <mnauw@users.sourceforge.net>,\n"
135
static GstStaticPadTemplate gst_xsharpen_src_template =
136
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
139
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
142
static GstStaticPadTemplate gst_xsharpen_sink_template =
143
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
146
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
149
static GstFlowReturn gst_xsharpen_transform (GstBaseTransform * btrans,
150
GstBuffer * in, GstBuffer * out);
151
static gboolean gst_xsharpen_start (GstBaseTransform * btrans);
152
static gboolean gst_xsharpen_stop (GstBaseTransform * btrans);
154
static void gst_xsharpen_set_property (GObject * object, guint prop_id,
155
const GValue * value, GParamSpec * pspec);
156
static void gst_xsharpen_get_property (GObject * object, guint prop_id,
157
GValue * value, GParamSpec * pspec);
159
GST_BOILERPLATE (GstXsharpen, gst_xsharpen, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
161
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE (GstXsharpen, gst_xsharpen);
163
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_xsharpen);
166
gst_xsharpen_base_init (gpointer g_class)
168
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
170
gst_element_class_set_details (element_class, &xsharpen_details);
172
gst_element_class_add_pad_template (element_class,
173
gst_static_pad_template_get (&gst_xsharpen_sink_template));
174
gst_element_class_add_pad_template (element_class,
175
gst_static_pad_template_get (&gst_xsharpen_src_template));
179
gst_xsharpen_class_init (GstXsharpenClass * g_class)
181
GObjectClass *gobject_class;
182
GstBaseTransformClass *trans_class;
184
gobject_class = G_OBJECT_CLASS (g_class);
185
trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
187
GST_DEBUG_CATEGORY_INIT (xsharpen_debug, "xsharpen", 0, "xsharpen");
189
gobject_class->set_property = gst_xsharpen_set_property;
190
gobject_class->get_property = gst_xsharpen_get_property;
192
g_object_class_install_property (gobject_class, PROP_THRESHOLD,
193
g_param_spec_uint ("threshold", "Threshold",
194
"Threshold for pixel to be mapped",
195
0, 256, DEFAULT_THRESHOLD, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
197
g_object_class_install_property (gobject_class, PROP_STRENGTH,
198
g_param_spec_uint ("strength", "Strength",
199
"Strength/weight of modification of a mapped pixel",
200
0, 256, DEFAULT_STRENGTH, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
202
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_xsharpen_set_caps);
203
trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_xsharpen_get_unit_size);
204
trans_class->transform = GST_DEBUG_FUNCPTR (gst_xsharpen_transform);
205
trans_class->start = GST_DEBUG_FUNCPTR (gst_xsharpen_start);
206
trans_class->stop = GST_DEBUG_FUNCPTR (gst_xsharpen_stop);
210
gst_xsharpen_init (GstXsharpen * filter, GstXsharpenClass * g_class)
212
filter->threshold = DEFAULT_THRESHOLD;
213
filter->strength = DEFAULT_STRENGTH;
217
gst_xsharpen_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
221
GstFlowReturn ret = GST_FLOW_OK;
223
gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
225
filter = GST_XSHARPEN (btrans);
227
src = (guint8 *) GST_BUFFER_DATA (in);
228
dest = (guint8 *) GST_BUFFER_DATA (out);
230
guint width = filter->width;
231
guint height = filter->height;
233
guint strength = filter->strength;
234
guint invstrength = 256 - strength;
235
guint threshold = filter->threshold;
237
guint stride = GST_VIDEO_I420_Y_ROWSTRIDE (width);
239
/* first copy everything so that chroma info is transferred
240
* also need to pass-through border luma lines as well */
241
memcpy (dest, src, GST_BUFFER_SIZE (in));
243
/* run the 3x3 rank-order sharpening kernel over the pixels */
247
guint x, y, luma, maxdiff, mindiff;
249
for (y = 1; y < height - 1; y++) {
251
for (x = 1; x < width - 1; x++) {
252
/* find the brightest and dimmest pixels in the 3x3 window
253
* surrounding the current pixel */
254
guint lumamax = -1000;
255
guint lumamin = 1000;
258
luma = (src - stride)[x-1];
264
luma = (src - stride)[x];
270
luma = (src - stride)[x+1];
295
luma = (src + stride)[x-1];
301
luma = (src + stride)[x];
307
luma = (src + stride)[x+1];
313
/* Determine whether the current pixel is closer to the
314
* brightest or the dimmest pixel. Then compare the current
315
* pixel to that closest pixel. If the difference is within
316
* threshold, map the current pixel to the closest pixel;
317
* otherwise pass it through. */
321
mindiff = lumac - lumamin;
322
maxdiff = lumamax - lumac;
323
if (mindiff > maxdiff) {
324
if (maxdiff < threshold)
328
if (mindiff < threshold)
337
lumac = src[x] & 0xff;
338
t = ((strength * p + invstrength * lumac) >> 8) & 0xff;
355
gst_xsharpen_start (GstBaseTransform * btrans)
361
gst_xsharpen_stop (GstBaseTransform * btrans)
367
gst_xsharpen_set_property (GObject * object, guint prop_id,
368
const GValue * value, GParamSpec * pspec)
372
g_return_if_fail (GST_IS_XSHARPEN (object));
373
src = GST_XSHARPEN (object);
377
src->threshold = g_value_get_uint (value);
380
src->strength = g_value_get_uint (value);
383
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
389
gst_xsharpen_get_property (GObject * object, guint prop_id, GValue * value,
394
g_return_if_fail (GST_IS_XSHARPEN (object));
395
src = GST_XSHARPEN (object);
399
g_value_set_uint (value, src->threshold);
402
g_value_set_uint (value, src->strength);
405
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);