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

« back to all changes in this revision

Viewing changes to gst/avidemux/gststabilize.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) 2008 Mark Nauwelaerts <mnauw@users.sourceforge.net>
 
3
 *
 
4
 * avidemux filter:
 
5
 * Copyright (C) Mean - 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-stabilize
 
24
 *
 
25
 * <refsect2>
 
26
 * <para>
 
27
 * Light-weight denoising/smoothing using previous and next frames.
 
28
 * </para>
 
29
 * <title>History</title>
 
30
 * <para>
 
31
 * <itemizedlist>
 
32
 * <listitem>
 
33
 * avidemux stabilize filter [Mean]
 
34
 * </listitem>
 
35
 * </itemizedlist>
 
36
 * </para>
 
37
 * </refsect2>
 
38
 */
 
39
 
 
40
 
 
41
#ifdef HAVE_CONFIG_H
 
42
#include "config.h"
 
43
#endif
 
44
 
 
45
#include "plugin-ad.h"
 
46
 
 
47
 
 
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))
 
58
 
 
59
typedef struct _GstStabilize GstStabilize;
 
60
typedef struct _GstStabilizeClass GstStabilizeClass;
 
61
 
 
62
 
 
63
struct _GstStabilize
 
64
{
 
65
  GstVideoFilter videofilter;
 
66
 
 
67
  gint width, height;
 
68
 
 
69
  /* past/future buffers */
 
70
  GstBuffer *queue[3];
 
71
  guint count;
 
72
 
 
73
  /* stabilize parameters */
 
74
  guint luma_threshold;
 
75
};
 
76
 
 
77
struct _GstStabilizeClass
 
78
{
 
79
  GstVideoFilterClass parent_class;
 
80
};
 
81
 
 
82
GST_DEBUG_CATEGORY_STATIC (smooth_debug);
 
83
#define GST_CAT_DEFAULT smooth_debug
 
84
 
 
85
/* signals and args */
 
86
enum
 
87
{
 
88
  /* FILL ME */
 
89
  LAST_SIGNAL
 
90
};
 
91
 
 
92
enum
 
93
{
 
94
  PROP_0,
 
95
  PROP_LUMA_THRESHOLD
 
96
      /* FILL ME */
 
97
};
 
98
 
 
99
#define DEFAULT_LUMA_THRESHOLD     30
 
100
 
 
101
 
 
102
static GstElementDetails smooth_details =
 
103
GST_ELEMENT_DETAILS ("Soften",
 
104
    "Filter/Effect/Video",
 
105
    "Softening",
 
106
    "Mark Nauwelaerts <mnauw@users.sourceforge.net>,\n"
 
107
    "Mean");
 
108
 
 
109
static GstStaticPadTemplate gst_stabilize_src_template =
 
110
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
 
111
    GST_PAD_SRC,
 
112
    GST_PAD_ALWAYS,
 
113
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
114
    );
 
115
 
 
116
static GstStaticPadTemplate gst_stabilize_sink_template =
 
117
GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
 
118
    GST_PAD_SINK,
 
119
    GST_PAD_ALWAYS,
 
120
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
 
121
    );
 
122
 
 
123
static gboolean gst_stabilize_hook_caps (GstStabilize * filter,
 
124
    GstCaps * incaps, GstCaps * outcaps);
 
125
static gboolean gst_stabilize_sink_event (GstBaseTransform * btrans,
 
126
    GstEvent * event);
 
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);
 
131
 
 
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);
 
136
 
 
137
GST_BOILERPLATE (GstStabilize, gst_stabilize, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
 
138
 
 
139
GST_VIDEO_FILTER_SET_CAPS_BOILERPLATE_FULL (GstStabilize, gst_stabilize,
 
140
    gst_stabilize_hook_caps);
 
141
 
 
142
GST_VIDEO_FILTER_GET_UNIT_SIZE_BOILERPLATE (gst_stabilize);
 
143
 
 
144
static void
 
145
gst_stabilize_base_init (gpointer g_class)
 
146
{
 
147
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
148
 
 
149
  gst_element_class_set_details (element_class, &smooth_details);
 
150
 
 
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));
 
