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

« back to all changes in this revision

Viewing changes to gst/transcode/gstsmooth.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
 * transcode filter:
 
5
 * Copyright (C) Chad Page - October 2002
 
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-smooth
 
24
 *
 
25
 * <refsect2>
 
26
 * <para>
 
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
 
31
 * needs one frame.
 
32
 * </para>
 
33
 * <title>History</title>
 
34
 * <para>
 
35
 * <itemizedlist>
 
36
 * <listitem>
 
37
 * transcode smooth filter [Chad Page]
 
38
 * </listitem>
 
39
 * </itemizedlist>
 
40
 * </para>
 
41
 * </refsect2>
 
42
 */
 
43
 
 
44
 
 
45
#ifdef HAVE_CONFIG_H
 
46
#include "config.h"
 
47
#endif
 
48
 
 
49
#include "plugin-tc.h"
 
50
 
 
51
#include <stdlib.h>
 
52
 
 
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))
 
63
 
 
64
typedef struct _GstSmooth GstSmooth;
 
65
typedef struct _GstSmoothClass GstSmoothClass;
 
66
 
 
67
 
 
68
struct _GstSmooth
 
69
{
 
70
  GstVideoFilter videofilter;
 
71
 
 
72
  gint width, height;
 
73
 
 
74
  /* denoise parameters */
 
75
  gfloat blend_factor;
 
76
  guint chroma_diff, luma_diff, search_range;
 
77
};
 
78
 
 
79
struct _GstSmoothClass
 
80
{
 
81
  GstVideoFilterClass parent_class;
 
82
};
 
83
 
 
84
GST_DEBUG_CATEGORY_STATIC (smooth_debug);
 
85
#define GST_CAT_DEFAULT smooth_debug
 
86
 
 
87
/* signals and args */
 
88
enum
 
89
{
 
90
  /* FILL ME */
 
91
  LAST_SIGNAL
 
92
};
 
93
 
 
94
enum
 
95
{
 
96
  PROP_0,
 
97
  PROP_BLEND_FACTOR,
 
98
  PROP_CHROMA_DIFF,
 
99
  PROP_LUMA_DIFF,
 
100
  PROP_SEARCH_RANGE
 
101
      /* FILL ME */
 
102
};
 
103
 
 
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
 
112
 
 
113
 
 
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"
 
119
    "Chad Page");
 
120
 
 
121
static GstStaticPadTemplate gst_smooth_src_template =
 
122
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
 
123
    GST_PAD_SRC,
 
124
    GST_PAD_ALWAYS,
 
125
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
126
    );
 
127
 
 
128
static GstStaticPadTemplate gst_smooth_sink_template =
 
129
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
 
130
    GST_PAD_SINK,
 
131
    GST_PAD_ALWAYS,
 
132
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
133
    );
 
134
 
 
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);
 
139
 
 
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);
 
144
 
 
145
GST_BOILERPLATE (GstSmooth, gst_smooth, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
 
146
 
 
147
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE (GstSmooth, gst_smooth);
 
148
 
 
149
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_smooth);
 
150
 
 
151
static void
 
152
gst_smooth_base_init (gpointer g_class)
 
153
{
 
154
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
155
 
 
156
  gst_element_class_set_details (element_class, &smooth_details);
 
157
 
 
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));
 
162
}
 
163
 
 
164
static void
 
165
gst_smooth_class_init (GstSmoothClass * g_class)
 
166
{
 
167
  GObjectClass *gobject_class;
 
168
  GstBaseTransformClass *trans_class;
 
169
 
 
170
  gobject_class = G_OBJECT_CLASS (g_class);
 
171
  trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
 
172
 
 
173
  GST_DEBUG_CATEGORY_INIT (smooth_debug, "smooth", 0, "smooth");
 
174
 
 
175
  gobject_class->set_property = gst_smooth_set_property;
 
176
  gobject_class->get_property = gst_smooth_get_property;
 
177
 
 
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));
 
182
 
 
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));
 
187
 
 
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));
 
192
 
 
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));
 
197
 
 
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);
 
203
}
 
204
 
 
205
static void
 
206
gst_smooth_init (GstSmooth * filter, GstSmoothClass * g_class)
 
207
{
 
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;
 
212
}
 
213
 
 
214
static void
 
215
gst_smooth (guint8 * src, guint8 * buf, gint width, gint height, gint maxdiff,
 
216
                gint maxldiff, gint maxdist, gfloat level)
 
