VideoFilter inherits from
[platform/upstream/gstreamer.git] / gst / videofilter / gstvideobalance.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * This file was (probably) generated from gstvideobalance.c,
23  * gstvideobalance.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "gstvideobalance.h"
31 #ifdef HAVE_LIBOIL
32 #include <liboil/liboil.h>
33 #endif
34 #include <string.h>
35 #include <math.h>
36
37 #include <gst/colorbalance/colorbalance.h>
38
39 /* GstVideobalance signals and args */
40 enum
41 {
42   ARG_0,
43   ARG_CONTRAST,
44   ARG_BRIGHTNESS,
45   ARG_HUE,
46   ARG_SATURATION
47       /* FILL ME */
48 };
49
50 static GstVideofilterClass *parent_class = NULL;
51
52 static void gst_videobalance_base_init (gpointer g_class);
53 static void gst_videobalance_class_init (gpointer g_class, gpointer class_data);
54 static void gst_videobalance_init (GTypeInstance * instance, gpointer g_class);
55
56 static void gst_videobalance_set_property (GObject * object, guint prop_id,
57     const GValue * value, GParamSpec * pspec);
58 static void gst_videobalance_get_property (GObject * object, guint prop_id,
59     GValue * value, GParamSpec * pspec);
60
61 static void gst_videobalance_planar411 (GstVideofilter * videofilter,
62     void *dest, void *src);
63 static void gst_videobalance_setup (GstVideofilter * videofilter);
64
65 static void gst_videobalance_interface_init (GstImplementsInterfaceClass *
66     klass);
67 static void gst_videobalance_colorbalance_init (GstColorBalanceClass * iface);
68
69 static void gst_videobalance_dispose (GObject * object);
70 static void gst_videobalance_update_properties (GstVideobalance * videobalance);
71
72 GType
73 gst_videobalance_get_type (void)
74 {
75   static GType videobalance_type = 0;
76
77   if (!videobalance_type) {
78     static const GTypeInfo videobalance_info = {
79       sizeof (GstVideobalanceClass),
80       gst_videobalance_base_init,
81       NULL,
82       gst_videobalance_class_init,
83       NULL,
84       NULL,
85       sizeof (GstVideobalance),
86       0,
87       gst_videobalance_init,
88     };
89
90     static const GInterfaceInfo iface_info = {
91       (GInterfaceInitFunc) gst_videobalance_interface_init,
92       NULL,
93       NULL,
94     };
95
96     static const GInterfaceInfo colorbalance_info = {
97       (GInterfaceInitFunc) gst_videobalance_colorbalance_init,
98       NULL,
99       NULL,
100     };
101
102     videobalance_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
103         "GstVideobalance", &videobalance_info, 0);
104
105     g_type_add_interface_static (videobalance_type,
106         GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
107     g_type_add_interface_static (videobalance_type, GST_TYPE_COLOR_BALANCE,
108         &colorbalance_info);
109   }
110   return videobalance_type;
111 }
112
113 static void
114 gst_videobalance_base_init (gpointer g_class)
115 {
116   static GstElementDetails videobalance_details =
117       GST_ELEMENT_DETAILS ("Video Balance Control",
118       "Filter/Effect/Video",
119       "Adjusts brightness, contrast, hue, saturation on a video stream",
120       "David Schleef <ds@schleef.org>");
121   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
122   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
123   int i;
124
125   gst_element_class_set_details (element_class, &videobalance_details);
126
127   for (i = 0; i < G_N_ELEMENTS (gst_videobalance_formats); i++) {
128     gst_videofilter_class_add_format (videofilter_class,
129         gst_videobalance_formats + i);
130   }
131
132   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
133 }
134
135 static void
136 gst_videobalance_dispose (GObject * object)
137 {
138   GList *channels = NULL;
139   GstVideobalance *balance;
140   gint i;
141
142   balance = GST_VIDEOBALANCE (object);
143
144   if (balance->tableu) {
145     for (i = 0; i < 256; i++)
146       g_free (balance->tableu[i]);
147     g_free (balance->tableu);
148     balance->tableu = NULL;
149   }
150
151   if (balance->tablev) {
152     for (i = 0; i < 256; i++)
153       g_free (balance->tablev[i]);
154     g_free (balance->tablev);
155     balance->tablev = NULL;
156   }
157
158   if (balance->tabley) {
159     g_free (balance->tabley);
160     balance->tabley = NULL;
161   }
162
163   channels = balance->channels;
164   while (channels) {
165     GstColorBalanceChannel *channel = channels->data;
166
167     g_object_unref (channel);
168     channels->data = NULL;
169     channels = g_list_next (channels);
170   }
171
172   if (balance->channels)
173     g_list_free (balance->channels);
174
175   G_OBJECT_CLASS (parent_class)->dispose (object);
176 }
177
178 static void
179 gst_videobalance_class_init (gpointer g_class, gpointer class_data)
180 {
181   GObjectClass *gobject_class;
182   GstVideofilterClass *videofilter_class;
183
184   gobject_class = G_OBJECT_CLASS (g_class);
185   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
186
187   parent_class = g_type_class_ref (GST_TYPE_VIDEOFILTER);
188
189   gobject_class->set_property = gst_videobalance_set_property;
190   gobject_class->get_property = gst_videobalance_get_property;
191
192   g_object_class_install_property (gobject_class, ARG_CONTRAST,
193       g_param_spec_double ("contrast", "Contrast", "contrast",
194           0, 2, 1, G_PARAM_READWRITE));
195   g_object_class_install_property (gobject_class, ARG_BRIGHTNESS,
196       g_param_spec_double ("brightness", "Brightness", "brightness",
197           -1, 1, 0, G_PARAM_READWRITE));
198   g_object_class_install_property (gobject_class, ARG_HUE,
199       g_param_spec_double ("hue", "Hue", "hue", -1, 1, 0, G_PARAM_READWRITE));
200   g_object_class_install_property (gobject_class, ARG_SATURATION,
201       g_param_spec_double ("saturation", "Saturation", "saturation",
202           0, 2, 1, G_PARAM_READWRITE));
203
204   gobject_class->dispose = gst_videobalance_dispose;
205
206   videofilter_class->setup = gst_videobalance_setup;
207
208 #ifdef HAVE_LIBOIL
209   oil_init ();
210 #endif
211 }
212
213 static void
214 gst_videobalance_init (GTypeInstance * instance, gpointer g_class)
215 {
216   GstVideobalance *videobalance = GST_VIDEOBALANCE (instance);
217   GstVideofilter *videofilter;
218   char *channels[4] = { "HUE", "SATURATION",
219     "BRIGHTNESS", "CONTRAST"
220   };
221   gint i;
222
223   GST_DEBUG ("gst_videobalance_init");
224
225   videofilter = GST_VIDEOFILTER (videobalance);
226
227   /* do stuff */
228   videobalance->contrast = 1.0;
229   videobalance->brightness = 0.0;
230   videobalance->saturation = 1.0;
231   videobalance->hue = 0.0;
232
233   videobalance->needupdate = FALSE;
234   videofilter->passthru = TRUE;
235
236   videobalance->tabley = g_new (guint8, 256);
237   videobalance->tableu = g_new (guint8 *, 256);
238   videobalance->tablev = g_new (guint8 *, 256);
239   for (i = 0; i < 256; i++) {
240     videobalance->tableu[i] = g_new (guint8, 256);
241     videobalance->tablev[i] = g_new (guint8, 256);
242   }
243
244   /* Generate the channels list */
245   for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
246     GstColorBalanceChannel *channel;
247
248     channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
249     channel->label = g_strdup (channels[i]);
250     channel->min_value = -1000;
251     channel->max_value = 1000;
252
253     videobalance->channels = g_list_append (videobalance->channels, channel);
254   }
255
256 }
257
258 static gboolean
259 gst_videobalance_interface_supported (GstImplementsInterface * iface,
260     GType type)
261 {
262   g_assert (type == GST_TYPE_COLOR_BALANCE);
263   return TRUE;
264 }
265
266 static void
267 gst_videobalance_interface_init (GstImplementsInterfaceClass * klass)
268 {
269   klass->supported = gst_videobalance_interface_supported;
270 }
271
272 static const GList *
273 gst_videobalance_colorbalance_list_channels (GstColorBalance * balance)
274 {
275   GstVideobalance *videobalance = GST_VIDEOBALANCE (balance);
276
277   g_return_val_if_fail (videobalance != NULL, NULL);
278   g_return_val_if_fail (GST_IS_VIDEOBALANCE (videobalance), NULL);
279
280   return videobalance->channels;
281 }
282
283 static void
284 gst_videobalance_colorbalance_set_value (GstColorBalance * balance,
285     GstColorBalanceChannel * channel, gint value)
286 {
287   GstVideobalance *vb = GST_VIDEOBALANCE (balance);
288
289   g_return_if_fail (vb != NULL);
290   g_return_if_fail (GST_IS_VIDEOBALANCE (vb));
291   g_return_if_fail (GST_IS_VIDEOFILTER (vb));
292   g_return_if_fail (channel->label != NULL);
293
294   if (!g_ascii_strcasecmp (channel->label, "HUE")) {
295     vb->hue = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
296   } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
297     vb->saturation = (value + 1000.0) * 2.0 / 2000.0;
298   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
299     vb->brightness = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
300   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
301     vb->contrast = (value + 1000.0) * 2.0 / 2000.0;
302   }
303
304   gst_videobalance_update_properties (vb);
305 }
306
307 static gint
308 gst_videobalance_colorbalance_get_value (GstColorBalance * balance,
309     GstColorBalanceChannel * channel)
310 {
311   GstVideobalance *vb = GST_VIDEOBALANCE (balance);
312   gint value = 0;
313
314   g_return_val_if_fail (vb != NULL, 0);
315   g_return_val_if_fail (GST_IS_VIDEOBALANCE (vb), 0);
316   g_return_val_if_fail (channel->label != NULL, 0);
317
318   if (!g_ascii_strcasecmp (channel->label, "HUE")) {
319     value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
320   } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
321     value = vb->saturation * 2000.0 / 2.0 - 1000.0;
322   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
323     value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
324   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
325     value = vb->contrast * 2000.0 / 2.0 - 1000.0;
326   }
327
328   return value;
329 }
330
331 static void
332 gst_videobalance_colorbalance_init (GstColorBalanceClass * iface)
333 {
334   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE;
335   iface->list_channels = gst_videobalance_colorbalance_list_channels;
336   iface->set_value = gst_videobalance_colorbalance_set_value;
337   iface->get_value = gst_videobalance_colorbalance_get_value;
338 }
339
340 static void
341 gst_videobalance_update_properties (GstVideobalance * videobalance)
342 {
343   GstVideofilter *vf = GST_VIDEOFILTER (videobalance);
344
345   videobalance->needupdate = TRUE;
346
347   if (videobalance->contrast == 1.0 &&
348       videobalance->brightness == 0.0 &&
349       videobalance->hue == 0.0 && videobalance->saturation == 1.0) {
350     vf->passthru = TRUE;
351   } else {
352     vf->passthru = FALSE;
353   }
354 }
355
356 static void
357 gst_videobalance_set_property (GObject * object, guint prop_id,
358     const GValue * value, GParamSpec * pspec)
359 {
360   GstVideobalance *src;
361
362   g_return_if_fail (GST_IS_VIDEOBALANCE (object));
363   src = GST_VIDEOBALANCE (object);
364
365   GST_DEBUG ("gst_videobalance_set_property");
366   switch (prop_id) {
367     case ARG_CONTRAST:
368       src->contrast = g_value_get_double (value);
369       break;
370     case ARG_BRIGHTNESS:
371       src->brightness = g_value_get_double (value);
372       break;
373     case ARG_HUE:
374       src->hue = g_value_get_double (value);
375       break;
376     case ARG_SATURATION:
377       src->saturation = g_value_get_double (value);
378       break;
379     default:
380       break;
381   }
382
383   gst_videobalance_update_properties (src);
384 }
385
386 static void
387 gst_videobalance_get_property (GObject * object, guint prop_id, GValue * value,
388     GParamSpec * pspec)
389 {
390   GstVideobalance *src;
391
392   g_return_if_fail (GST_IS_VIDEOBALANCE (object));
393   src = GST_VIDEOBALANCE (object);
394
395   switch (prop_id) {
396     case ARG_CONTRAST:
397       g_value_set_double (value, src->contrast);
398       break;
399     case ARG_BRIGHTNESS:
400       g_value_set_double (value, src->brightness);
401       break;
402     case ARG_HUE:
403       g_value_set_double (value, src->hue);
404       break;
405     case ARG_SATURATION:
406       g_value_set_double (value, src->saturation);
407       break;
408     default:
409       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
410       break;
411   }
412 }
413
414 static gboolean
415 plugin_init (GstPlugin * plugin)
416 {
417   if (!gst_library_load ("gstvideofilter"))
418     return FALSE;
419
420   return gst_element_register (plugin, "videobalance", GST_RANK_NONE,
421       GST_TYPE_VIDEOBALANCE);
422 }
423
424 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
425     GST_VERSION_MINOR,
426     "videobalance",
427     "Changes hue, saturation, brightness etc. on video images",
428     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
429
430 static void
431 gst_videobalance_setup (GstVideofilter * videofilter)
432 {
433   GstVideobalance *videobalance;
434
435   g_return_if_fail (GST_IS_VIDEOBALANCE (videofilter));
436   videobalance = GST_VIDEOBALANCE (videofilter);
437
438   /* if any setup needs to be done, do it here */
439
440 }
441
442 /*
443  * look-up tables (LUT).
444  */
445
446 static void
447 gst_videobalance_update_tables_planar411 (GstVideobalance * vb)
448 {
449   gint i, j;
450   gdouble y, u, v, hue_cos, hue_sin;
451
452   /* Y */
453   for (i = 0; i < 256; i++) {
454     y = 16 + ((i - 16) * vb->contrast + vb->brightness * 255);
455     if (y < 0)
456       y = 0;
457     else if (y > 255)
458       y = 255;
459     vb->tabley[i] = rint (y);
460   }
461
462   /* FIXME this is a bogus transformation for hue, but you get
463    * the idea */
464   hue_cos = cos (M_PI * vb->hue);
465   hue_sin = sin (M_PI * vb->hue);
466
467   /* U/V lookup tables are 2D, since we need both U/V for each table
468    * separately. */
469   for (i = -128; i < 128; i++) {
470     for (j = -128; j < 128; j++) {
471       u = 128 + ((i * hue_cos + j * hue_sin) * vb->saturation);
472       v = 128 + ((-i * hue_sin + j * hue_cos) * vb->saturation);
473       if (u < 0)
474         u = 0;
475       else if (u > 255)
476         u = 255;
477       if (v < 0)
478         v = 0;
479       else if (v > 255)
480         v = 255;
481       vb->tableu[i + 128][j + 128] = rint (u);
482       vb->tablev[i + 128][j + 128] = rint (v);
483     }
484   }
485 }
486
487 #ifndef HAVE_LIBOIL
488 void
489 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
490     guint8 * table, int tstr, int n)
491 {
492   int i;
493
494   for (i = 0; i < n; i++) {
495     *dest = table[*src * tstr];
496     dest += dstr;
497     src += sstr;
498   }
499 }
500 #endif
501
502 static void
503 gst_videobalance_planar411 (GstVideofilter * videofilter, void *dest, void *src)
504 {
505   GstVideobalance *videobalance;
506   int width;
507   int height;
508   int x, y;
509
510   g_return_if_fail (GST_IS_VIDEOBALANCE (videofilter));
511   videobalance = GST_VIDEOBALANCE (videofilter);
512
513   if (videobalance->needupdate) {
514     gst_videobalance_update_tables_planar411 (videobalance);
515     videobalance->needupdate = FALSE;
516   }
517
518   width = videofilter->from_width;
519   height = videofilter->from_height;
520
521   {
522     guint8 *cdest = dest;
523     guint8 *csrc = src;
524
525     for (y = 0; y < height; y++) {
526       oil_tablelookup_u8 (cdest + y * width, 1, csrc + y * width, 1,
527           videobalance->tabley, 1, width);
528     }
529   }
530
531   {
532     gint u1, v1;
533     guint8 *usrc, *vsrc;
534     guint8 *udest, *vdest;
535
536     usrc = src + width * height;
537     udest = dest + width * height;
538     vsrc = src + width * height + (width / 2) * (height / 2);
539     vdest = dest + width * height + (width / 2) * (height / 2);
540
541     for (y = 0; y < height / 2; y++) {
542       for (x = 0; x < width / 2; x++) {
543         u1 = usrc[y * (width / 2) + x];
544         v1 = vsrc[y * (width / 2) + x];
545         udest[y * (width / 2) + x] = videobalance->tableu[u1][v1];
546         vdest[y * (width / 2) + x] = videobalance->tablev[u1][v1];
547       }
548     }
549   }
550
551 }