155
}
 
156
 
 
157
static void
 
158
gst_stabilize_class_init (GstStabilizeClass * g_class)
 
159
{
 
160
  GObjectClass *gobject_class;
 
161
  GstBaseTransformClass *trans_class;
 
162
 
 
163
  gobject_class = G_OBJECT_CLASS (g_class);
 
164
  trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
 
165
 
 
166
  GST_DEBUG_CATEGORY_INIT (smooth_debug, "smooth", 0, "smooth");
 
167
 
 
168
  gobject_class->set_property = gst_stabilize_set_property;
 
169
  gobject_class->get_property = gst_stabilize_get_property;
 
170
 
 
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));
 
175
 
 
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);
 
182
}
 
183
 
 
184
static void
 
185
gst_stabilize_init (GstStabilize * filter, GstStabilizeClass * g_class)
 
186
{
 
187
  filter->luma_threshold = DEFAULT_LUMA_THRESHOLD;
 
188
}
 
189
 
 
190
// TODO consider this as a library function
 
191
/* empties queue and resets frame count */
 
192
static void
 
193
gst_stabilize_flush (GstStabilize * filter, gboolean send)
 
194
{
 
195
  GstBuffer *buf;
 
196
  GstBaseTransform *btrans;
 
197
  gint i;
 
198
 
 
199
  btrans = GST_BASE_TRANSFORM (filter);
 
200
 
 
201
  filter->count = 0;
 
202
  for (i = 2; i >= 0; i--) {
 
203
    buf = filter->queue[i];
 
204
    if (buf) {
 
205
      filter->queue[i] = NULL;
 
206
      if (send) {
 
207
        gst_buffer_set_caps (buf, GST_PAD_CAPS (btrans->srcpad));
 
208
        gst_pad_push (btrans->srcpad, buf);
 
209
      }
 
210
      else
 
211
        gst_buffer_unref (buf);
 
212
    }
 
213
  }
 
214
}
 
215
 
 
216
static gboolean
 
217
gst_stabilize_hook_caps (GstStabilize * filter, GstCaps * incaps,
 
218
    GstCaps * outcaps)
 
219
{
 
220
  gst_stabilize_flush (filter, TRUE);
 
221
 
 
222
  return TRUE;
 
223
}
 
224
 
 
225
static gboolean
 
226
gst_stabilize_sink_event (GstBaseTransform * btrans, GstEvent * event)
 
227
{
 
228
  GstStabilize *filter;
 
229
 
 
230
  filter = GST_STABILIZE (btrans);
 
231
 
 
232
  switch (GST_EVENT_TYPE (event)) {
 
233
    case GST_EVENT_EOS:
 
234
      gst_stabilize_flush (filter, TRUE);
 
235
      break;
 
236
    default:
 
237
      break;
 
238
  }
 
239
 
 
240
  return GST_BASE_TRANSFORM_CLASS (parent_class)->event (btrans, event);
 
241
}
 
242
 
 
243
 
 
244
/* see below for specific (loop) context */
 
245
#define PONDERATE(x) G_STMT_START { \
 
246
      if (distMatrix[*incur][x] < threshold) { \
 
247
        c += x; \
 
248
        coeff++; \
 
249
      } \
 
250
    } G_STMT_END
 
251
 
 
252
static void
 
253
gst_stabilize (guint8 * src, guint8 * dst, guint8 * src_prev, guint8 * src_next,
 
254
    gint width, gint height, gint threshold)
 
