gstreamer/gst/videofilter/gstvideobalance.c
Julien Moutte 2ea4f5b3c9 VideoFilter inherits from
Original commit message from CVS:
2005-11-23  Julien MOUTTE  <julien@moutte.net>

* ext/cairo/gsttimeoverlay.c:
(gst_timeoverlay_update_font_height),
(gst_timeoverlay_set_caps), (gst_timeoverlay_get_unit_size),
(gst_timeoverlay_transform), (gst_timeoverlay_base_init),
(gst_timeoverlay_class_init), (gst_timeoverlay_init),
(gst_timeoverlay_get_type):
* ext/cairo/gsttimeoverlay.h:
* gst/debug/Makefile.am:
* gst/debug/gstnavigationtest.c:
(gst_navigationtest_handle_src_event),
(gst_navigationtest_get_unit_size),
(gst_navigationtest_set_caps),
(gst_navigationtest_transform),
(gst_navigationtest_change_state),
(gst_navigationtest_base_init), (gst_navigationtest_class_init),
(gst_navigationtest_init), (gst_navigationtest_get_type),
(plugin_init):
* gst/debug/gstnavigationtest.h:
* gst/effectv/Makefile.am:
* gst/effectv/gstaging.c: (gst_agingtv_set_caps),
(gst_agingtv_get_unit_size), (gst_agingtv_transform),
(gst_agingtv_base_init), (gst_agingtv_class_init),
(gst_agingtv_init), (gst_agingtv_get_type):
* gst/effectv/gstdice.c: (gst_dicetv_set_caps),
(gst_dicetv_get_unit_size), (gst_dicetv_transform),
(gst_dicetv_base_init), (gst_dicetv_class_init),
(gst_dicetv_init),
(gst_dicetv_get_type):
* gst/effectv/gstedge.c: (gst_edgetv_set_caps),
(gst_edgetv_get_unit_size), (gst_edgetv_transform),
(gst_edgetv_base_init), (gst_edgetv_class_init),
(gst_edgetv_init),
(gst_edgetv_get_type):
* gst/effectv/gsteffectv.c:
* gst/effectv/gsteffectv.h:
* gst/effectv/gstquark.c: (gst_quarktv_set_caps),
(gst_quarktv_get_unit_size), (fastrand),
(gst_quarktv_transform),
(gst_quarktv_change_state), (gst_quarktv_base_init),
(gst_quarktv_class_init), (gst_quarktv_init),
(gst_quarktv_get_type):
* gst/effectv/gstrev.c: (gst_revtv_set_caps),
(gst_revtv_get_unit_size), (gst_revtv_transform),
(gst_revtv_base_init), (gst_revtv_class_init), (gst_revtv_init),
(gst_revtv_get_type):
* gst/effectv/gstshagadelic.c: (gst_shagadelictv_set_caps),
(gst_shagadelictv_get_unit_size), (gst_shagadelictv_transform),
(gst_shagadelictv_base_init), (gst_shagadelictv_class_init),
(gst_shagadelictv_init), (gst_shagadelictv_get_type):
* gst/effectv/gstvertigo.c: (gst_vertigotv_set_caps),
(gst_vertigotv_get_unit_size), (gst_vertigotv_transform),
(gst_vertigotv_base_init), (gst_vertigotv_class_init),
(gst_vertigotv_init), (gst_vertigotv_get_type):
* gst/effectv/gstwarp.c: (gst_warptv_set_caps),
(gst_warptv_get_unit_size), (gst_warptv_transform),
(gst_warptv_base_init), (gst_warptv_class_init),
(gst_warptv_init),
(gst_warptv_get_type):
* gst/videofilter/Makefile.am:
* gst/videofilter/gstvideobalance.c:
* gst/videofilter/gstvideobalance.h:
* gst/videofilter/gstvideofilter.c: (gst_videofilter_get_type),
(gst_videofilter_class_init), (gst_videofilter_init):
* gst/videofilter/gstvideofilter.h:
* gst/videofilter/gstvideoflip.c: (gst_videoflip_set_caps),
(gst_videoflip_transform_caps), (gst_videoflip_get_unit_size),
(gst_videoflip_flip), (gst_videoflip_transform),
(gst_videoflip_handle_src_event), (gst_videoflip_set_property),
(gst_videoflip_base_init), (gst_videoflip_class_init),
(gst_videoflip_init), (plugin_init), (gst_videoflip_get_type):
* gst/videofilter/gstvideoflip.h: VideoFilter inherits from
BaseTransform, it's just a place holder for now and every video
effect plugin has been ported to use BaseTransform features
directly. QuarkTV was fixed too (was broken), navigationtest
works
and best for the end, videoflip converts navigation events
depending
on flip method ! Fixes #320953
2005-11-23 15:50:51 +00:00

