gl: implement a colorbalance element

It performs the exact same operation as videobalance but with opengl shaders and
was tested with glvideomixer by comparing frames from videobalance and
glcolorbalance.
This commit is contained in:
Matthew Waters 2016-01-12 18:31:29 +11:00 committed by Tim-Philipp Müller
parent 1d55ce912b
commit 731f9928dd
4 changed files with 624 additions and 0 deletions

View file

@ -32,6 +32,7 @@ libgstopengl_la_SOURCES = \
effects/gstgleffectsobel.c \
effects/gstgleffectlaplacian.c \
gstglcolorscale.c \
gstglcolorbalance.c \
gstglmixer.c \
gstglvideomixer.c \
gstglfiltershader.c \
@ -54,6 +55,7 @@ noinst_HEADERS = \
gstgleffects.h \
effects/gstgleffectssources.h \
gstglcolorscale.h \
gstglcolorbalance.h \
gstglmixer.h \
gstglvideomixer.h \
gstglfiltershader.h \

543
ext/gl/gstglcolorbalance.c Normal file
View file

@ -0,0 +1,543 @@
/* GStreamer
* Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
*
* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* This file was modified from videobalance and converted to OpenGL
*/
/**
* SECTION:element-glcolorbalance
*
* Adjusts brightness, contrast, hue, saturation on a video stream.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch-1.0 videotestsrc ! glupload ! glcolorbalance saturation=0.0 ! glcolorconvert ! gldownload ! ximagesink
* ]| This pipeline converts the image to black and white by setting the
* saturation to 0.0.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/math-compat.h>
#include "gstglcolorbalance.h"
#include <string.h>
#include <gst/video/colorbalance.h>
GST_DEBUG_CATEGORY_STATIC (glcolorbalance_debug);
#define GST_CAT_DEFAULT glcolorbalance_debug
/* GstGLColorBalance properties */
#define DEFAULT_PROP_CONTRAST 1.0
#define DEFAULT_PROP_BRIGHTNESS 0.0
#define DEFAULT_PROP_HUE 0.0
#define DEFAULT_PROP_SATURATION 1.0
/* *INDENT-OFF* */
static const gchar *color_balance_frag =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform float brightness;\n"
"uniform float contrast;\n"
"uniform float saturation;\n"
"uniform float hue;\n"
"varying vec2 v_texcoord;\n"
"uniform sampler2D tex;\n"
"#define from_yuv_bt601_offset vec3(-0.0625, -0.5, -0.5)\n"
"#define from_yuv_bt601_rcoeff vec3(1.164, 0.000, 1.596)\n"
"#define from_yuv_bt601_gcoeff vec3(1.164,-0.391,-0.813)\n"
"#define from_yuv_bt601_bcoeff vec3(1.164, 2.018, 0.000)\n"
"#define from_rgb_bt601_offset vec3(0.0625, 0.5, 0.5)\n"
"#define from_rgb_bt601_ycoeff vec3(0.256816, 0.504154, 0.0979137)\n"
"#define from_rgb_bt601_ucoeff vec3(-0.148246, -0.29102, 0.439266)\n"
"#define from_rgb_bt601_vcoeff vec3(0.439271, -0.367833, -0.071438)\n"
"#define PI 3.14159265\n"
"\n"
"vec3 yuv_to_rgb (vec3 val) {\n"
" vec3 rgb;\n"
" val += from_yuv_bt601_offset;\n"
" rgb.r = dot(val, from_yuv_bt601_rcoeff);\n"
" rgb.g = dot(val, from_yuv_bt601_gcoeff);\n"
" rgb.b = dot(val, from_yuv_bt601_bcoeff);\n"
" return rgb;\n"
"}\n"
"vec3 rgb_to_yuv (vec3 val) {\n"
" vec3 yuv;\n"
" yuv.r = dot(val.rgb, from_rgb_bt601_ycoeff);\n"
" yuv.g = dot(val.rgb, from_rgb_bt601_ucoeff);\n"
" yuv.b = dot(val.rgb, from_rgb_bt601_vcoeff);\n"
" yuv += from_rgb_bt601_offset;\n"
" return yuv;\n"
"}\n"
/* 224 = 256 - (256 - 240) - 16*/
"float luma_to_narrow (float luma) {\n"
" return (luma + 16.0 / 256.0) * 219.0 / 256.0;"
"}\n"
"float luma_to_full (float luma) {\n"
" return (luma * 256.0 / 219.0) - 16.0 / 256.0;"
"}\n"
"void main () {\n"
" vec3 yuv;\n"
/* operations translated from videobalanceand tested with glvideomixer
* with one pad's paremeters blend-equation-rgb={subtract,reverse-subtract},
* blend-function-src-rgb=src-color and blend-function-dst-rgb=dst-color */
" float hue_cos = cos (PI * hue);\n"
" float hue_sin = sin (PI * hue);\n"
" vec4 rgba = texture2D (tex, v_texcoord);\n"
" yuv = rgb_to_yuv (rgba.rgb);\n"
" yuv.x = clamp (luma_to_narrow (luma_to_full(yuv.x) * contrast) + brightness, 0.0, 1.0);\n"
" vec2 uv = yuv.yz;\n"
" yuv.y = clamp (0.5 + (((uv.x - 0.5) * hue_cos + (uv.y - 0.5) * hue_sin) * saturation), 0.0, 1.0);\n"
" yuv.z = clamp (0.5 + (((0.5 - uv.x) * hue_sin + (uv.y - 0.5) * hue_cos) * saturation), 0.0, 1.0);\n"
" rgba.rgb = yuv_to_rgb (yuv);\n"
" gl_FragColor = rgba;\n"
"}\n";
/* *INDENT-ON* */
enum
{
PROP_0,
PROP_CONTRAST,
PROP_BRIGHTNESS,
PROP_HUE,
PROP_SATURATION
};
static void gst_gl_color_balance_colorbalance_init (GstColorBalanceInterface *
iface);
static void gst_gl_color_balance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_color_balance_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
#define gst_gl_color_balance_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLColorBalance, gst_gl_color_balance,
GST_TYPE_GL_FILTER,
G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
gst_gl_color_balance_colorbalance_init));
static gboolean
gst_gl_color_balance_is_passthrough (GstGLColorBalance * glcolorbalance)
{
return glcolorbalance->contrast == 1.0 &&
glcolorbalance->brightness == 0.0 &&
glcolorbalance->hue == 0.0 && glcolorbalance->saturation == 1.0;
}
static void
gst_gl_color_balance_update_properties (GstGLColorBalance * glcolorbalance)
{
gboolean passthrough;
GstBaseTransform *base = GST_BASE_TRANSFORM (glcolorbalance);
GST_OBJECT_LOCK (glcolorbalance);
passthrough = gst_gl_color_balance_is_passthrough (glcolorbalance);
GST_OBJECT_UNLOCK (glcolorbalance);
gst_base_transform_set_passthrough (base, passthrough);
}
static gboolean
gst_gl_color_balance_gl_start (GstGLBaseFilter * base_filter)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base_filter);
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GError *error = NULL;
if (balance->shader)
gst_object_unref (balance->shader);
if (!(balance->shader =
gst_gl_shader_new_link_with_stages (base_filter->context, &error,
gst_glsl_stage_new_default_vertex (base_filter->context),
gst_glsl_stage_new_with_string (base_filter->context,
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
color_balance_frag), NULL))) {
GST_ELEMENT_ERROR (balance, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize colorbalance shader"), ("%s",
error ? error->message : "Unknown error"));
return FALSE;
}
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (balance->shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (balance->shader, "a_texcoord");
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
static void
gst_gl_color_balance_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base_filter);
if (balance->shader)
gst_object_unref (balance->shader);
balance->shader = NULL;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static void
gst_gl_color_balance_before_transform (GstBaseTransform * base, GstBuffer * buf)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base);
GstClockTime timestamp, stream_time;
timestamp = GST_BUFFER_TIMESTAMP (buf);
stream_time =
gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
GST_DEBUG_OBJECT (balance, "sync to %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
if (GST_CLOCK_TIME_IS_VALID (stream_time))
gst_object_sync_values (GST_OBJECT (balance), stream_time);
}
static void
gst_gl_color_balance_callback (gint width, gint height, guint tex_id,
gpointer data)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (data);
GstGLFilter *filter = GST_GL_FILTER (data);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (data)->context->gl_vtable;
gst_gl_shader_use (balance->shader);
GST_OBJECT_LOCK (balance);
gst_gl_shader_set_uniform_1f (balance->shader, "brightness",
balance->brightness);
gst_gl_shader_set_uniform_1f (balance->shader, "contrast", balance->contrast);
gst_gl_shader_set_uniform_1f (balance->shader, "saturation",
balance->saturation);
gst_gl_shader_set_uniform_1f (balance->shader, "hue", balance->hue);
GST_OBJECT_UNLOCK (balance);
gl->BindTexture (GL_TEXTURE_2D, tex_id);
gst_gl_filter_draw_texture (filter, tex_id, width, height);
}
static gboolean
gst_gl_color_balance_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
(GLCB) gst_gl_color_balance_callback, filter);
return TRUE;
}
static void
gst_gl_color_balance_finalize (GObject * object)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
GList *channels = 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)->finalize (object);
}
static void
gst_gl_color_balance_class_init (GstGLColorBalanceClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
GstGLBaseFilterClass *base_filter_class = (GstGLBaseFilterClass *) klass;
GstGLFilterClass *filter_class = (GstGLFilterClass *) klass;
GST_DEBUG_CATEGORY_INIT (glcolorbalance_debug, "glcolorbalance", 0,
"glcolorbalance");
gobject_class->finalize = gst_gl_color_balance_finalize;
gobject_class->set_property = gst_gl_color_balance_set_property;
gobject_class->get_property = gst_gl_color_balance_get_property;
g_object_class_install_property (gobject_class, PROP_CONTRAST,
g_param_spec_double ("contrast", "Contrast", "contrast",
0.0, 2.0, DEFAULT_PROP_CONTRAST,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0,
DEFAULT_PROP_BRIGHTNESS,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HUE,
g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_PROP_HUE,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SATURATION,
g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0,
DEFAULT_PROP_SATURATION,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class, "Video balance",
"Filter/Effect/Video",
"Adjusts brightness, contrast, hue, saturation on a video stream",
"Matthew Waters <matthew@centricular.com>");
trans_class->before_transform =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_before_transform);
trans_class->transform_ip_on_passthrough = FALSE;
base_filter_class->gl_start =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_gl_start);
base_filter_class->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_color_balance_gl_stop);
filter_class->filter_texture =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_filter_texture);
}
static void
gst_gl_color_balance_init (GstGLColorBalance * glcolorbalance)
{
const gchar *channels[4] = { "HUE", "SATURATION",
"BRIGHTNESS", "CONTRAST"
};
gint i;
/* Initialize propertiews */
glcolorbalance->contrast = DEFAULT_PROP_CONTRAST;
glcolorbalance->brightness = DEFAULT_PROP_BRIGHTNESS;
glcolorbalance->hue = DEFAULT_PROP_HUE;
glcolorbalance->saturation = DEFAULT_PROP_SATURATION;
gst_gl_color_balance_update_properties (glcolorbalance);
/* Generate the channels list */
for (i = 0; i < G_N_ELEMENTS (channels); 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;
glcolorbalance->channels =
g_list_append (glcolorbalance->channels, channel);
}
}
static const GList *
gst_gl_color_balance_colorbalance_list_channels (GstColorBalance * balance)
{
GstGLColorBalance *glcolorbalance = GST_GL_COLOR_BALANCE (balance);
g_return_val_if_fail (glcolorbalance != NULL, NULL);
g_return_val_if_fail (GST_IS_GL_COLOR_BALANCE (glcolorbalance), NULL);
return glcolorbalance->channels;
}
static void
gst_gl_color_balance_colorbalance_set_value (GstColorBalance * balance,
GstColorBalanceChannel * channel, gint value)
{
GstGLColorBalance *vb = GST_GL_COLOR_BALANCE (balance);
gdouble new_val;
gboolean changed = FALSE;
g_return_if_fail (vb != NULL);
g_return_if_fail (GST_IS_GL_COLOR_BALANCE (vb));
g_return_if_fail (channel->label != NULL);
GST_OBJECT_LOCK (vb);
if (!g_ascii_strcasecmp (channel->label, "HUE")) {
new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
changed = new_val != vb->hue;
vb->hue = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
new_val = (value + 1000.0) * 2.0 / 2000.0;
changed = new_val != vb->saturation;
vb->saturation = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
changed = new_val != vb->brightness;
vb->brightness = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
new_val = (value + 1000.0) * 2.0 / 2000.0;
changed = new_val != vb->contrast;
vb->contrast = new_val;
}
GST_OBJECT_UNLOCK (vb);
if (changed)
gst_gl_color_balance_update_properties (vb);
if (changed) {
gst_color_balance_value_changed (balance, channel,
gst_color_balance_get_value (balance, channel));
}
}
static gint
gst_gl_color_balance_colorbalance_get_value (GstColorBalance * balance,
GstColorBalanceChannel * channel)
{
GstGLColorBalance *vb = GST_GL_COLOR_BALANCE (balance);
gint value = 0;
g_return_val_if_fail (vb != NULL, 0);
g_return_val_if_fail (GST_IS_GL_COLOR_BALANCE (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 GstColorBalanceType
gst_gl_color_balance_colorbalance_get_balance_type (GstColorBalance * balance)
{
return GST_COLOR_BALANCE_SOFTWARE;
}
static void
gst_gl_color_balance_colorbalance_init (GstColorBalanceInterface * iface)
{
iface->list_channels = gst_gl_color_balance_colorbalance_list_channels;
iface->set_value = gst_gl_color_balance_colorbalance_set_value;
iface->get_value = gst_gl_color_balance_colorbalance_get_value;
iface->get_balance_type = gst_gl_color_balance_colorbalance_get_balance_type;
}
static GstColorBalanceChannel *
gst_gl_color_balance_find_channel (GstGLColorBalance * balance,
const gchar * label)
{
GList *l;
for (l = balance->channels; l; l = l->next) {
GstColorBalanceChannel *channel = l->data;
if (g_ascii_strcasecmp (channel->label, label) == 0)
return channel;
}
return NULL;
}
static void
gst_gl_color_balance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
gdouble d;
const gchar *label = NULL;
GST_OBJECT_LOCK (balance);
switch (prop_id) {
case PROP_CONTRAST:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing contrast from %lf to %lf",
balance->contrast, d);
if (d != balance->contrast)
label = "CONTRAST";
balance->contrast = d;
break;
case PROP_BRIGHTNESS:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing brightness from %lf to %lf",
balance->brightness, d);
if (d != balance->brightness)
label = "BRIGHTNESS";
balance->brightness = d;
break;
case PROP_HUE:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing hue from %lf to %lf", balance->hue,
d);
if (d != balance->hue)
label = "HUE";
balance->hue = d;
break;
case PROP_SATURATION:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing saturation from %lf to %lf",
balance->saturation, d);
if (d != balance->saturation)
label = "SATURATION";
balance->saturation = d;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (balance);
gst_gl_color_balance_update_properties (balance);
if (label) {
GstColorBalanceChannel *channel =
gst_gl_color_balance_find_channel (balance, label);
gst_color_balance_value_changed (GST_COLOR_BALANCE (balance), channel,
gst_color_balance_get_value (GST_COLOR_BALANCE (balance), channel));
}
}
static void
gst_gl_color_balance_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
switch (prop_id) {
case PROP_CONTRAST:
g_value_set_double (value, balance->contrast);
break;
case PROP_BRIGHTNESS:
g_value_set_double (value, balance->brightness);
break;
case PROP_HUE:
g_value_set_double (value, balance->hue);
break;
case PROP_SATURATION:
g_value_set_double (value, balance->saturation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -0,0 +1,73 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_COLOR_BALANCE_H__
#define __GST_GL_COLOR_BALANCE_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_COLOR_BALANCE \
(gst_gl_color_balance_get_type())
#define GST_GL_COLOR_BALANCE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLOR_BALANCE,GstGLColorBalance))
#define GST_GL_COLOR_BALANCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_COLOR_BALANCE,GstGLColorBalanceClass))
#define GST_IS_GL_COLOR_BALANCE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLOR_BALANCE))
#define GST_IS_GL_COLOR_BALANCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_COLOR_BALANCE))
typedef struct _GstGLColorBalance GstGLColorBalance;
typedef struct _GstGLColorBalanceClass GstGLColorBalanceClass;
/**
* GstGLColorBalance:
*
* Opaque data structure.
*/
struct _GstGLColorBalance {
GstGLFilter videofilter;
/* < private > */
GstGLShader *shader;
/* channels for interface */
GList *channels;
/* properties */
gdouble contrast;
gdouble brightness;
gdouble hue;
gdouble saturation;
};
struct _GstGLColorBalanceClass {
GstGLFilterClass parent_class;
};
GType gst_gl_color_balance_get_type(void);
G_END_DECLS
#endif /* __GST_GL_COLOR_BALANCE_H__ */

View file

@ -47,6 +47,7 @@
#include "gstgluploadelement.h"
#include "gstgldownloadelement.h"
#include "gstglcolorconvertelement.h"
#include "gstglcolorbalance.h"
#include "gstglfilterbin.h"
#include "gstglsinkbin.h"
#include "gstglsrcbin.h"
@ -140,6 +141,11 @@ plugin_init (GstPlugin * plugin)
return FALSE;
}
if (!gst_element_register (plugin, "glcolorbalance",
GST_RANK_NONE, GST_TYPE_GL_COLOR_BALANCE)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterbin",
GST_RANK_NONE, GST_TYPE_GL_FILTER_BIN)) {
return FALSE;