Remove unused variables in _class_init
[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 /**
27  * SECTION:element-videobalance
28  *
29  * Adjusts brightness, contrast, hue, saturation on a video stream.
30  *
31  * <refsect2>
32  * <title>Example launch line</title>
33  * |[
34  * gst-launch videotestsrc ! videobalance saturation=0.0 ! ffmpegcolorspace ! ximagesink
35  * ]| This pipeline converts the image to black and white by setting the
36  * saturation to 0.0.
37  * </refsect2>
38  *
39  * Last reviewed on 2006-03-03 (0.10.3)
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include "gstvideobalance.h"
47 #ifdef HAVE_LIBOIL
48 #include <liboil/liboil.h>
49 #endif
50 #include <string.h>
51 #include <math.h>
52
53 #include <gst/video/video.h>
54 #include <gst/interfaces/colorbalance.h>
55
56 #ifndef M_PI
57 #define M_PI  3.14159265358979323846
58 #endif
59
60 #ifdef WIN32
61 #define rint(x) (floor((x)+0.5))
62 #endif
63
64 static const GstElementDetails video_balance_details =
65 GST_ELEMENT_DETAILS ("Video balance",
66     "Filter/Effect/Video",
67     "Adjusts brightness, contrast, hue, saturation on a video stream",
68     "David Schleef <ds@schleef.org>");
69
70 /* GstVideoBalance signals and args */
71 #define DEFAULT_PROP_CONTRAST           1.0
72 #define DEFAULT_PROP_BRIGHTNESS         0.0
73 #define DEFAULT_PROP_HUE                0.0
74 #define DEFAULT_PROP_SATURATION         1.0
75
76 enum
77 {
78   PROP_0,
79   PROP_CONTRAST,
80   PROP_BRIGHTNESS,
81   PROP_HUE,
82   PROP_SATURATION
83 };
84
85 static GstStaticPadTemplate gst_video_balance_src_template =
86 GST_STATIC_PAD_TEMPLATE ("src",
87     GST_PAD_SRC,
88     GST_PAD_ALWAYS,
89     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
90     );
91
92 static GstStaticPadTemplate gst_video_balance_sink_template =
93 GST_STATIC_PAD_TEMPLATE ("sink",
94     GST_PAD_SINK,
95     GST_PAD_ALWAYS,
96     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
97     );
98
99 /*
100  * look-up tables (LUT).
101  */
102 static void
103 gst_video_balance_update_tables_planar411 (GstVideoBalance * vb)
104 {
105   gint i, j;
106   gdouble y, u, v, hue_cos, hue_sin;
107
108   /* Y */
109   for (i = 0; i < 256; i++) {
110     y = 16 + ((i - 16) * vb->contrast + vb->brightness * 255);
111     if (y < 0)
112       y = 0;
113     else if (y > 255)
114       y = 255;
115     vb->tabley[i] = rint (y);
116   }
117
118   /* FIXME this is a bogus transformation for hue, but you get
119    * the idea */
120   hue_cos = cos (M_PI * vb->hue);
121   hue_sin = sin (M_PI * vb->hue);
122
123   /* U/V lookup tables are 2D, since we need both U/V for each table
124    * separately. */
125   for (i = -128; i < 128; i++) {
126     for (j = -128; j < 128; j++) {
127       u = 128 + ((i * hue_cos + j * hue_sin) * vb->saturation);
128       v = 128 + ((-i * hue_sin + j * hue_cos) * vb->saturation);
129       if (u < 0)
130         u = 0;
131       else if (u > 255)
132         u = 255;
133       if (v < 0)
134         v = 0;
135       else if (v > 255)
136         v = 255;
137       vb->tableu[i + 128][j + 128] = rint (u);
138       vb->tablev[i + 128][j + 128] = rint (v);
139     }
140   }
141 }
142
143 static gboolean
144 gst_video_balance_is_passthrough (GstVideoBalance * videobalance)
145 {
146   return videobalance->contrast == 1.0 &&
147       videobalance->brightness == 0.0 &&
148       videobalance->hue == 0.0 && videobalance->saturation == 1.0;
149 }
150
151 static void
152 gst_video_balance_update_properties (GstVideoBalance * videobalance)
153 {
154   videobalance->passthru = gst_video_balance_is_passthrough (videobalance);
155
156   if (!videobalance->passthru) {
157     gst_video_balance_update_tables_planar411 (videobalance);
158   }
159 }
160
161 #ifndef HAVE_LIBOIL
162 void
163 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
164     guint8 * table, int tstr, int n)
165 {
166   int i;
167
168   for (i = 0; i < n; i++) {
169     *dest = table[*src * tstr];
170     dest += dstr;
171     src += sstr;
172   }
173 }
174 #endif
175
176 /* Useful macros */
177 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
178 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
179 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
180
181 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
182 #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
183 #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
184 #define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
185
186 static void
187 gst_video_balance_planar411_ip (GstVideoBalance * videobalance, guint8 * data,
188     gint width, gint height)
189 {
190   int x, y;
191   guint8 *ydata;
192   guint8 *udata, *vdata;
193   gint ystride, ustride, vstride;
194   gint width2, height2;
195
196   ydata = data + GST_VIDEO_I420_Y_OFFSET (width, height);
197   ystride = GST_VIDEO_I420_Y_ROWSTRIDE (width);
198
199   for (y = 0; y < height; y++) {
200     oil_tablelookup_u8 (ydata, 1, ydata, 1, videobalance->tabley, 1, width);
201     ydata += ystride;
202   }
203
204   width2 = width >> 1;
205   height2 = height >> 1;
206
207   udata = data + GST_VIDEO_I420_U_OFFSET (width, height);
208   vdata = data + GST_VIDEO_I420_V_OFFSET (width, height);
209   ustride = GST_VIDEO_I420_U_ROWSTRIDE (width);
210   vstride = GST_VIDEO_I420_V_ROWSTRIDE (width);
211
212   for (y = 0; y < height2; y++) {
213     guint8 *uptr, *vptr;
214     guint8 u1, v1;
215
216     uptr = udata + y * ustride;
217     vptr = vdata + y * vstride;
218
219     for (x = 0; x < width2; x++) {
220       u1 = *uptr;
221       v1 = *vptr;
222
223       *uptr++ = videobalance->tableu[u1][v1];
224       *vptr++ = videobalance->tablev[u1][v1];
225     }
226   }
227 }
228
229 /* get notified of caps and plug in the correct process function */
230 static gboolean
231 gst_video_balance_set_caps (GstBaseTransform * base, GstCaps * incaps,
232     GstCaps * outcaps)
233 {
234   GstVideoBalance *this;
235   GstStructure *structure;
236   gboolean res;
237
238   this = GST_VIDEO_BALANCE (base);
239
240   GST_DEBUG_OBJECT (this,
241       "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
242
243   structure = gst_caps_get_structure (incaps, 0);
244
245   res = gst_structure_get_int (structure, "width", &this->width);
246   res &= gst_structure_get_int (structure, "height", &this->height);
247   if (!res)
248     goto done;
249
250   this->size = GST_VIDEO_I420_SIZE (this->width, this->height);
251
252 done:
253   return res;
254 }
255
256 static GstFlowReturn
257 gst_video_balance_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
258 {
259   GstVideoBalance *videobalance;
260   guint8 *data;
261   guint size;
262   gint width, height;
263
264   videobalance = GST_VIDEO_BALANCE (base);
265
266   /* if no change is needed, we are done */
267   if (videobalance->passthru)
268     goto done;
269
270   data = GST_BUFFER_DATA (outbuf);
271   size = GST_BUFFER_SIZE (outbuf);
272
273   width = videobalance->width;
274   height = videobalance->height;
275
276   if (size < videobalance->size)
277     goto wrong_size;
278
279   gst_video_balance_planar411_ip (videobalance, data,
280       videobalance->width, videobalance->height);
281
282 done:
283   return GST_FLOW_OK;
284
285   /* ERRORS */
286 wrong_size:
287   {
288     GST_ELEMENT_ERROR (videobalance, STREAM, FORMAT,
289         (NULL), ("Invalid buffer size %d, expected %d", size,
290             videobalance->size));
291     return GST_FLOW_ERROR;
292   }
293 }
294
295
296 /****************
297  * Boilerplate
298  */
299 static GstVideoFilterClass *parent_class = NULL;
300
301 static void gst_video_balance_set_property (GObject * object, guint prop_id,
302     const GValue * value, GParamSpec * pspec);
303 static void gst_video_balance_get_property (GObject * object, guint prop_id,
304     GValue * value, GParamSpec * pspec);
305
306 static void
307 gst_video_balance_base_init (gpointer g_class)
308 {
309   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
310
311   gst_element_class_set_details (element_class, &video_balance_details);
312
313   gst_element_class_add_pad_template (element_class,
314       gst_static_pad_template_get (&gst_video_balance_sink_template));
315   gst_element_class_add_pad_template (element_class,
316       gst_static_pad_template_get (&gst_video_balance_src_template));
317 }
318
319 static void
320 gst_video_balance_finalize (GObject * object)
321 {
322   GList *channels = NULL;
323   GstVideoBalance *balance;
324   gint i;
325
326   balance = GST_VIDEO_BALANCE (object);
327
328   if (balance->tableu) {
329     for (i = 0; i < 256; i++)
330       g_free (balance->tableu[i]);
331     g_free (balance->tableu);
332     balance->tableu = NULL;
333   }
334
335   if (balance->tablev) {
336     for (i = 0; i < 256; i++)
337       g_free (balance->tablev[i]);
338     g_free (balance->tablev);
339     balance->tablev = NULL;
340   }
341
342   if (balance->tabley) {
343     g_free (balance->tabley);
344     balance->tabley = NULL;
345   }
346
347   channels = balance->channels;
348   while (channels) {
349     GstColorBalanceChannel *channel = channels->data;
350
351     g_object_unref (channel);
352     channels->data = NULL;
353     channels = g_list_next (channels);
354   }
355
356   if (balance->channels)
357     g_list_free (balance->channels);
358
359   G_OBJECT_CLASS (parent_class)->finalize (object);
360 }
361
362 static void
363 gst_video_balance_class_init (gpointer g_class, gpointer class_data)
364 {
365   GObjectClass *gobject_class;
366   GstBaseTransformClass *trans_class;
367
368   gobject_class = G_OBJECT_CLASS (g_class);
369   trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
370
371   parent_class = g_type_class_peek_parent (g_class);
372
373   gobject_class->set_property = gst_video_balance_set_property;
374   gobject_class->get_property = gst_video_balance_get_property;
375
376   g_object_class_install_property (gobject_class, PROP_CONTRAST,
377       g_param_spec_double ("contrast", "Contrast", "contrast",
378           0.0, 2.0, DEFAULT_PROP_CONTRAST, G_PARAM_READWRITE));
379   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
380       g_param_spec_double ("brightness", "Brightness", "brightness",
381           -1.0, 1.0, DEFAULT_PROP_BRIGHTNESS, G_PARAM_READWRITE));
382   g_object_class_install_property (gobject_class, PROP_HUE,
383       g_param_spec_double ("hue", "Hue", "hue",
384           -1.0, 1.0, DEFAULT_PROP_HUE, G_PARAM_READWRITE));
385   g_object_class_install_property (gobject_class, PROP_SATURATION,
386       g_param_spec_double ("saturation", "Saturation", "saturation",
387           0.0, 2.0, DEFAULT_PROP_SATURATION, G_PARAM_READWRITE));
388
389   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_video_balance_finalize);
390
391   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_balance_set_caps);
392   trans_class->transform_ip =
393       GST_DEBUG_FUNCPTR (gst_video_balance_transform_ip);
394
395 #ifdef HAVE_LIBOIL
396   oil_init ();
397 #endif
398 }
399
400 static void
401 gst_video_balance_init (GTypeInstance * instance, gpointer g_class)
402 {
403   GstVideoBalance *videobalance = GST_VIDEO_BALANCE (instance);
404   GstVideoFilter *videofilter;
405   char *channels[4] = { "HUE", "SATURATION",
406     "BRIGHTNESS", "CONTRAST"
407   };
408   gint i;
409
410   GST_DEBUG ("gst_video_balance_init");
411
412   videofilter = GST_VIDEO_FILTER (videobalance);
413
414   /* do stuff */
415   videobalance->contrast = DEFAULT_PROP_CONTRAST;
416   videobalance->brightness = DEFAULT_PROP_BRIGHTNESS;
417   videobalance->hue = DEFAULT_PROP_HUE;
418   videobalance->saturation = DEFAULT_PROP_SATURATION;
419
420   gst_video_balance_update_properties (videobalance);
421
422   videobalance->tabley = g_new (guint8, 256);
423   videobalance->tableu = g_new (guint8 *, 256);
424   videobalance->tablev = g_new (guint8 *, 256);
425   for (i = 0; i < 256; i++) {
426     videobalance->tableu[i] = g_new (guint8, 256);
427     videobalance->tablev[i] = g_new (guint8, 256);
428   }
429
430   /* Generate the channels list */
431   for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
432     GstColorBalanceChannel *channel;
433
434     channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
435     channel->label = g_strdup (channels[i]);
436     channel->min_value = -1000;
437     channel->max_value = 1000;
438
439     videobalance->channels = g_list_append (videobalance->channels, channel);
440   }
441
442 }
443
444 static gboolean
445 gst_video_balance_interface_supported (GstImplementsInterface * iface,
446     GType type)
447 {
448   g_assert (type == GST_TYPE_COLOR_BALANCE);
449   return TRUE;
450 }
451
452 static void
453 gst_video_balance_interface_init (GstImplementsInterfaceClass * klass)
454 {
455   klass->supported = gst_video_balance_interface_supported;
456 }
457
458 static const GList *
459 gst_video_balance_colorbalance_list_channels (GstColorBalance * balance)
460 {
461   GstVideoBalance *videobalance = GST_VIDEO_BALANCE (balance);
462
463   g_return_val_if_fail (videobalance != NULL, NULL);
464   g_return_val_if_fail (GST_IS_VIDEO_BALANCE (videobalance), NULL);
465
466   return videobalance->channels;
467 }
468
469 static void
470 gst_video_balance_colorbalance_set_value (GstColorBalance * balance,
471     GstColorBalanceChannel * channel, gint value)
472 {
473   GstVideoBalance *vb = GST_VIDEO_BALANCE (balance);
474
475   g_return_if_fail (vb != NULL);
476   g_return_if_fail (GST_IS_VIDEO_BALANCE (vb));
477   g_return_if_fail (GST_IS_VIDEO_FILTER (vb));
478   g_return_if_fail (channel->label != NULL);
479
480   if (!g_ascii_strcasecmp (channel->label, "HUE")) {
481     vb->hue = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
482   } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
483     vb->saturation = (value + 1000.0) * 2.0 / 2000.0;
484   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
485     vb->brightness = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
486   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
487     vb->contrast = (value + 1000.0) * 2.0 / 2000.0;
488   }
489
490   gst_video_balance_update_properties (vb);
491 }
492
493 static gint
494 gst_video_balance_colorbalance_get_value (GstColorBalance * balance,
495     GstColorBalanceChannel * channel)
496 {
497   GstVideoBalance *vb = GST_VIDEO_BALANCE (balance);
498   gint value = 0;
499
500   g_return_val_if_fail (vb != NULL, 0);
501   g_return_val_if_fail (GST_IS_VIDEO_BALANCE (vb), 0);
502   g_return_val_if_fail (channel->label != NULL, 0);
503
504   if (!g_ascii_strcasecmp (channel->label, "HUE")) {
505     value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
506   } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
507     value = vb->saturation * 2000.0 / 2.0 - 1000.0;
508   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
509     value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
510   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
511     value = vb->contrast * 2000.0 / 2.0 - 1000.0;
512   }
513
514   return value;
515 }
516
517 static void
518 gst_video_balance_colorbalance_init (GstColorBalanceClass * iface)
519 {
520   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE;
521   iface->list_channels = gst_video_balance_colorbalance_list_channels;
522   iface->set_value = gst_video_balance_colorbalance_set_value;
523   iface->get_value = gst_video_balance_colorbalance_get_value;
524 }
525
526 static void
527 gst_video_balance_set_property (GObject * object, guint prop_id,
528     const GValue * value, GParamSpec * pspec)
529 {
530   GstVideoBalance *src;
531
532   src = GST_VIDEO_BALANCE (object);
533
534   GST_DEBUG ("gst_video_balance_set_property");
535   switch (prop_id) {
536     case PROP_CONTRAST:
537       src->contrast = g_value_get_double (value);
538       break;
539     case PROP_BRIGHTNESS:
540       src->brightness = g_value_get_double (value);
541       break;
542     case PROP_HUE:
543       src->hue = g_value_get_double (value);
544       break;
545     case PROP_SATURATION:
546       src->saturation = g_value_get_double (value);
547       break;
548     default:
549       break;
550   }
551
552   gst_video_balance_update_properties (src);
553 }
554
555 static void
556 gst_video_balance_get_property (GObject * object, guint prop_id, GValue * value,
557     GParamSpec * pspec)
558 {
559   GstVideoBalance *src;
560
561   src = GST_VIDEO_BALANCE (object);
562
563   switch (prop_id) {
564     case PROP_CONTRAST:
565       g_value_set_double (value, src->contrast);
566       break;
567     case PROP_BRIGHTNESS:
568       g_value_set_double (value, src->brightness);
569       break;
570     case PROP_HUE:
571       g_value_set_double (value, src->hue);
572       break;
573     case PROP_SATURATION:
574       g_value_set_double (value, src->saturation);
575       break;
576     default:
577       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
578       break;
579   }
580 }
581
582 GType
583 gst_video_balance_get_type (void)
584 {
585   static GType video_balance_type = 0;
586
587   if (!video_balance_type) {
588     static const GTypeInfo video_balance_info = {
589       sizeof (GstVideoBalanceClass),
590       gst_video_balance_base_init,
591       NULL,
592       gst_video_balance_class_init,
593       NULL,
594       NULL,
595       sizeof (GstVideoBalance),
596       0,
597       gst_video_balance_init,
598     };
599
600     static const GInterfaceInfo iface_info = {
601       (GInterfaceInitFunc) gst_video_balance_interface_init,
602       NULL,
603       NULL,
604     };
605
606     static const GInterfaceInfo colorbalance_info = {
607       (GInterfaceInitFunc) gst_video_balance_colorbalance_init,
608       NULL,
609       NULL,
610     };
611
612     video_balance_type = g_type_register_static (GST_TYPE_VIDEO_FILTER,
613         "GstVideoBalance", &video_balance_info, 0);
614
615     g_type_add_interface_static (video_balance_type,
616         GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
617     g_type_add_interface_static (video_balance_type, GST_TYPE_COLOR_BALANCE,
618         &colorbalance_info);
619   }
620   return video_balance_type;
621 }
622
623
624 static gboolean
625 plugin_init (GstPlugin * plugin)
626 {
627   return gst_element_register (plugin, "videobalance", GST_RANK_NONE,
628       GST_TYPE_VIDEO_BALANCE);
629 }
630
631 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
632     GST_VERSION_MINOR,
633     "videobalance",
634     "Changes hue, saturation, brightness etc. on video images",
635     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);