551 lines
15 KiB
C

/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2003> David Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* This file was (probably) generated from gstvideobalance.c,
* gstvideobalance.c,v 1.7 2003/11/08 02:48:59 dschleef Exp
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstvideobalance.h"
#ifdef HAVE_LIBOIL
#include <liboil/liboil.h>
#endif
#include <string.h>
#include <math.h>
#include <gst/colorbalance/colorbalance.h>
/* GstVideobalance signals and args */
enum
{
ARG_0,
ARG_CONTRAST,
ARG_BRIGHTNESS,
ARG_HUE,
ARG_SATURATION
/* FILL ME */
};
static GstVideofilterClass *parent_class = NULL;
static void gst_videobalance_base_init (gpointer g_class);
static void gst_videobalance_class_init (gpointer g_class, gpointer class_data);
static void gst_videobalance_init (GTypeInstance * instance, gpointer g_class);
static void gst_videobalance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_videobalance_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_videobalance_planar411 (GstVideofilter * videofilter,
void *dest, void *src);
static void gst_videobalance_setup (GstVideofilter * videofilter);
static void gst_videobalance_interface_init (GstImplementsInterfaceClass *
klass);
static void gst_videobalance_colorbalance_init (GstColorBalanceClass * iface);
static void gst_videobalance_dispose (GObject * object);
static void gst_videobalance_update_properties (GstVideobalance * videobalance);
GType
gst_videobalance_get_type (void)
{
static GType videobalance_type = 0;
if (!videobalance_type) {
static const GTypeInfo videobalance_info = {
sizeof (GstVideobalanceClass),
gst_videobalance_base_init,
NULL,
gst_videobalance_class_init,
NULL,
NULL,
sizeof (GstVideobalance),
0,
gst_videobalance_init,
};
static const GInterfaceInfo iface_info = {
(GInterfaceInitFunc) gst_videobalance_interface_init,
NULL,
NULL,
};
static const GInterfaceInfo colorbalance_info = {
(GInterfaceInitFunc) gst_videobalance_colorbalance_init,
NULL,
NULL,
};
videobalance_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
"GstVideobalance", &videobalance_info, 0);
g_type_add_interface_static (videobalance_type,
GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
g_type_add_interface_static (videobalance_type, GST_TYPE_COLOR_BALANCE,
&colorbalance_info);
}
return videobalance_type;
}
static void
gst_videobalance_base_init (gpointer g_class)
{
static GstElementDetails videobalance_details =
GST_ELEMENT_DETAILS ("Video Balance Control",
"Filter/Effect/Video",
"Adjusts brightness, contrast, hue, saturation on a video stream",
"David Schleef <ds@schleef.org>");
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
int i;
gst_element_class_set_details (element_class, &videobalance_details);
for (i = 0; i < G_N_ELEMENTS (gst_videobalance_formats); i++) {
gst_videofilter_class_add_format (videofilter_class,
gst_videobalance_formats + i);
}
gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
}
static void
gst_videobalance_dispose (GObject * object)
{
GList *channels = NULL;
GstVideobalance *balance;
gint i;
balance = GST_VIDEOBALANCE (object);
if (balance->tableu) {
for (i = 0; i < 256; i++)
g_free (balance->tableu[i]);
g_free (balance->tableu);
balance->tableu = NULL;
}
if (balance->tablev) {
for (i = 0; i < 256; i++)
g_free (balance->tablev[i]);
g_free (balance->tablev);
balance->tablev = NULL;
}
if (balance->tabley) {
g_free (balance->tabley);
balance->tabley = NULL;
}
channels = balance->channels;
while (channels) {
GstColorBalanceChannel *channel = channels->data;
g_object_unref (channel);
channels->data = NULL;
channels = g_list_next (channels);
}
if (balance->channels)
g_list_free (balance->channels);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_videobalance_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstVideofilterClass *videofilter_class;
gobject_class = G_OBJECT_CLASS (g_class);
videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
parent_class = g_type_class_ref (GST_TYPE_VIDEOFILTER);
gobject_class->set_property = gst_videobalance_set_property;
gobject_class->get_property = gst_videobalance_get_property;
g_object_class_install_property (gobject_class, ARG_CONTRAST,
g_param_spec_double ("contrast", "Contrast", "contrast",
0, 2, 1, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_BRIGHTNESS,
g_param_spec_double ("brightness", "Brightness", "brightness",
-1, 1, 0, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_HUE,
g_param_spec_double ("hue", "Hue", "hue", -1, 1, 0, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_SATURATION,
g_param_spec_double ("saturation", "Saturation", "saturation",
0, 2, 1, G_PARAM_READWRITE));
gobject_class->dispose = gst_videobalance_dispose;
videofilter_class->setup = gst_videobalance_setup;
#ifdef HAVE_LIBOIL
oil_init ();
#endif
}
static void
gst_videobalance_init (GTypeInstance * instance, gpointer g_class)
{
GstVideobalance *videobalance = GST_VIDEOBALANCE (instance);
GstVideofilter *videofilter;
char *channels[4] = { "HUE", "SATURATION",
"BRIGHTNESS", "CONTRAST"
};
gint i;
GST_DEBUG ("gst_videobalance_init");
videofilter = GST_VIDEOFILTER (videobalance);
/* do stuff */
videobalance->contrast = 1.0;
videobalance->brightness = 0.0;
videobalance->saturation = 1.0;
videobalance->hue = 0.0;
videobalance->needupdate = FALSE;
videofilter->passthru = TRUE;
videobalance->tabley = g_new (guint8, 256);
videobalance->tableu = g_new (guint8 *, 256);
videobalance->tablev = g_new (guint8 *, 256);
for (i = 0; i < 256; i++) {
videobalance->tableu[i] = g_new (guint8, 256);
videobalance->tablev[i] = g_new (guint8, 256);
}
/* Generate the channels list */
for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
GstColorBalanceChannel *channel;
channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
channel->label = g_strdup (channels[i]);
channel->min_value = -1000;
channel->max_value = 1000;
videobalance->channels = g_list_append (videobalance->channels, channel);
}
}
static gboolean
gst_videobalance_interface_supported (GstImplementsInterface * iface,
GType type)
{
g_assert (type == GST_TYPE_COLOR_BALANCE);
return TRUE;
}
static void
gst_videobalance_interface_init (GstImplementsInterfaceClass * klass)
{
klass->supported = gst_videobalance_interface_supported;
}
static const GList *
gst_videobalance_colorbalance_list_channels (GstColorBalance * balance)
{
GstVideobalance *videobalance = GST_VIDEOBALANCE (balance);
g_return_val_if_fail (videobalance != NULL, NULL);
g_return_val_if_fail (GST_IS_VIDEOBALANCE (videobalance), NULL);
return videobalance->channels;
}
static void
gst_videobalance_colorbalance_set_value (GstColorBalance * balance,
GstColorBalanceChannel * channel, gint value)
{
GstVideobalance *vb = GST_VIDEOBALANCE (balance);
g_return_if_fail (vb != NULL);
g_return_if_fail (GST_IS_VIDEOBALANCE (vb));
g_return_if_fail (GST_IS_VIDEOFILTER (vb));
g_return_if_fail (channel->label != NULL);
if (!g_ascii_strcasecmp (channel->label, "HUE")) {
vb->hue = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
} else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
vb->saturation = (value + 1000.0) * 2.0 / 2000.0;
} else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
vb->brightness = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
} else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
vb->contrast = (value + 1000.0) * 2.0 / 2000.0;
}
gst_videobalance_update_properties (vb);
}
static gint
gst_videobalance_colorbalance_get_value (GstColorBalance * balance,
GstColorBalanceChannel * channel)
{
GstVideobalance *vb = GST_VIDEOBALANCE (balance);
gint value = 0;
g_return_val_if_fail (vb != NULL, 0);
g_return_val_if_fail (GST_IS_VIDEOBALANCE (vb), 0);
g_return_val_if_fail (channel->label != NULL, 0);
if (!g_ascii_strcasecmp (channel->label, "HUE")) {
value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
value = vb->saturation * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
value = vb->contrast * 2000.0 / 2.0 - 1000.0;
}
return value;
}
static void
gst_videobalance_colorbalance_init (GstColorBalanceClass * iface)
{
GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE;
iface->list_channels = gst_videobalance_colorbalance_list_channels;
iface->set_value = gst_videobalance_colorbalance_set_value;
iface->get_value = gst_videobalance_colorbalance_get_value;
}
static void
gst_videobalance_update_properties (GstVideobalance * videobalance)
{
GstVideofilter *vf = GST_VIDEOFILTER (videobalance);
videobalance->needupdate = TRUE;
if (videobalance->contrast == 1.0 &&
videobalance->brightness == 0.0 &&
videobalance->hue == 0.0 && videobalance->saturation == 1.0) {
vf->passthru = TRUE;
} else {
vf->passthru = FALSE;
}
}
static void
gst_videobalance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstVideobalance *src;
g_return_if_fail (GST_IS_VIDEOBALANCE (object));
src = GST_VIDEOBALANCE (object);
GST_DEBUG ("gst_videobalance_set_property");
switch (prop_id) {
case ARG_CONTRAST:
src->contrast = g_value_get_double (value);
break;
case ARG_BRIGHTNESS:
src->brightness = g_value_get_double (value);
break;
case ARG_HUE:
src->hue = g_value_get_double (value);
break;
case ARG_SATURATION:
src->saturation = g_value_get_double (value);
break;
default:
break;
}
gst_videobalance_update_properties (src);
}
static void
gst_videobalance_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstVideobalance *src;
g_return_if_fail (GST_IS_VIDEOBALANCE (object));
src = GST_VIDEOBALANCE (object);
switch (prop_id) {
case ARG_CONTRAST:
g_value_set_double (value, src->contrast);
break;
case ARG_BRIGHTNESS:
g_value_set_double (value, src->brightness);
break;
case ARG_HUE:
g_value_set_double (value, src->hue);
break;
case ARG_SATURATION:
g_value_set_double (value, src->saturation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_library_load ("gstvideofilter"))
return FALSE;
return gst_element_register (plugin, "videobalance", GST_RANK_NONE,
GST_TYPE_VIDEOBALANCE);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"videobalance",
"Changes hue, saturation, brightness etc. on video images",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
static void
gst_videobalance_setup (GstVideofilter * videofilter)
{
GstVideobalance *videobalance;
g_return_if_fail (GST_IS_VIDEOBALANCE (videofilter));
videobalance = GST_VIDEOBALANCE (videofilter);
/* if any setup needs to be done, do it here */
}
/*
* look-up tables (LUT).
*/
static void
gst_videobalance_update_tables_planar411 (GstVideobalance * vb)
{
gint i, j;
gdouble y, u, v, hue_cos, hue_sin;
/* Y */
for (i = 0; i < 256; i++) {
y = 16 + ((i - 16) * vb->contrast + vb->brightness * 255);
if (y < 0)
y = 0;
else if (y > 255)
y = 255;
vb->tabley[i] = rint (y);
}
/* FIXME this is a bogus transformation for hue, but you get
* the idea */
hue_cos = cos (M_PI * vb->hue);
hue_sin = sin (M_PI * vb->hue);
/* U/V lookup tables are 2D, since we need both U/V for each table
* separately. */
for (i = -128; i < 128; i++) {
for (j = -128; j < 128; j++) {
u = 128 + ((i * hue_cos + j * hue_sin) * vb->saturation);
v = 128 + ((-i * hue_sin + j * hue_cos) * vb->saturation);
if (u < 0)
u = 0;
else if (u > 255)
u = 255;
if (v < 0)
v = 0;
else if (v > 255)
v = 255;
vb->tableu[i + 128][j + 128] = rint (u);
vb->tablev[i + 128][j + 128] = rint (v);
}
}
}
#ifndef HAVE_LIBOIL
void
oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
guint8 * table, int tstr, int n)
{
int i;
for (i = 0; i < n; i++) {
*dest = table[*src * tstr];
dest += dstr;
src += sstr;
}
}
#endif
static void
gst_videobalance_planar411 (GstVideofilter * videofilter, void *dest, void *src)
{
GstVideobalance *videobalance;
int width;
int height;
int x, y;
g_return_if_fail (GST_IS_VIDEOBALANCE (videofilter));
videobalance = GST_VIDEOBALANCE (videofilter);
if (videobalance->needupdate) {
gst_videobalance_update_tables_planar411 (videobalance);
videobalance->needupdate = FALSE;
}
width = videofilter->from_width;
height = videofilter->from_height;
{
guint8 *cdest = dest;
guint8 *csrc = src;
for (y = 0; y < height; y++) {
oil_tablelookup_u8 (cdest + y * width, 1, csrc + y * width, 1,
videobalance->tabley, 1, width);
}
}
{
gint u1, v1;
guint8 *usrc, *vsrc;
guint8 *udest, *vdest;
usrc = src + width * height;
udest = dest + width * height;
vsrc = src + width * height + (width / 2) * (height / 2);
vdest = dest + width * height + (width / 2) * (height / 2);
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
u1 = usrc[y * (width / 2) + x];
v1 = vsrc[y * (width / 2) + x];
udest[y * (width / 2) + x] = videobalance->tableu[u1][v1];
vdest[y * (width / 2) + x] = videobalance->tablev[u1][v1];
}
}
}
}