~ubuntu-branches/ubuntu/natty/gst-entrans/natty

« back to all changes in this revision

Viewing changes to gst/virtualdub/gstxsharpen.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2010-09-13 19:49:29 UTC
  • Revision ID: james.westby@ubuntu.com-20100913194929-qz90a14xyxln9yfz
Tags: upstream-0.10.2
ImportĀ upstreamĀ versionĀ 0.10.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer Element
 
2
 * Copyright (C) 2006 Mark Nauwelaerts <mnauw@users.sourceforge.net>
 
3
 *
 
4
 * VirtualDub filter:
 
5
 * Copyright (C) 1999-2000 Donald A. Graft
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 */
 
21
 
 
22
/**
 
23
 * SECTION:element-xsharpen
 
24
 *
 
25
 * <refsect2>
 
26
 * <para>
 
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.
 
31
 * <itemizedlist>
 
32
 * <listitem>
 
33
 * <para>
 
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.
 
39
 * </para>
 
40
 * </listitem>
 
41
 * <listitem>
 
42
 * <para>
 
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.
 
48
 * </para>
 
49
 * </listitem>
 
50
 * </itemizedlist>
 
51
 * </para>
 
52
 * <title>History</title>
 
53
 * <para>
 
54
 * <itemizedlist>
 
55
 * <listitem>
 
56
 * VirtualDub xsharpen filter [Donald A. Graft]
 
57
 * </listitem>
 
58
 * <listitem>
 
59
 * Also available in transcode (xsharpen filter)
 
60
 * </listitem>
 
61
 * </itemizedlist>
 
62
 * </para>
 
63
 * </refsect2>
 
64
 */
 
65
 
 
66
 
 
67
#ifdef HAVE_CONFIG_H
 
68
#include "config.h"
 
69
#endif
 
70
 
 
71
#include "plugin-vd.h"
 
72
 
 
73
#include <string.h>
 
74
 
 
75
 
 
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))
 
86
 
 
87
 
 
88
typedef struct _GstXsharpen GstXsharpen;
 
89
typedef struct _GstXsharpenClass GstXsharpenClass;
 
90
 
 
91
struct _GstXsharpen
 
92
{
 
93
  GstVideoFilter videofilter;
 
94
 
 
95
  gint width, height;
 
96
 
 
97
  guint threshold, strength;
 
98
};
 
99
 
 
100
 
 
101
struct _GstXsharpenClass
 
102
{
 
103
  GstVideoFilterClass parent_class;
 
104
};
 
105
 
 
106
GST_DEBUG_CATEGORY_STATIC (xsharpen_debug);
 
107
#define GST_CAT_DEFAULT xsharpen_debug
 
108
 
 
109
 
 
110
/* signals and args */
 
111
enum
 
112
{
 
113
  /* FILL ME */
 
114
  LAST_SIGNAL
 
115
};
 
116
 
 
117
enum
 
118
{
 
119
  PROP_0,
 
120
  PROP_THRESHOLD,
 
121
  PROP_STRENGTH
 
122
      /* FILL ME */
 
123
};
 
124
 
 
125
#define DEFAULT_THRESHOLD  256
 
126
#define DEFAULT_STRENGTH   200
 
127
 
 
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"
 
133
    "Donald A. Graft");
 
134
 
 
135
static GstStaticPadTemplate gst_xsharpen_src_template =
 
136
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
 
137
    GST_PAD_SRC,
 
138
    GST_PAD_ALWAYS,
 
139
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
140
    );
 
141
 
 
142
static GstStaticPadTemplate gst_xsharpen_sink_template =
 
143
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
 
144
    GST_PAD_SINK,
 
145
    GST_PAD_ALWAYS,
 
146
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
147
    );
 
148
 
 
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);
 
153
 
 
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);
 
158
 
 
159
GST_BOILERPLATE (GstXsharpen, gst_xsharpen, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
 
160
 
 
161
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE (GstXsharpen, gst_xsharpen);
 
162
 
 
163
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_xsharpen);
 
164
 
 
165
static void
 
166
gst_xsharpen_base_init (gpointer g_class)
 
167
{
 
168
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
169
 
 
170
  gst_element_class_set_details (element_class, &xsharpen_details);
 
171
 
 
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));
 
176
}
 
177
 
 
178
static void
 
179
gst_xsharpen_class_init (GstXsharpenClass * g_class)
 
180
{
 
181
  GObjectClass *gobject_class;
 
182
  GstBaseTransformClass *trans_class;
 
183
 
 
184
  gobject_class = G_OBJECT_CLASS (g_class);
 
185
  trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
 
186
 
 
187
  GST_DEBUG_CATEGORY_INIT (xsharpen_debug, "xsharpen", 0, "xsharpen");
 
188
 
 
189
  gobject_class->set_property = gst_xsharpen_set_property;
 
190
  gobject_class->get_property = gst_xsharpen_get_property;
 
191
 
 
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));
 
196
 
 
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));
 
201
 
 
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);
 
207
}
 
208
 
 
209
static void
 
210
gst_xsharpen_init (GstXsharpen * filter, GstXsharpenClass * g_class)
 
211
{
 
212
  filter->threshold = DEFAULT_THRESHOLD;
 
213
  filter->strength = DEFAULT_STRENGTH;
 
214
}
 
215
 
 
216
static GstFlowReturn
 
217
gst_xsharpen_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
 
