compatibility fix for new GST_DEBUG stuff.
[platform/upstream/gstreamer.git] / gst / smooth / gstsmooth.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24 #include <gstsmooth.h>
25
26 /* elementfactory information */
27 static GstElementDetails smooth_details = {
28   "Smooth effect",
29   "Filter/Video",
30   "LGPL",
31   "Apply a smooth filter to an image",
32   VERSION,
33   "Wim Taymans <wim.taymans@chello.be>",
34   "(C) 2000",
35 };
36
37
38 /* Smooth signals and args */
39 enum {
40   /* FILL ME */
41   LAST_SIGNAL
42 };
43
44 enum {
45   ARG_0,
46   ARG_ACTIVE,
47   ARG_TOLERANCE,
48   ARG_FILTERSIZE,
49   ARG_LUM_ONLY
50 };
51
52 GST_PAD_TEMPLATE_FACTORY (smooth_src_factory,
53   "src",
54   GST_PAD_SRC,
55   GST_PAD_ALWAYS,
56   GST_CAPS_NEW (
57    "smooth_src",
58    "video/raw",
59      "format",   GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
60   )
61 )
62
63 GST_PAD_TEMPLATE_FACTORY (smooth_sink_factory,
64   "sink",
65   GST_PAD_SINK,
66   GST_PAD_ALWAYS,
67   GST_CAPS_NEW (
68    "smooth_src",
69    "video/raw",
70      "format",   GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
71   )
72 )
73
74 static void     gst_smooth_class_init   (GstSmoothClass *klass);
75 static void     gst_smooth_init         (GstSmooth *smooth);
76
77 static void     gst_smooth_chain        (GstPad *pad, GstBuffer *buf);
78 static void     smooth_filter           (unsigned char* dest, unsigned char* src,
79                                          int width, int height, int tolerance, int filtersize);
80
81 static void     gst_smooth_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
82 static void     gst_smooth_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
83
84 static GstElementClass *parent_class = NULL;
85 /*static guint gst_smooth_signals[LAST_SIGNAL] = { 0 }; */
86
87 GType
88 gst_smooth_get_type (void)
89 {
90   static GType smooth_type = 0;
91
92   if (!smooth_type) {
93     static const GTypeInfo smooth_info = {
94       sizeof(GstSmoothClass),      NULL,
95       NULL,
96       (GClassInitFunc)gst_smooth_class_init,
97       NULL,
98       NULL,
99       sizeof(GstSmooth),
100       0,
101       (GInstanceInitFunc)gst_smooth_init,
102     };
103     smooth_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSmooth", &smooth_info, 0);
104   }
105   return smooth_type;
106 }
107
108 static void
109 gst_smooth_class_init (GstSmoothClass *klass)
110 {
111   GObjectClass *gobject_class;
112   GstElementClass *gstelement_class;
113
114   gobject_class = (GObjectClass*)klass;
115   gstelement_class = (GstElementClass*)klass;
116
117   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
118
119   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ACTIVE,
120     g_param_spec_boolean("active","active","active",
121                          TRUE,G_PARAM_READWRITE)); /* CHECKME */
122   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOLERANCE,
123     g_param_spec_int("tolerance","tolerance","tolerance",
124                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
125   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FILTERSIZE,
126     g_param_spec_int("filtersize","filtersize","filtersize",
127                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
128
129   gobject_class->set_property = gst_smooth_set_property;
130   gobject_class->get_property = gst_smooth_get_property;
131
132 }
133
134 static GstPadLinkReturn
135 gst_smooth_sinkconnect (GstPad *pad, GstCaps *caps)
136 {
137   GstSmooth *filter;
138
139   filter = GST_SMOOTH (gst_pad_get_parent (pad));
140
141   if (!GST_CAPS_IS_FIXED (caps))
142     return GST_PAD_LINK_DELAYED;
143
144   gst_caps_get_int (caps, "width", &filter->width);
145   gst_caps_get_int (caps, "height", &filter->height);
146
147   return GST_PAD_LINK_OK;
148 }
149
150 static void
151 gst_smooth_init (GstSmooth *smooth)
152 {
153   smooth->sinkpad = gst_pad_new_from_template (
154                   GST_PAD_TEMPLATE_GET (smooth_sink_factory), "sink");
155   gst_pad_set_link_function (smooth->sinkpad, gst_smooth_sinkconnect);
156   gst_pad_set_chain_function (smooth->sinkpad, gst_smooth_chain);
157   gst_element_add_pad (GST_ELEMENT (smooth), smooth->sinkpad);
158
159   smooth->srcpad = gst_pad_new_from_template (
160                   GST_PAD_TEMPLATE_GET (smooth_src_factory), "src");
161   gst_element_add_pad (GST_ELEMENT (smooth), smooth->srcpad);
162
163   smooth->active = TRUE;
164   smooth->tolerance = 8;
165   smooth->filtersize = 3;
166   smooth->lum_only = TRUE;
167 }
168
169 static void
170 smooth_filter (unsigned char* dest, unsigned char* src, int width, int height, int tolerance, int filtersize)
171 {
172   int refval, aktval, upperval, lowerval, numvalues, sum;
173   int x, y, fx, fy, fy1, fy2, fx1, fx2;
174   unsigned char *srcp = src;
175
176   fy1 = 0;
177   fy2 = MIN(filtersize+1, height) * width;
178
179   for(y = 0; y < height; y++)
180   {
181     if (y>(filtersize+1)) fy1 += width;
182     if (y<height-(filtersize+1)) fy2 += width;
183
184     for(x = 0; x < width; x++)
185     {
186       refval    = *src;
187       upperval  = refval + tolerance;
188       lowerval  = refval - tolerance;
189
190       numvalues = 1;
191       sum       = refval;
192
193       fx1      = MAX(x-filtersize,   0)     + fy1;
194       fx2      = MIN(x+filtersize+1, width) + fy1;
195
196       for (fy = fy1; fy<fy2; fy+=width)
197       {
198         for (fx = fx1; fx<fx2; fx++)
199         {
200           aktval = srcp[fx];
201           if ((lowerval-aktval)*(upperval-aktval)<0)
202           {
203             numvalues ++;
204             sum += aktval;
205           }
206         } /*for fx */
207         fx1 += width;
208         fx2 += width;
209       } /*for fy */
210
211       src++;
212       *dest++ = sum/numvalues;
213     }
214   }
215 }
216
217 static void
218 gst_smooth_chain (GstPad *pad, GstBuffer *buf)
219 {
220   GstSmooth *smooth;
221   guchar *data;
222   gulong size;
223   GstBuffer *outbuf;
224   gint lumsize, chromsize;
225
226   g_return_if_fail (pad != NULL);
227   g_return_if_fail (GST_IS_PAD (pad));
228   g_return_if_fail (buf != NULL);
229
230   smooth = GST_SMOOTH (GST_OBJECT_PARENT (pad));
231
232   if (!smooth->active) {
233     gst_pad_push(smooth->srcpad,buf);
234     return;
235   }
236
237   data = GST_BUFFER_DATA (buf);
238   size = GST_BUFFER_SIZE (buf);
239
240   GST_DEBUG ("smooth: have buffer of %d", GST_BUFFER_SIZE (buf));
241
242   outbuf = gst_buffer_new();
243   GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (buf));
244   GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf);
245
246   lumsize = smooth->width*smooth->height;
247   chromsize = lumsize/4;
248
249   smooth_filter (GST_BUFFER_DATA (outbuf), data, smooth->width, smooth->height, 
250                   smooth->tolerance, smooth->filtersize);
251   if (!smooth->lum_only) {
252     smooth_filter (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, smooth->width/2, smooth->height/2, 
253                   smooth->tolerance, smooth->filtersize/2);
254     smooth_filter (GST_BUFFER_DATA (outbuf)+lumsize+chromsize, data+lumsize+chromsize, smooth->width/2, 
255                   smooth->height/2, smooth->tolerance, smooth->filtersize/2);
256   }
257   else {
258     memcpy (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, chromsize*2);
259   }
260
261   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
262
263   gst_buffer_unref (buf);
264
265   gst_pad_push (smooth->srcpad, outbuf);
266 }
267
268 static void
269 gst_smooth_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
270 {
271   GstSmooth *smooth;
272
273   /* it's not null if we got it, but it might not be ours */
274   g_return_if_fail(GST_IS_SMOOTH(object));
275   smooth = GST_SMOOTH(object);
276
277   switch (prop_id) {
278     case ARG_ACTIVE:
279       smooth->active = g_value_get_boolean (value);
280       break;
281     case ARG_TOLERANCE:
282       smooth->tolerance = g_value_get_int (value);
283       break;
284     case ARG_FILTERSIZE:
285       smooth->filtersize = g_value_get_int (value);
286       break;
287     case ARG_LUM_ONLY:
288       smooth->lum_only = g_value_get_boolean (value);
289       break;
290     default:
291       break;
292   }
293 }
294
295 static void
296 gst_smooth_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
297 {
298   GstSmooth *smooth;
299
300   /* it's not null if we got it, but it might not be ours */
301   g_return_if_fail(GST_IS_SMOOTH(object));
302   smooth = GST_SMOOTH(object);
303
304   switch (prop_id) {
305     case ARG_ACTIVE:
306       g_value_set_boolean (value, smooth->active);
307       break;
308     case ARG_TOLERANCE:
309       g_value_set_int (value, smooth->tolerance);
310       break;
311     case ARG_FILTERSIZE:
312       g_value_set_int (value, smooth->filtersize);
313       break;
314     case ARG_LUM_ONLY:
315       g_value_set_boolean (value, smooth->lum_only);
316       break;
317     default:
318       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
319       break;
320   }
321 }
322
323
324 static gboolean
325 plugin_init (GModule *module, GstPlugin *plugin)
326 {
327   GstElementFactory *factory;
328
329   factory = gst_element_factory_new("smooth",GST_TYPE_SMOOTH,
330                                    &smooth_details);
331   g_return_val_if_fail(factory != NULL, FALSE);
332
333   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (smooth_sink_factory));
334   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (smooth_src_factory));
335
336   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
337
338   return TRUE;
339 }
340
341 GstPluginDesc plugin_desc = {
342   GST_VERSION_MAJOR,
343   GST_VERSION_MINOR,
344   "smooth",
345   plugin_init
346 };
347