217
{
 
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;
 
223
 
 
224
  ltbuf = src;
 
225
  tbufcr = ltbuf + GST_VIDEO_I420_U_OFFSET (width, height);
 
226
  tbufcb = ltbuf + GST_VIDEO_I420_V_OFFSET (width, height);
 
227
 
 
228
  bufcr = buf + GST_VIDEO_I420_U_OFFSET (width, height);
 
229
  bufcb = buf + GST_VIDEO_I420_V_OFFSET (width, height);
 
230
 
 
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++) {
 
238
        if (xa < 0)
 
239
          xa = 0;
 
240
        if ((xa == x) && (xa < width - 1))
 
241
          xa++;
 
242
        cpu = ((y >> 1) * (width >> 1)) + (xa >> 1);
 
243
        cdiff = abs (tbufcr[pu] - tbufcr[cpu]);
 
244
        cdiff += abs (tbufcb[pu] - tbufcb[cpu]);
 
245
 
 
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)) {
 
250
          dist = abs (xa - x);
 
251
          ratio = level / dist;
 
252
          nval = nval * (1 - ratio);
 
253
          nval += ((gfloat) ltbuf[xa + (y * width)]) * ratio;
 
254
        }
 
255
      }
 
256
      buf[x + (y * width)] = (guint8) (nval + 0.5);
 
257
    }
 
258
  }
 
259
 
 
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++) {
 
267
        if (ya < 0)
 
268
          ya = 0;
 
269
        if ((ya == y) && (ya < height - 1))
 
270
          ya++;
 
271
        cpu = ((ya >> 1) * (width >> 1)) + (x >> 1);
 
272
        cdiff = abs (tbufcr[pu] - tbufcr[cpu]);
 
273
        cdiff += abs (tbufcb[pu] - tbufcb[cpu]);
 
274
 
 
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)) {
 
279
          dist = abs (ya - y);
 
280
          ratio = level / dist;
 
281
          nval = nval * (1 - ratio);
 
282
          nval += ((gfloat) ltbuf[x + (ya * width)]) * ratio;
 
283
        }
 
284
      }
 
285
      buf[x + (y * width)] = (guint8) (nval + 0.5);
 
286
    }
 
287
  }
 
288
}
 
289
 
 
290
static GstFlowReturn
 
291
gst_smooth_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
 
292
{
 
293
  GstSmooth *filter;
 
294
  guint8 *src, *dest;
 
295
 
 
296
  gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
 
297
 
 
298
  filter = GST_SMOOTH (btrans);
 
299
 
 
300
  src = (guint8 *) GST_BUFFER_DATA (in);
 
301
  dest = (guint8 *) GST_BUFFER_DATA (out);
 
302
 
 
303
  oil_memcpy (dest, src, GST_VIDEO_I420_SIZE (filter->width, filter->height));
 
304
 
 
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);
 
308
 
 
309
  return GST_FLOW_OK;
 
310
}
 
311
 
 
312
static gboolean
 
313
gst_smooth_start (GstBaseTransform * btrans)
 
314
{
 
315
 
 
316
  return TRUE;
 
317
}
 
318
 
 
319
static gboolean
 
320
gst_smooth_stop (GstBaseTransform * btrans)
 
321
{
 
322
 
 
323
  return TRUE;
 
324
}
 
325
 
 
326
static void
 
327
gst_smooth_set_property (GObject * object, guint prop_id,
 
328
    const GValue * value, GParamSpec * pspec)
 
329
{
 
330
  GstSmooth *src;
 
331
 
 
332
  g_return_if_fail (GST_IS_SMOOTH (object));
 
333
  src = GST_SMOOTH (object);
 
334
 
 
335
  switch (prop_id) {
 
336
    case PROP_BLEND_FACTOR:
 
337
      src->blend_factor = g_value_get_float (value);
 
338
      break;
 
339
    case PROP_CHROMA_DIFF:
 
340
      src->chroma_diff = g_value_get_uint (value);
 
341
      break;
 
342
    case PROP_LUMA_DIFF:
 
343
      src->luma_diff = g_value_get_uint (value);
 
344
      break;
 
345
    case PROP_SEARCH_RANGE:
 
346
      src->search_range = g_value_get_uint (value);
 
347
      break;
 
348
    default:
 
349
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
350
      break;
 
351
  }
 
352
}
 
353
 
 
354
static void
 
355
gst_smooth_get_property (GObject * object, guint prop_id, GValue * value,
 
356
    GParamSpec * pspec)
 
357
{
 
358
  GstSmooth *src;
 
359
 
 
360
  g_return_if_fail (GST_IS_SMOOTH (object));
 
361
  src = GST_SMOOTH (object);
 
362
 
 
363
  switch (prop_id) {
 
364
    case PROP_BLEND_FACTOR:
 
365
      g_value_set_float (value, src->blend_factor);
 
366
      break;
 
367
    case PROP_CHROMA_DIFF:
 
368
      g_value_set_uint (value, src->chroma_diff);
 
369
      break;
 
370
    case PROP_LUMA_DIFF:
 
371
      g_value_set_uint (value, src->luma_diff);
 
372
      break;
 
373
    case PROP_SEARCH_RANGE:
 
374
      g_value_set_uint (value, src->search_range);
 
375
      break;
 
376
    default:
 
377
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
378
      break;
 
379
  }
 
380
}