218
{
 
219
  GstXsharpen *filter;
 
220
  guint8 *src, *dest;
 
221
  GstFlowReturn ret = GST_FLOW_OK;
 
222
 
 
223
  gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
 
224
 
 
225
  filter = GST_XSHARPEN (btrans);
 
226
 
 
227
  src = (guint8 *) GST_BUFFER_DATA (in);
 
228
  dest = (guint8 *) GST_BUFFER_DATA (out);
 
229
 
 
230
  guint width = filter->width;
 
231
  guint height = filter->height;
 
232
 
 
233
  guint strength = filter->strength;
 
234
  guint invstrength = 256 - strength;
 
235
  guint threshold = filter->threshold;
 
236
 
 
237
  guint stride = GST_VIDEO_I420_Y_ROWSTRIDE (width);
 
238
 
 
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));
 
242
 
 
243
  /* run the 3x3 rank-order sharpening kernel over the pixels */
 
244
  src += stride;
 
245
  dest += stride;
 
246
 
 
247
  guint x, y, luma, maxdiff, mindiff;
 
248
 
 
249
  for (y = 1; y < height - 1; y++) {
 
250
 
 
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;
 
256
      guint lumac;
 
257
 
 
258
      luma = (src - stride)[x-1];
 
259
      if (luma > lumamax)
 
260
        lumamax = luma;
 
261
      if (luma < lumamin)
 
262
        lumamin = luma;
 
263
 
 
264
      luma = (src - stride)[x];
 
265
      if (luma > lumamax)
 
266
        lumamax = luma;
 
267
      if (luma < lumamin)
 
268
        lumamin = luma;
 
269
 
 
270
      luma = (src - stride)[x+1];
 
271
      if (luma > lumamax)
 
272
        lumamax = luma;
 
273
      if (luma < lumamin)
 
274
        lumamin = luma;
 
275
 
 
276
      luma = src[x-1];
 
277
      if (luma > lumamax)
 
278
        lumamax = luma;
 
279
      if (luma < lumamin)
 
280
        lumamin = luma;
 
281
 
 
282
      luma = src[x];
 
283
      lumac = luma;
 
284
      if (luma > lumamax)
 
285
        lumamax = luma;
 
286
      if (luma < lumamin)
 
287
        lumamin = luma;
 
288
 
 
289
      luma = src[x+1];
 
290
      if (luma > lumamax)
 
291
        lumamax = luma;
 
292
      if (luma < lumamin)
 
293
        lumamin = luma;
 
294
 
 
295
      luma = (src + stride)[x-1];
 
296
      if (luma > lumamax)
 
297
        lumamax = luma;
 
298
      if (luma < lumamin)
 
299
        lumamin = luma;
 
300
 
 
301
      luma = (src + stride)[x];
 
302
      if (luma > lumamax)
 
303
        lumamax = luma;
 
304
      if (luma < lumamin)
 
305
        lumamin = luma;
 
306
 
 
307
      luma = (src + stride)[x+1];
 
308
      if (luma > lumamax)
 
309
        lumamax = luma;
 
310
      if (luma < lumamin)
 
311
        lumamin = luma;
 
312
 
 
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. */
 
318
 
 
319
      guint p = 256;
 
320
      if (strength != 0) {
 
321
        mindiff = lumac - lumamin;
 
322
        maxdiff = lumamax - lumac;
 
323
        if (mindiff > maxdiff) {
 
324
          if (maxdiff < threshold)
 
325
            p = lumamax & 0xff;
 
326
        }
 
327
        else {
 
328
          if (mindiff < threshold)
 
329
            p = lumamin & 0xff;
 
330
        }
 
331
      }
 
332
      if (p == 256) {
 
333
        dest[x] = src[x];
 
334
      }
 
335
      else {
 
336
        int t;
 
337
        lumac = src[x] & 0xff;
 
338
        t = ((strength * p + invstrength * lumac) >> 8) & 0xff;
 
339
        if (t > 240)
 
340
          t = 240;
 
341
        if (t < 16)
 
342
          t = 16;
 
343
        dest[x] = t & 0xff;
 
344
      }
 
345
    }
 
346
    src += stride;
 
347
    dest += stride;
 
348
  }
 
349
 
 
350
  return ret;
 
351
}
 
352
 
 
353
 
 
354
static gboolean
 
355
gst_xsharpen_start (GstBaseTransform * btrans)
 
356
{
 
357
  return TRUE;
 
358
}
 
359
 
 
360
static gboolean
 
361
gst_xsharpen_stop (GstBaseTransform * btrans)
 
362
{
 
363
  return TRUE;
 
364
}
 
365
 
 
366
static void
 
367
gst_xsharpen_set_property (GObject * object, guint prop_id,
 
368
    const GValue * value, GParamSpec * pspec)
 
369
{
 
370
  GstXsharpen *src;
 
371
 
 
372
  g_return_if_fail (GST_IS_XSHARPEN (object));
 
373
  src = GST_XSHARPEN (object);
 
374
 
 
375
  switch (prop_id) {
 
376
    case PROP_THRESHOLD:
 
377
      src->threshold = g_value_get_uint (value);
 
378
      break;
 
379
    case PROP_STRENGTH:
 
380
      src->strength = g_value_get_uint (value);
 
381
      break;
 
382
    default:
 
383
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
384
      break;
 
385
  }
 
386
}
 
387
 
 
388
static void
 
389
gst_xsharpen_get_property (GObject * object, guint prop_id, GValue * value,
 
390
    GParamSpec * pspec)
 
391
{
 
392
  GstXsharpen *src;
 
393
 
 
394
  g_return_if_fail (GST_IS_XSHARPEN (object));
 
395
  src = GST_XSHARPEN (object);
 
396
 
 
397
  switch (prop_id) {
 
398
    case PROP_THRESHOLD:
 
399
      g_value_set_uint (value, src->threshold);
 
400
      break;
 
401
    case PROP_STRENGTH:
 
402
      g_value_set_uint (value, src->strength);
 
403
      break;
 
404
    default:
 
405
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
406
      break;
 
407
  }
 
408
}