2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David Schleef <ds@schleef.org>
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.
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.
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.
22 * This file was (probably) generated from gstvideobalance.c,
23 * gstvideobalance.c,v 1.7 2003/11/08 02:48:59 dschleef Exp
30 /*#define DEBUG_ENABLED */
31 #include <gstvideobalance.h>
33 #include <liboil/liboil.h>
38 #include <gst/colorbalance/colorbalance.h>
40 /* GstVideobalance signals and args */
55 static GstVideofilterClass *parent_class = NULL;
57 static void gst_videobalance_base_init (gpointer g_class);
58 static void gst_videobalance_class_init (gpointer g_class, gpointer class_data);
59 static void gst_videobalance_init (GTypeInstance *instance, gpointer g_class);
61 static void gst_videobalance_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
62 static void gst_videobalance_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
64 static void gst_videobalance_planar411(GstVideofilter *videofilter, void *dest, void *src);
65 static void gst_videobalance_setup(GstVideofilter *videofilter);
67 static void gst_videobalance_interface_init (GstImplementsInterfaceClass *klass);
68 static void gst_videobalance_colorbalance_init (GstColorBalanceClass *iface);
70 static void gst_videobalance_dispose (GObject *object);
71 static void gst_videobalance_update_properties (GstVideobalance *videobalance);
74 gst_videobalance_get_type (void)
76 static GType videobalance_type = 0;
78 if (!videobalance_type) {
79 static const GTypeInfo videobalance_info = {
80 sizeof(GstVideobalanceClass),
81 gst_videobalance_base_init,
83 gst_videobalance_class_init,
86 sizeof(GstVideobalance),
88 gst_videobalance_init,
91 static const GInterfaceInfo iface_info = {
92 (GInterfaceInitFunc) gst_videobalance_interface_init,
97 static const GInterfaceInfo colorbalance_info = {
98 (GInterfaceInitFunc) gst_videobalance_colorbalance_init,
103 videobalance_type = g_type_register_static(GST_TYPE_VIDEOFILTER,
104 "GstVideobalance", &videobalance_info, 0);
106 g_type_add_interface_static (videobalance_type, GST_TYPE_IMPLEMENTS_INTERFACE,
108 g_type_add_interface_static (videobalance_type, GST_TYPE_COLOR_BALANCE,
111 return videobalance_type;
114 static GstVideofilterFormat gst_videobalance_formats[] = {
115 { "I420", 12, gst_videobalance_planar411, },
120 gst_videobalance_base_init (gpointer g_class)
122 static GstElementDetails videobalance_details = GST_ELEMENT_DETAILS (
123 "Video Balance Control",
124 "Filter/Effect/Video",
125 "Adjusts brightness, contrast, hue, saturation on a video stream",
126 "David Schleef <ds@schleef.org>"
128 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
129 GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
132 gst_element_class_set_details (element_class, &videobalance_details);
134 for(i=0;i<G_N_ELEMENTS(gst_videobalance_formats);i++){
135 gst_videofilter_class_add_format(videofilter_class,
136 gst_videobalance_formats + i);
139 gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
143 gst_videobalance_dispose (GObject *object)
145 GList *channels = NULL;
146 GstVideobalance *balance;
149 balance = GST_VIDEOBALANCE (object);
151 for (i = 0; i < 256; i++) {
152 g_free (balance->tableu[i]);
153 g_free (balance->tablev[i]);
155 g_free (balance->tabley);
156 g_free (balance->tableu);
157 g_free (balance->tablev);
159 channels = balance->channels;
163 GstColorBalanceChannel *channel = channels->data;
164 g_object_unref (channel);
165 channels = g_list_next (channels);
168 if (balance->channels)
169 g_list_free (balance->channels);
171 G_OBJECT_CLASS (parent_class)->dispose (object);
175 gst_videobalance_class_init (gpointer g_class, gpointer class_data)
177 GObjectClass *gobject_class;
178 GstVideofilterClass *videofilter_class;
180 gobject_class = G_OBJECT_CLASS (g_class);
181 videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
183 parent_class = g_type_class_ref (GST_TYPE_VIDEOFILTER);
185 g_object_class_install_property(gobject_class, ARG_CONTRAST,
186 g_param_spec_double("contrast","Contrast","contrast",
187 0, 2, 1, G_PARAM_READWRITE));
188 g_object_class_install_property(gobject_class, ARG_BRIGHTNESS,
189 g_param_spec_double("brightness","Brightness","brightness",
190 -1, 1, 0, G_PARAM_READWRITE));
191 g_object_class_install_property(gobject_class, ARG_HUE,
192 g_param_spec_double("hue","Hue","hue",
193 -1, 1, 0, G_PARAM_READWRITE));
194 g_object_class_install_property(gobject_class, ARG_SATURATION,
195 g_param_spec_double("saturation","Saturation","saturation",
196 0, 2, 1, G_PARAM_READWRITE));
198 gobject_class->set_property = gst_videobalance_set_property;
199 gobject_class->get_property = gst_videobalance_get_property;
200 gobject_class->dispose = gst_videobalance_dispose;
202 videofilter_class->setup = gst_videobalance_setup;
210 gst_videobalance_init (GTypeInstance *instance, gpointer g_class)
212 GstVideobalance *videobalance = GST_VIDEOBALANCE (instance);
213 GstVideofilter *videofilter;
214 char *channels[4] = { "HUE", "SATURATION",
215 "BRIGHTNESS", "CONTRAST" };
218 GST_DEBUG("gst_videobalance_init");
220 videofilter = GST_VIDEOFILTER(videobalance);
223 videobalance->contrast = 1.0;
224 videobalance->brightness = 0.0;
225 videobalance->saturation = 1.0;
226 videobalance->hue = 0.0;
228 videobalance->needupdate = FALSE;
229 videofilter->passthru = TRUE;
231 videobalance->tabley = g_new (guint8, 256);
232 videobalance->tableu = g_new (guint8 *, 256);
233 videobalance->tablev = g_new (guint8 *, 256);
234 for (i = 0; i < 256; i++) {
235 videobalance->tableu[i] = g_new (guint8, 256);
236 videobalance->tablev[i] = g_new (guint8, 256);
239 /* Generate the channels list */
240 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++)
242 GstColorBalanceChannel *channel;
244 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
245 channel->label = g_strdup (channels[i]);
246 channel->min_value = -1000;
247 channel->max_value = 1000;
249 videobalance->channels = g_list_append (videobalance->channels,
256 gst_videobalance_interface_supported (GstImplementsInterface *iface, GType type)
258 g_assert (type == GST_TYPE_COLOR_BALANCE);
263 gst_videobalance_interface_init (GstImplementsInterfaceClass *klass)
265 klass->supported = gst_videobalance_interface_supported;
269 gst_videobalance_colorbalance_list_channels (GstColorBalance *balance)
271 GstVideobalance *videobalance = GST_VIDEOBALANCE (balance);
273 g_return_val_if_fail (videobalance != NULL, NULL);
274 g_return_val_if_fail (GST_IS_VIDEOBALANCE (videobalance), NULL);
276 return videobalance->channels;
280 gst_videobalance_colorbalance_set_value (GstColorBalance *balance,
281 GstColorBalanceChannel *channel,
284 GstVideobalance *vb = GST_VIDEOBALANCE (balance);
285 GstVideofilter *vf = GST_VIDEOFILTER (vb);
287 g_return_if_fail (vb != NULL);
288 g_return_if_fail (GST_IS_VIDEOBALANCE (vb));
289 g_return_if_fail (GST_IS_VIDEOFILTER (vf));
290 g_return_if_fail (channel->label != NULL);
292 if (!g_ascii_strcasecmp (channel->label, "HUE")) {
293 vb->hue = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
294 } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
295 vb->saturation = (value + 1000.0) * 2.0 / 2000.0;
296 } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
297 vb->brightness = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
298 } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
299 vb->contrast = (value + 1000.0) * 2.0 / 2000.0;
302 gst_videobalance_update_properties (vb);
306 gst_videobalance_colorbalance_get_value (GstColorBalance *balance,
307 GstColorBalanceChannel *channel)
309 GstVideobalance *vb = GST_VIDEOBALANCE (balance);
312 g_return_val_if_fail (vb != NULL, 0);
313 g_return_val_if_fail (GST_IS_VIDEOBALANCE (vb), 0);
314 g_return_val_if_fail (channel->label != NULL, 0);
316 if (!g_ascii_strcasecmp (channel->label, "HUE")) {
317 value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
318 } else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
319 value = vb->saturation * 2000.0 / 2.0 - 1000.0;
320 } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
321 value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
322 } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
323 value = vb->contrast * 2000.0 / 2.0 - 1000.0;
330 gst_videobalance_colorbalance_init (GstColorBalanceClass *iface)
332 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE;
333 iface->list_channels = gst_videobalance_colorbalance_list_channels;
334 iface->set_value = gst_videobalance_colorbalance_set_value;
335 iface->get_value = gst_videobalance_colorbalance_get_value;
339 gst_videobalance_update_properties (GstVideobalance *videobalance)
341 GstVideofilter *vf = GST_VIDEOFILTER (videobalance);
343 videobalance->needupdate = TRUE;
345 if (videobalance->contrast == 1.0 &&
346 videobalance->brightness == 0.0 &&
347 videobalance->hue == 0.0 &&
348 videobalance->saturation == 1.0) {
351 vf->passthru = FALSE;
356 gst_videobalance_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
358 GstVideobalance *src;
360 /* it's not null if we got it, but it might not be ours */
361 g_return_if_fail(GST_IS_VIDEOBALANCE(object));
362 src = GST_VIDEOBALANCE(object);
364 GST_DEBUG("gst_videobalance_set_property");
367 src->contrast = g_value_get_double (value);
370 src->brightness = g_value_get_double (value);
373 src->hue = g_value_get_double (value);
376 src->saturation = g_value_get_double (value);
382 gst_videobalance_update_properties (src);
386 gst_videobalance_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
388 GstVideobalance *src;
390 /* it's not null if we got it, but it might not be ours */
391 g_return_if_fail(GST_IS_VIDEOBALANCE(object));
392 src = GST_VIDEOBALANCE(object);
396 g_value_set_double (value, src->contrast);
399 g_value_set_double (value, src->brightness);
402 g_value_set_double (value, src->hue);
405 g_value_set_double (value, src->saturation);
408 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
413 static gboolean plugin_init (GstPlugin *plugin)
415 if(!gst_library_load("gstvideofilter"))
418 return gst_element_register (plugin, "videobalance", GST_RANK_NONE,
419 GST_TYPE_VIDEOBALANCE);
426 "Changes hue, saturation, brightness etc. on video images",
434 static void gst_videobalance_setup(GstVideofilter *videofilter)
436 GstVideobalance *videobalance;
438 g_return_if_fail(GST_IS_VIDEOBALANCE(videofilter));
439 videobalance = GST_VIDEOBALANCE(videofilter);
441 /* if any setup needs to be done, do it here */
446 * look-up tables (LUT).
450 gst_videobalance_update_tables_planar411 (GstVideobalance *vb)
453 gdouble y, u, v, hue_cos, hue_sin;
456 for (i = 0; i < 256; i++) {
457 y = 16 + ((i - 16) * vb->contrast + vb->brightness * 255);
462 vb->tabley[i] = rint (y);
465 /* FIXME this is a bogus transformation for hue, but you get
467 hue_cos = cos (M_PI * vb->hue);
468 hue_sin = sin (M_PI * vb->hue);
470 /* U/V lookup tables are 2D, since we need both U/V for each table
472 for (i = -128; i < 128; i++) {
473 for (j = -128; j < 128; j++) {
474 u = 128 + (( i * hue_cos + j * hue_sin) * vb->saturation);
475 v = 128 + ((-i * hue_sin + j * hue_cos) * vb->saturation);
484 vb->tableu[i+128][j+128] = rint (u);
485 vb->tablev[i+128][j+128] = rint (v);
491 void tablelookup_u8 (guint8 *dest, int dstr, guint8 *src, int sstr,
492 guint8 *table, int tstr, int n)
496 *dest = table[*src * tstr];
503 static void gst_videobalance_planar411(GstVideofilter *videofilter,
504 void *dest, void *src)
506 GstVideobalance *videobalance;
511 g_return_if_fail(GST_IS_VIDEOBALANCE(videofilter));
512 videobalance = GST_VIDEOBALANCE(videofilter);
514 if (videobalance->needupdate) {
515 gst_videobalance_update_tables_planar411 (videobalance);
516 videobalance->needupdate = FALSE;
519 width = videofilter->from_width;
520 height = videofilter->from_height;
523 guint8 *cdest = dest;
526 for(y=0;y<height;y++) {
527 tablelookup_u8 (cdest + y*width, 1, csrc + y*width, 1,
528 videobalance->tabley, 1, width);
535 guint8 *udest, *vdest;
537 usrc = src + width*height;
538 udest = dest + width*height;
539 vsrc = src + width*height + (width/2)*(height/2);
540 vdest = dest + width*height + (width/2)*(height/2);
542 for(y=0;y<height/2;y++){
543 for(x=0;x<width/2;x++){
544 u1 = usrc[y*(width/2) + x];
545 v1 = vsrc[y*(width/2) + x];
546 udest[y*(width/2) + x] = videobalance->tableu[u1][v1];
547 vdest[y*(width/2) + x] = videobalance->tablev[u1][v1];