255
{
 
256
  guint8 *inprev, *innext, *incur, *nl, *pl, *nc, *pc, *zout;
 
257
  guint x, y;
 
258
 
 
259
  inprev = src_prev + width + 1;
 
260
  innext = src_next + width + 1;
 
261
  incur = src + width + 1;
 
262
  zout = dst + width + 1;
 
263
 
 
264
  for (y = height - 1; y > 1; y--) {
 
265
    nl = incur + width;
 
266
    pl = incur - width;
 
267
    nc = incur + 1;
 
268
    pc = incur - 1;
 
269
 
 
270
    for (x = width - 1; x > 1; x--) {
 
271
      guint16 c, coeff;
 
272
 
 
273
      c = *incur * 4;
 
274
      coeff = 4;
 
275
      PONDERATE (*innext);
 
276
      PONDERATE (*inprev);
 
277
      PONDERATE (*pc);
 
278
      PONDERATE (*nc);
 
279
      PONDERATE (*nl);
 
280
      PONDERATE (*pl);
 
281
 
 
282
      *zout = (c * fixMul[coeff]) >> 16;
 
283
      zout++;
 
284
      incur++;
 
285
      innext++;
 
286
      inprev++;
 
287
      nl++;
 
288
      pl++;
 
289
      nc++;
 
290
      pc++;
 
291
    }
 
292
 
 
293
    /* proceed to next line */
 
294
    zout += 2;
 
295
    incur += 2;
 
296
    innext += 2;
 
297
    inprev += 2;
 
298
  }
 
299
}
 
300
 
 
301
static GstFlowReturn
 
302
gst_stabilize_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
 
303
{
 
304
  GstStabilize *filter;
 
305
  guint8 *src, *dest;
 
306
 
 
307
  gst_object_sync_values (G_OBJECT (btrans), GST_BUFFER_TIMESTAMP (in));
 
308
 
 
309
  filter = GST_STABILIZE (btrans);
 
310
 
 
311
  filter->queue[filter->count] = gst_buffer_ref (in);
 
312
  filter->count++;
 
313
 
 
314
  if (filter->count < 3)
 
315
    return GST_BASE_TRANSFORM_FLOW_DROPPED;
 
316
 
 
317
  src = (guint8 *) GST_BUFFER_DATA (filter->queue[1]);
 
318
  dest = (guint8 *) GST_BUFFER_DATA (out);
 
319
 
 
320
  oil_memcpy (dest, src, GST_VIDEO_I420_SIZE (filter->width, filter->height));
 
321
 
 
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);
 
327
 
 
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;
 
332
  filter->count--;
 
333
 
 
334
  return GST_FLOW_OK;
 
335
}
 
336
 
 
337
static gboolean
 
338
gst_stabilize_start (GstBaseTransform * btrans)
 
339
{
 
340
 
 
341
  return TRUE;
 
342
}
 
343
 
 
344
static gboolean
 
345
gst_stabilize_stop (GstBaseTransform * btrans)
 
346
{
 
347
  GstStabilize *filter = GST_STABILIZE (btrans);
 
348
 
 
349
  gst_stabilize_flush (filter, FALSE);
 
350
 
 
351
  return TRUE;
 
352
}
 
353
 
 
354
static void
 
355
gst_stabilize_set_property (GObject * object, guint prop_id,
 
356
    const GValue * value, GParamSpec * pspec)
 
357
{
 
358
  GstStabilize *src;
 
359
 
 
360
  g_return_if_fail (GST_IS_SOFTEN (object));
 
361
  src = GST_STABILIZE (object);
 
362
 
 
363
  switch (prop_id) {
 
364
    case PROP_LUMA_THRESHOLD:
 
365
      src->luma_threshold = g_value_get_uint (value);
 
366
      break;
 
367
    default:
 
368
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
369
      break;
 
370
  }
 
371
}
 
372
 
 
373
static void
 
374
gst_stabilize_get_property (GObject * object, guint prop_id, GValue * value,
 
375
    GParamSpec * pspec)
 
376
{
 
377
  GstStabilize *src;
 
378
 
 
379
  g_return_if_fail (GST_IS_SOFTEN (object));
 
380
  src = GST_STABILIZE (object);
 
381
 
 
382
  switch (prop_id) {
 
383
    case PROP_LUMA_THRESHOLD:
 
384
      g_value_set_uint (value, src->luma_threshold);
 
385
      break;
 
386
    default:
 
387
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
388
      break;
 
389
  }
 
390
}