Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / smooth / gstsmooth.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *               <2001> Wim Taymans <wim.taymans@chello.be>
4  *               <2011> Stefan Sauer <ensonic@user.sf.net>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <string.h>
26 #include "gstsmooth.h"
27 #include <gst/video/video.h>
28
29 /* Smooth args */
30
31 enum
32 {
33   PROP_0,
34   PROP_ACTIVE,
35   PROP_TOLERANCE,
36   PROP_FILTER_SIZE,
37   PROP_LUMA_ONLY
38 };
39
40 static GstStaticPadTemplate gst_smooth_src_template =
41 GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")
45     )
46     );
47
48 static GstStaticPadTemplate gst_smooth_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50     GST_PAD_SINK,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")
53     )
54     );
55
56
57 static gboolean gst_smooth_set_caps (GstBaseTransform * btrans,
58     GstCaps * incaps, GstCaps * outcaps);
59
60 static GstFlowReturn gst_smooth_transform (GstBaseTransform * btrans,
61     GstBuffer * inbuf, GstBuffer * outbuf);
62 static void smooth_filter (unsigned char *dest, unsigned char *src,
63     int width, int height, int tolerance, int filtersize);
64
65 static void gst_smooth_set_property (GObject * object, guint prop_id,
66     const GValue * value, GParamSpec * pspec);
67 static void gst_smooth_get_property (GObject * object, guint prop_id,
68     GValue * value, GParamSpec * pspec);
69
70 GST_BOILERPLATE (GstSmooth, gst_smooth, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
71
72 static void
73 gst_smooth_base_init (gpointer g_class)
74 {
75   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
76
77   gst_element_class_add_static_pad_template (element_class,
78       &gst_smooth_sink_template);
79   gst_element_class_add_static_pad_template (element_class,
80       &gst_smooth_src_template);
81   gst_element_class_set_details_simple (element_class, "Smooth effect",
82       "Filter/Effect/Video",
83       "Apply a smooth filter to an image",
84       "Wim Taymans <wim.taymans@chello.be>");
85 }
86
87 static void
88 gst_smooth_class_init (GstSmoothClass * klass)
89 {
90   GObjectClass *gobject_class = (GObjectClass *) klass;
91   GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
92
93   gobject_class->set_property = gst_smooth_set_property;
94   gobject_class->get_property = gst_smooth_get_property;
95
96   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ACTIVE,
97       g_param_spec_boolean ("active", "active", "process video", TRUE,
98           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
99   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOLERANCE,
100       g_param_spec_int ("tolerance",
101           "tolerance", "contrast tolerance for smoothing", G_MININT,
102           G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
103   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTER_SIZE,
104       g_param_spec_int ("filter-size", "filter-size", "size of media filter",
105           G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
106   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LUMA_ONLY,
107       g_param_spec_boolean ("luma-only", "luma-only", "only filter luma part",
108           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109
110   btrans_class->transform = GST_DEBUG_FUNCPTR (gst_smooth_transform);
111   btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_smooth_set_caps);
112 }
113
114 static gboolean
115 gst_smooth_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
116     GstCaps * outcaps)
117 {
118   GstSmooth *filter;
119   GstStructure *structure;
120   gboolean ret;
121
122   filter = GST_SMOOTH (btrans);
123
124   structure = gst_caps_get_structure (incaps, 0);
125   ret = gst_structure_get_int (structure, "width", &filter->width);
126   ret &= gst_structure_get_int (structure, "height", &filter->height);
127
128   return ret;
129 }
130
131 static void
132 gst_smooth_init (GstSmooth * smooth, GstSmoothClass * klass)
133 {
134   smooth->active = TRUE;
135   smooth->tolerance = 8;
136   smooth->filtersize = 3;
137   smooth->luma_only = TRUE;
138 }
139
140 static void
141 smooth_filter (guchar * dest, guchar * src, gint width, gint height,
142     gint tolerance, gint filtersize)
143 {
144   gint refval, aktval, upperval, lowerval, numvalues, sum;
145   gint x, y, fx, fy, fy1, fy2, fx1, fx2;
146   guchar *srcp = src;
147
148   fy1 = 0;
149   fy2 = MIN (filtersize + 1, height) * width;
150
151   for (y = 0; y < height; y++) {
152     if (y > (filtersize + 1))
153       fy1 += width;
154     if (y < height - (filtersize + 1))
155       fy2 += width;
156
157     for (x = 0; x < width; x++) {
158       refval = *src;
159       upperval = refval + tolerance;
160       lowerval = refval - tolerance;
161
162       numvalues = 1;
163       sum = refval;
164
165       fx1 = MAX (x - filtersize, 0) + fy1;
166       fx2 = MIN (x + filtersize + 1, width) + fy1;
167
168       for (fy = fy1; fy < fy2; fy += width) {
169         for (fx = fx1; fx < fx2; fx++) {
170           aktval = srcp[fx];
171           if ((lowerval - aktval) * (upperval - aktval) < 0) {
172             numvalues++;
173             sum += aktval;
174           }
175         }                       /*for fx */
176         fx1 += width;
177         fx2 += width;
178       }                         /*for fy */
179
180       src++;
181       *dest++ = sum / numvalues;
182     }
183   }
184 }
185
186 static GstFlowReturn
187 gst_smooth_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
188     GstBuffer * outbuf)
189 {
190   GstSmooth *smooth;
191   guint8 *idata, *odata;
192   guint size, lumsize, chromsize;
193
194   smooth = GST_SMOOTH (btrans);
195   idata = GST_BUFFER_DATA (inbuf);
196   odata = GST_BUFFER_DATA (outbuf);
197   size = GST_BUFFER_SIZE (inbuf);
198
199   if (!smooth->active) {
200     memcpy (odata, idata, size);
201     return GST_FLOW_OK;
202   }
203
204   GST_DEBUG_OBJECT (smooth, "smooth: have buffer of %d", size);
205
206   lumsize = smooth->width * smooth->height;
207   chromsize = lumsize / 4;
208
209   smooth_filter (odata, idata, smooth->width, smooth->height,
210       smooth->tolerance, smooth->filtersize);
211   if (!smooth->luma_only) {
212     smooth_filter (odata + lumsize, idata + lumsize,
213         smooth->width / 2, smooth->height / 2, smooth->tolerance,
214         smooth->filtersize / 2);
215     smooth_filter (odata + lumsize + chromsize,
216         idata + lumsize + chromsize, smooth->width / 2, smooth->height / 2,
217         smooth->tolerance, smooth->filtersize / 2);
218   } else {
219     memcpy (odata + lumsize, idata + lumsize, chromsize * 2);
220   }
221
222   return GST_FLOW_OK;
223 }
224
225 static void
226 gst_smooth_set_property (GObject * object, guint prop_id, const GValue * value,
227     GParamSpec * pspec)
228 {
229   GstSmooth *smooth;
230
231   g_return_if_fail (GST_IS_SMOOTH (object));
232   smooth = GST_SMOOTH (object);
233
234   switch (prop_id) {
235     case PROP_ACTIVE:
236       smooth->active = g_value_get_boolean (value);
237       break;
238     case PROP_TOLERANCE:
239       smooth->tolerance = g_value_get_int (value);
240       break;
241     case PROP_FILTER_SIZE:
242       smooth->filtersize = g_value_get_int (value);
243       break;
244     case PROP_LUMA_ONLY:
245       smooth->luma_only = g_value_get_boolean (value);
246       break;
247     default:
248       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249       break;
250   }
251 }
252
253 static void
254 gst_smooth_get_property (GObject * object, guint prop_id, GValue * value,
255     GParamSpec * pspec)
256 {
257   GstSmooth *smooth;
258
259   g_return_if_fail (GST_IS_SMOOTH (object));
260   smooth = GST_SMOOTH (object);
261
262   switch (prop_id) {
263     case PROP_ACTIVE:
264       g_value_set_boolean (value, smooth->active);
265       break;
266     case PROP_TOLERANCE:
267       g_value_set_int (value, smooth->tolerance);
268       break;
269     case PROP_FILTER_SIZE:
270       g_value_set_int (value, smooth->filtersize);
271       break;
272     case PROP_LUMA_ONLY:
273       g_value_set_boolean (value, smooth->luma_only);
274       break;
275     default:
276       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277       break;
278   }
279 }
280
281
282 static gboolean
283 plugin_init (GstPlugin * plugin)
284 {
285   return gst_element_register (plugin, "smooth",
286       GST_RANK_NONE, GST_TYPE_SMOOTH);
287 }
288
289 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
290     GST_VERSION_MINOR,
291     "smooth",
292     "Apply a smooth filter to an image",
293     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)