From b23977cb9357d5084e09d2f4af9b3b65db32824c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 21 Jan 2012 20:03:52 +0100 Subject: controller: allow different controlbindings Make controlbinding an abstract baseclass. Move implementation to control- binding-direct and add a control-binding-argb. Add an example. --- docs/gst/gstreamer-sections.txt | 2 - gst/gstcontrolbinding.c | 261 ++---------------- gst/gstcontrolbinding.h | 23 +- gst/gstobject.c | 6 +- libs/gst/controller/Makefile.am | 4 + libs/gst/controller/gstcontrolbindingargb.c | 315 ++++++++++++++++++++++ libs/gst/controller/gstcontrolbindingargb.h | 98 +++++++ libs/gst/controller/gstcontrolbindingdirect.c | 351 +++++++++++++++++++++++++ libs/gst/controller/gstcontrolbindingdirect.h | 106 ++++++++ tests/benchmarks/controller.c | 2 +- tests/check/gst/gstcontroller.c | 28 +- tests/check/libs/controller.c | 53 ++-- tests/examples/controller/.gitignore | 1 + tests/examples/controller/Makefile.am | 2 +- tests/examples/controller/audio-example.c | 5 +- tests/examples/controller/control-sources.c | 12 +- tests/examples/controller/text-color-example.c | 120 +++++++++ win32/common/libgstreamer.def | 2 - 18 files changed, 1082 insertions(+), 309 deletions(-) create mode 100644 libs/gst/controller/gstcontrolbindingargb.c create mode 100644 libs/gst/controller/gstcontrolbindingargb.h create mode 100644 libs/gst/controller/gstcontrolbindingdirect.c create mode 100644 libs/gst/controller/gstcontrolbindingdirect.h create mode 100644 tests/examples/controller/text-color-example.c diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 31587d61c..8fffedf1e 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -596,11 +596,9 @@ GST_USING_PRINTF_EXTENSION GstControlBinding GstControlBindingClass GstControlBindingConvert -gst_control_binding_new gst_control_binding_sync_values gst_control_binding_get_value gst_control_binding_get_value_array -gst_control_binding_get_control_source gst_control_binding_set_disabled gst_control_binding_is_disabled diff --git a/gst/gstcontrolbinding.c b/gst/gstcontrolbinding.c index f8ed007be..2d2e44073 100644 --- a/gst/gstcontrolbinding.c +++ b/gst/gstcontrolbinding.c @@ -38,23 +38,16 @@ #define GST_CAT_DEFAULT control_binding_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); -static void gst_control_binding_dispose (GObject * object); -static void gst_control_binding_finalize (GObject * object); - #define _do_init \ GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbinding", 0, \ "dynamic parameter control source attachment"); -G_DEFINE_TYPE_WITH_CODE (GstControlBinding, gst_control_binding, +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstControlBinding, gst_control_binding, GST_TYPE_OBJECT, _do_init); static void gst_control_binding_class_init (GstControlBindingClass * klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gst_control_binding_dispose; - gobject_class->finalize = gst_control_binding_finalize; } static void @@ -62,162 +55,6 @@ gst_control_binding_init (GstControlBinding * self) { } -static void -gst_control_binding_dispose (GObject * object) -{ - GstControlBinding *self = GST_CONTROL_BINDING (object); - - if (self->csource) { - g_object_unref (self->csource); - self->csource = NULL; - } -} - -static void -gst_control_binding_finalize (GObject * object) -{ - GstControlBinding *self = GST_CONTROL_BINDING (object); - - g_value_unset (&self->cur_value); -} - -/* mapping functions */ -#define DEFINE_CONVERT(type,Type,TYPE) \ -static void \ -convert_to_##type (GstControlBinding *self, gdouble s, GValue *d) \ -{ \ - GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (self->pspec); \ - g##type v; \ - \ - s = CLAMP (s, 0.0, 1.0); \ - v = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \ - g_value_set_##type (d, v); \ -} - -DEFINE_CONVERT (int, Int, INT); -DEFINE_CONVERT (uint, UInt, UINT); -DEFINE_CONVERT (long, Long, LONG); -DEFINE_CONVERT (ulong, ULong, ULONG); -DEFINE_CONVERT (int64, Int64, INT64); -DEFINE_CONVERT (uint64, UInt64, UINT64); -DEFINE_CONVERT (float, Float, FLOAT); -DEFINE_CONVERT (double, Double, DOUBLE); - -static void -convert_to_boolean (GstControlBinding * self, gdouble s, GValue * d) -{ - s = CLAMP (s, 0.0, 1.0); - g_value_set_boolean (d, (gboolean) (s + 0.5)); -} - -static void -convert_to_enum (GstControlBinding * self, gdouble s, GValue * d) -{ - GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (self->pspec); - GEnumClass *e = pspec->enum_class; - gint v; - - s = CLAMP (s, 0.0, 1.0); - v = s * (e->n_values - 1); - g_value_set_enum (d, e->values[v].value); -} - -/** - * gst_control_binding_new: - * @object: the object of the property - * @property_name: the property-name to attach the control source - * @csource: the control source - * - * Create a new control-binding that attaches the #GstControlSource to the - * #GObject property. - * - * Returns: the new #GstControlBinding - */ -GstControlBinding * -gst_control_binding_new (GstObject * object, const gchar * property_name, - GstControlSource * csource) -{ - GstControlBinding *self = NULL; - GParamSpec *pspec; - - GST_INFO_OBJECT (object, "trying to put property '%s' under control", - property_name); - - /* check if the object has a property of that name */ - if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), - property_name))) { - GST_DEBUG_OBJECT (object, " psec->flags : 0x%08x", pspec->flags); - - /* check if this param is witable && controlable && !construct-only */ - g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE | - GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) == - (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL); - - if ((self = (GstControlBinding *) g_object_newv (GST_TYPE_CONTROL_BINDING, - 0, NULL))) { - GType type = G_PARAM_SPEC_VALUE_TYPE (pspec), base; - - // add pspec as a construction parameter and move below to construct() - self->pspec = pspec; - self->name = pspec->name; - self->csource = g_object_ref (csource); - self->disabled = FALSE; - - g_value_init (&self->cur_value, type); - - base = type = G_PARAM_SPEC_VALUE_TYPE (pspec); - while ((type = g_type_parent (type))) - base = type; - - GST_DEBUG_OBJECT (object, " using type %s", g_type_name (base)); - - // select mapping function - // FIXME: only select mapping if super class hasn't set any? - switch (base) { - case G_TYPE_INT: - self->convert = convert_to_int; - break; - case G_TYPE_UINT: - self->convert = convert_to_uint; - break; - case G_TYPE_LONG: - self->convert = convert_to_long; - break; - case G_TYPE_ULONG: - self->convert = convert_to_ulong; - break; - case G_TYPE_INT64: - self->convert = convert_to_int64; - break; - case G_TYPE_UINT64: - self->convert = convert_to_uint64; - break; - case G_TYPE_FLOAT: - self->convert = convert_to_float; - break; - case G_TYPE_DOUBLE: - self->convert = convert_to_double; - break; - case G_TYPE_BOOLEAN: - self->convert = convert_to_boolean; - break; - case G_TYPE_ENUM: - self->convert = convert_to_enum; - break; - default: - // FIXME: return NULL? - GST_WARNING ("incomplete implementation for paramspec type '%s'", - G_PARAM_SPEC_TYPE_NAME (pspec)); - break; - } - } - } else { - GST_WARNING_OBJECT (object, "class '%s' has no property '%s'", - G_OBJECT_TYPE_NAME (object), property_name); - } - return self; -} - /* functions */ /** @@ -240,41 +77,22 @@ gboolean gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync) { - GValue *dst_val; - gdouble src_val; - gboolean ret; + GstControlBindingClass *klass; + gboolean ret = FALSE; g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), FALSE); if (self->disabled) return TRUE; - GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT, - self->name, GST_TIME_ARGS (timestamp)); + klass = GST_CONTROL_BINDING_GET_CLASS (self); - dst_val = &self->cur_value; - ret = gst_control_source_get_value (self->csource, timestamp, &src_val); - if (G_LIKELY (ret)) { - GST_LOG_OBJECT (object, " new value %lf", src_val); - /* always set the value for first time, but then only if it changed - * this should limit g_object_notify invocations. - * FIXME: can we detect negative playback rates? - */ - if ((timestamp < last_sync) || (src_val != self->last_value)) { - GST_LOG_OBJECT (object, " mapping %s to value of type %s", self->name, - G_VALUE_TYPE_NAME (dst_val)); - /* run mapping function to convert gdouble to GValue */ - self->convert (self, src_val, dst_val); - /* we can make this faster - * http://bugzilla.gnome.org/show_bug.cgi?id=536939 - */ - g_object_set_property ((GObject *) object, self->name, dst_val); - self->last_value = src_val; - } + if (G_LIKELY (klass->sync_values != NULL)) { + ret = klass->sync_values (self, object, timestamp, last_sync); } else { - GST_DEBUG_OBJECT (object, "no control value for param %s", self->name); + GST_WARNING_OBJECT (self, "missing sync_values implementation"); } - return (ret); + return ret; } /** @@ -290,23 +108,20 @@ gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, GValue * gst_control_binding_get_value (GstControlBinding * self, GstClockTime timestamp) { - GValue *dst_val = NULL; - gdouble src_val; + GstControlBindingClass *klass; + GValue *ret = NULL; g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), NULL); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); - /* get current value via control source */ - if (gst_control_source_get_value (self->csource, timestamp, &src_val)) { - dst_val = g_new0 (GValue, 1); - g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (self->pspec)); - self->convert (self, src_val, dst_val); + klass = GST_CONTROL_BINDING_GET_CLASS (self); + + if (G_LIKELY (klass->get_value != NULL)) { + ret = klass->get_value (self, timestamp); } else { - GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT, - self->name, GST_TIME_ARGS (timestamp)); + GST_WARNING_OBJECT (self, "missing get_value implementation"); } - - return dst_val; + return ret; } /** @@ -331,52 +146,22 @@ gst_control_binding_get_value_array (GstControlBinding * self, GstClockTime timestamp, GstClockTime interval, guint n_values, GValue * values) { - gint i; - gdouble *src_val; - gboolean res = FALSE; - GType type; - GstControlBindingConvert convert; + GstControlBindingClass *klass; + gboolean ret = FALSE; g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); g_return_val_if_fail (values, FALSE); - convert = self->convert; - type = G_PARAM_SPEC_VALUE_TYPE (self->pspec); + klass = GST_CONTROL_BINDING_GET_CLASS (self); - src_val = g_new0 (gdouble, n_values); - if ((res = gst_control_source_get_value_array (self->csource, timestamp, - interval, n_values, src_val))) { - for (i = 0; i < n_values; i++) { - if (!isnan (src_val[i])) { - g_value_init (&values[i], type); - convert (self, src_val[i], &values[i]); - } else { - GST_LOG ("no control value for property %s at index %d", self->name, i); - } - } + if (G_LIKELY (klass->get_value_array != NULL)) { + ret = klass->get_value_array (self, timestamp, interval, n_values, values); } else { - GST_LOG ("failed to get control value for property %s at ts %" - GST_TIME_FORMAT, self->name, GST_TIME_ARGS (timestamp)); + GST_WARNING_OBJECT (self, "missing get_value_array implementation"); } - g_free (src_val); - return res; -} - -/** - * gst_control_binding_get_control_source: - * @self: the control binding - * - * Get the control source. - * - * Returns: the control source. Unref when done with it. - */ -GstControlSource * -gst_control_binding_get_control_source (GstControlBinding * self) -{ - g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), NULL); - return g_object_ref (self->csource); + return ret; } /** diff --git a/gst/gstcontrolbinding.h b/gst/gstcontrolbinding.h index ace87aac6..d4629494d 100644 --- a/gst/gstcontrolbinding.h +++ b/gst/gstcontrolbinding.h @@ -68,15 +68,10 @@ struct _GstControlBinding { /*< public >*/ const gchar *name; /* name of the property */ + GParamSpec *pspec; /* GParamSpec for this property */ /*< private >*/ - GParamSpec *pspec; /* GParamSpec for this property */ - GstControlSource *csource; /* GstControlSource for this property */ gboolean disabled; - GValue cur_value; - gdouble last_value; - - GstControlBindingConvert convert; gpointer _gst_reserved[GST_PADDING]; }; @@ -92,12 +87,11 @@ struct _GstControlBinding { struct _GstControlBindingClass { GstObjectClass parent_class; - - /* need vfuncs for: - _sync_values - _get_value - _get_value_array - */ + + /* virtual methods */ + gboolean (* sync_values) (GstControlBinding *self, GstObject *object, GstClockTime timestamp, GstClockTime last_sync); + GValue * (* get_value) (GstControlBinding *self, GstClockTime timestamp); + gboolean (* get_value_array) (GstControlBinding *self, GstClockTime timestamp,GstClockTime interval, guint n_values, GValue *values); /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -107,16 +101,13 @@ GType gst_control_binding_get_type (void); /* Functions */ -GstControlBinding * gst_control_binding_new (GstObject * object, const gchar * property_name, - GstControlSource * csource); - gboolean gst_control_binding_sync_values (GstControlBinding * self, GstObject *object, GstClockTime timestamp, GstClockTime last_sync); GValue * gst_control_binding_get_value (GstControlBinding *binding, GstClockTime timestamp); gboolean gst_control_binding_get_value_array (GstControlBinding *binding, GstClockTime timestamp, GstClockTime interval, guint n_values, GValue *values); -GstControlSource * gst_control_binding_get_control_source (GstControlBinding * self); + void gst_control_binding_set_disabled (GstControlBinding * self, gboolean disabled); gboolean gst_control_binding_is_disabled (GstControlBinding * self); G_END_DECLS diff --git a/gst/gstobject.c b/gst/gstobject.c index 3bb837816..fd56e3182 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -117,7 +117,7 @@ * * * Attach the #GstControlSource on the controller to a property. - * gst_object_add_control_binding (object, gst_control_binding_new (objetct, "prop1", csource)); + * gst_object_add_control_binding (object, gst_control_binding_direct_new (objetct, "prop1", csource)); * * * Set the control values @@ -1222,8 +1222,8 @@ gst_object_add_control_binding (GstObject * object, GstControlBinding * binding) g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE); - g_return_val_if_fail (g_type_is_a (binding->pspec->owner_type, - G_OBJECT_TYPE (object)), FALSE); + //g_return_val_if_fail (g_type_is_a (binding->pspec->owner_type, + // G_OBJECT_TYPE (object)), FALSE); GST_OBJECT_LOCK (object); if ((old = gst_object_find_control_binding (object, binding->name))) { diff --git a/libs/gst/controller/Makefile.am b/libs/gst/controller/Makefile.am index e09519240..490cb8ca1 100644 --- a/libs/gst/controller/Makefile.am +++ b/libs/gst/controller/Makefile.am @@ -2,12 +2,16 @@ lib_LTLIBRARIES = libgstcontroller-@GST_MAJORMINOR@.la libgstcontroller_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \ + gstcontrolbindingargb.h \ + gstcontrolbindingdirect.h \ gsttimedvaluecontrolsource.h \ gstinterpolationcontrolsource.h \ gsttriggercontrolsource.h \ gstlfocontrolsource.h libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \ + gstcontrolbindingargb.c \ + gstcontrolbindingdirect.c \ gsttimedvaluecontrolsource.c \ gstinterpolationcontrolsource.c \ gsttriggercontrolsource.c \ diff --git a/libs/gst/controller/gstcontrolbindingargb.c b/libs/gst/controller/gstcontrolbindingargb.c new file mode 100644 index 000000000..12c576e02 --- /dev/null +++ b/libs/gst/controller/gstcontrolbindingargb.c @@ -0,0 +1,315 @@ +/* GStreamer + * + * Copyright (C) 2011 Stefan Sauer + * + * gstcontrolbindingargb.c: Attachment for multiple control sources to gargb + * properties + * + * 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. + */ +/** + * SECTION:gstcontrolbindingargb + * @short_description: attachment for control source sources to argb properties + * + * A value mapping object that attaches multiple control sources to a guint + * gobject properties representing a color. + */ + +#include +#include + +#include "gstcontrolbindingargb.h" + +#include + +#define GST_CAT_DEFAULT control_binding_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +static void gst_control_binding_argb_dispose (GObject * object); +static void gst_control_binding_argb_finalize (GObject * object); + +static gboolean gst_control_binding_argb_sync_values (GstControlBinding * _self, + GstObject * object, GstClockTime timestamp, GstClockTime last_sync); +static GValue *gst_control_binding_argb_get_value (GstControlBinding * _self, + GstClockTime timestamp); +static gboolean gst_control_binding_argb_get_value_array (GstControlBinding * + _self, GstClockTime timestamp, GstClockTime interval, guint n_values, + GValue * values); + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbindingargb", 0, \ + "dynamic parameter control source attachment"); + +G_DEFINE_TYPE_WITH_CODE (GstControlBindingARGB, gst_control_binding_argb, + GST_TYPE_CONTROL_BINDING, _do_init); + +static void +gst_control_binding_argb_class_init (GstControlBindingARGBClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstControlBindingClass *control_binding_class = + GST_CONTROL_BINDING_CLASS (klass); + + gobject_class->dispose = gst_control_binding_argb_dispose; + gobject_class->finalize = gst_control_binding_argb_finalize; + + control_binding_class->sync_values = gst_control_binding_argb_sync_values; + control_binding_class->get_value = gst_control_binding_argb_get_value; + control_binding_class->get_value_array = + gst_control_binding_argb_get_value_array; +} + +static void +gst_control_binding_argb_init (GstControlBindingARGB * self) +{ +} + +static void +gst_control_binding_argb_dispose (GObject * object) +{ + GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (object); + + if (self->cs_a) + gst_object_replace ((GstObject **) & self->cs_a, NULL); + if (self->cs_r) + gst_object_replace ((GstObject **) & self->cs_r, NULL); + if (self->cs_g) + gst_object_replace ((GstObject **) & self->cs_g, NULL); + if (self->cs_b) + gst_object_replace ((GstObject **) & self->cs_b, NULL); +} + +static void +gst_control_binding_argb_finalize (GObject * object) +{ + GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (object); + + g_value_unset (&self->cur_value); +} + +static gboolean +gst_control_binding_argb_sync_values (GstControlBinding * _self, + GstObject * object, GstClockTime timestamp, GstClockTime last_sync) +{ + GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self); + gdouble src_val_a = 1.0, src_val_r = 0.0, src_val_g = 0.0, src_val_b = 0.0; + gboolean ret = TRUE; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), FALSE); + + GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT, + _self->name, GST_TIME_ARGS (timestamp)); + + if (self->cs_a) + ret &= gst_control_source_get_value (self->cs_a, timestamp, &src_val_a); + if (self->cs_r) + ret &= gst_control_source_get_value (self->cs_r, timestamp, &src_val_r); + if (self->cs_g) + ret &= gst_control_source_get_value (self->cs_g, timestamp, &src_val_g); + if (self->cs_b) + ret &= gst_control_source_get_value (self->cs_b, timestamp, &src_val_b); + if (G_LIKELY (ret)) { + guint src_val = (((guint) (CLAMP (src_val_a, 0.0, 1.0) * 255)) << 24) | + (((guint) (CLAMP (src_val_r, 0.0, 1.0) * 255)) << 16) | + (((guint) (CLAMP (src_val_g, 0.0, 1.0) * 255)) << 8) | + ((guint) (CLAMP (src_val_b, 0.0, 1.0) * 255)); + GST_LOG_OBJECT (object, " new value 0x%08x", src_val); + /* always set the value for first time, but then only if it changed + * this should limit g_object_notify invocations. + * FIXME: can we detect negative playback rates? + */ + if ((timestamp < last_sync) || (src_val != self->last_value)) { + GValue *dst_val = &self->cur_value; + + g_value_set_uint (dst_val, src_val); + /* we can make this faster + * http://bugzilla.gnome.org/show_bug.cgi?id=536939 + */ + g_object_set_property ((GObject *) object, _self->name, dst_val); + self->last_value = src_val; + } + } else { + GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name); + } + return (ret); +} + +static GValue * +gst_control_binding_argb_get_value (GstControlBinding * _self, + GstClockTime timestamp) +{ + GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self); + GValue *dst_val = NULL; + gdouble src_val_a = 1.0, src_val_r = 0.0, src_val_g = 0.0, src_val_b = 0.0; + gboolean ret = TRUE; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), NULL); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); + + /* get current value via control source */ + if (self->cs_a) + ret &= gst_control_source_get_value (self->cs_a, timestamp, &src_val_a); + if (self->cs_r) + ret &= gst_control_source_get_value (self->cs_r, timestamp, &src_val_r); + if (self->cs_g) + ret &= gst_control_source_get_value (self->cs_g, timestamp, &src_val_g); + if (self->cs_b) + ret &= gst_control_source_get_value (self->cs_b, timestamp, &src_val_b); + if (G_LIKELY (ret)) { + guint src_val = (((guint) (CLAMP (src_val_a, 0.0, 1.0) * 255)) << 24) | + (((guint) (CLAMP (src_val_r, 0.0, 1.0) * 255)) << 16) | + (((guint) (CLAMP (src_val_g, 0.0, 1.0) * 255)) << 8) | + ((guint) (CLAMP (src_val_b, 0.0, 1.0) * 255)); + dst_val = g_new0 (GValue, 1); + g_value_init (dst_val, G_TYPE_UINT); + g_value_set_uint (dst_val, src_val); + } else { + GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT, + _self->name, GST_TIME_ARGS (timestamp)); + } + + return dst_val; +} + +static gboolean +gst_control_binding_argb_get_value_array (GstControlBinding * _self, + GstClockTime timestamp, GstClockTime interval, guint n_values, + GValue * values) +{ + GstControlBindingARGB *self = GST_CONTROL_BINDING_ARGB (_self); + gint i; + gdouble *src_val_a = NULL, *src_val_r = NULL, *src_val_g = NULL, *src_val_b = + NULL; + guint src_val; + gboolean ret = TRUE; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_ARGB (self), FALSE); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); + g_return_val_if_fail (values, FALSE); + + if (self->cs_a) { + src_val_a = g_new0 (gdouble, n_values); + ret &= gst_control_source_get_value_array (self->cs_a, timestamp, + interval, n_values, src_val_a); + } + if (self->cs_r) { + src_val_r = g_new0 (gdouble, n_values); + ret &= gst_control_source_get_value_array (self->cs_r, timestamp, + interval, n_values, src_val_r); + } + if (self->cs_g) { + src_val_g = g_new0 (gdouble, n_values); + ret &= gst_control_source_get_value_array (self->cs_g, timestamp, + interval, n_values, src_val_g); + } + if (self->cs_b) { + src_val_b = g_new0 (gdouble, n_values); + ret &= gst_control_source_get_value_array (self->cs_b, timestamp, + interval, n_values, src_val_b); + } + if (G_LIKELY (ret)) { + for (i = 0; i < n_values; i++) { + gdouble a = 1.0, r = 0.0, g = 0.0, b = 0.0; + if (src_val_a && !isnan (src_val_a[i])) + a = src_val_a[i]; + if (src_val_r && !isnan (src_val_r[i])) + r = src_val_r[i]; + if (src_val_g && !isnan (src_val_g[i])) + g = src_val_g[i]; + if (src_val_b && !isnan (src_val_b[i])) + b = src_val_b[i]; + src_val = (((guint) (CLAMP (a, 0.0, 1.0) * 255)) << 24) | + (((guint) (CLAMP (r, 0.0, 1.0) * 255)) << 16) | + (((guint) (CLAMP (g, 0.0, 1.0) * 255)) << 8) | + ((guint) (CLAMP (b, 0.0, 1.0) * 255)); + g_value_init (&values[i], G_TYPE_UINT); + g_value_set_uint (&values[i], src_val); + } + } else { + GST_LOG ("failed to get control value for property %s at ts %" + GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); + } + g_free (src_val_a); + g_free (src_val_r); + g_free (src_val_g); + g_free (src_val_b); + return ret; +} + +/* mapping function */ + +/** + * gst_control_binding_argb_new: + * @object: the object of the property + * @property_name: the property-name to attach the control source + * @cs_a: the control source for the alpha channel + * @cs_r: the control source for the red channel + * @cs_g: the control source for the green channel + * @cs_b: the control source for the blue channel + * + * Create a new control-binding that attaches the given #GstControlSource to the + * #GObject property. + * + * Returns: the new #GstControlBindingARGB + */ +GstControlBinding * +gst_control_binding_argb_new (GstObject * object, const gchar * property_name, + GstControlSource * cs_a, GstControlSource * cs_r, GstControlSource * cs_g, + GstControlSource * cs_b) +{ + GstControlBindingARGB *self = NULL; + GParamSpec *pspec; + + GST_INFO_OBJECT (object, "trying to put property '%s' under control", + property_name); + + /* check if the object has a property of that name */ + if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), + property_name))) { + GST_DEBUG_OBJECT (object, " psec->flags : 0x%08x", pspec->flags); + + /* check if this param is witable && controlable && !construct-only */ + g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE | + GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) == + (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL); + + g_return_val_if_fail (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_UINT, NULL); + + if ((self = (GstControlBindingARGB *) + g_object_newv (GST_TYPE_CONTROL_BINDING_ARGB, 0, NULL))) { + // move below to construct() + ((GstControlBinding *) self)->pspec = pspec; + ((GstControlBinding *) self)->name = pspec->name; + if (cs_a) + self->cs_a = gst_object_ref (cs_a); + if (cs_r) + self->cs_r = gst_object_ref (cs_r); + if (cs_g) + self->cs_g = gst_object_ref (cs_g); + if (cs_b) + self->cs_b = gst_object_ref (cs_b); + + g_value_init (&self->cur_value, G_TYPE_UINT); + } + } else { + GST_WARNING_OBJECT (object, "class '%s' has no property '%s'", + G_OBJECT_TYPE_NAME (object), property_name); + } + return (GstControlBinding *) self; +} + +/* functions */ diff --git a/libs/gst/controller/gstcontrolbindingargb.h b/libs/gst/controller/gstcontrolbindingargb.h new file mode 100644 index 000000000..8d42eceef --- /dev/null +++ b/libs/gst/controller/gstcontrolbindingargb.h @@ -0,0 +1,98 @@ +/* GStreamer + * + * Copyright (C) 2011 Stefan Sauer + * + * gstcontrolbindingargb.h: Attachment for multiple control sources to gargb + * properties + * + * 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. + */ + +#ifndef __GST_CONTROL_BINDING_ARGB_H__ +#define __GST_CONTROL_BINDING_ARGB_H__ + +#include + +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_CONTROL_BINDING_ARGB \ + (gst_control_binding_argb_get_type()) +#define GST_CONTROL_BINDING_ARGB(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONTROL_BINDING_ARGB,GstControlBindingARGB)) +#define GST_CONTROL_BINDING_ARGB_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONTROL_BINDING_ARGB,GstControlBindingARGBClass)) +#define GST_IS_CONTROL_BINDING_ARGB(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONTROL_BINDING_ARGB)) +#define GST_IS_CONTROL_BINDING_ARGB_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONTROL_BINDING_ARGB)) +#define GST_CONTROL_BINDING_ARGB_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CONTOL_SOURCE, GstControlBindingARGBClass)) + +typedef struct _GstControlBindingARGB GstControlBindingARGB; +typedef struct _GstControlBindingARGBClass GstControlBindingARGBClass; + +/** + * GstControlBindingARGB: + * @name: name of the property of this binding + * + * The instance structure of #GstControlBindingARGB. + */ +struct _GstControlBindingARGB { + GstControlBinding parent; + + /*< private >*/ + GstControlSource *cs_a; /* GstControlSources for this property */ + GstControlSource *cs_r; + GstControlSource *cs_g; + GstControlSource *cs_b; + + GValue cur_value; + guint32 last_value; + + gpointer _gst_reserved[GST_PADDING]; +}; + +/** + * GstControlBindingARGBClass: + * @parent_class: Parent class + * @convert: Class method to convert control-values + * + * The class structure of #GstControlBindingARGB. + */ + +struct _GstControlBindingARGBClass +{ + GstControlBindingClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_control_binding_argb_get_type (void); + +/* Functions */ + +GstControlBinding * gst_control_binding_argb_new (GstObject * object, const gchar * property_name, + GstControlSource * cs_a, GstControlSource * cs_r, + GstControlSource * cs_g, GstControlSource * cs_b); + +G_END_DECLS + +#endif /* __GST_CONTROL_BINDING_ARGB_H__ */ diff --git a/libs/gst/controller/gstcontrolbindingdirect.c b/libs/gst/controller/gstcontrolbindingdirect.c new file mode 100644 index 000000000..5148193d7 --- /dev/null +++ b/libs/gst/controller/gstcontrolbindingdirect.c @@ -0,0 +1,351 @@ +/* GStreamer + * + * Copyright (C) 2011 Stefan Sauer + * + * gstcontrolbindingdirect.c: Direct attachment for control sources + * + * 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. + */ +/** + * SECTION:gstcontrolbindingdirect + * @short_description: direct attachment for control source sources + * + * A value mapping object that attaches control sources to gobject properties. + */ + + +#include +#include + +#include "gstcontrolbindingdirect.h" + +#include + +#define GST_CAT_DEFAULT control_binding_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +static void gst_control_binding_direct_dispose (GObject * object); +static void gst_control_binding_direct_finalize (GObject * object); + +static gboolean gst_control_binding_direct_sync_values (GstControlBinding * + _self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync); +static GValue *gst_control_binding_direct_get_value (GstControlBinding * _self, + GstClockTime timestamp); +static gboolean gst_control_binding_direct_get_value_array (GstControlBinding * + _self, GstClockTime timestamp, GstClockTime interval, guint n_values, + GValue * values); + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbindingdirect", 0, \ + "dynamic parameter control source attachment"); + +G_DEFINE_TYPE_WITH_CODE (GstControlBindingDirect, gst_control_binding_direct, + GST_TYPE_CONTROL_BINDING, _do_init); + +static void +gst_control_binding_direct_class_init (GstControlBindingDirectClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstControlBindingClass *control_binding_class = + GST_CONTROL_BINDING_CLASS (klass); + + gobject_class->dispose = gst_control_binding_direct_dispose; + gobject_class->finalize = gst_control_binding_direct_finalize; + + control_binding_class->sync_values = gst_control_binding_direct_sync_values; + control_binding_class->get_value = gst_control_binding_direct_get_value; + control_binding_class->get_value_array = + gst_control_binding_direct_get_value_array; +} + +static void +gst_control_binding_direct_init (GstControlBindingDirect * self) +{ +} + +static void +gst_control_binding_direct_dispose (GObject * object) +{ + GstControlBindingDirect *self = GST_CONTROL_BINDING_DIRECT (object); + + if (self->csource) + gst_object_replace ((GstObject **) & self->csource, NULL); +} + +static void +gst_control_binding_direct_finalize (GObject * object) +{ + GstControlBindingDirect *self = GST_CONTROL_BINDING_DIRECT (object); + + g_value_unset (&self->cur_value); +} + +static gboolean +gst_control_binding_direct_sync_values (GstControlBinding * _self, + GstObject * object, GstClockTime timestamp, GstClockTime last_sync) +{ + GstControlBindingDirect *self = GST_CONTROL_BINDING_DIRECT (_self); + gdouble src_val; + gboolean ret; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_DIRECT (self), FALSE); + + GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT, + _self->name, GST_TIME_ARGS (timestamp)); + + ret = gst_control_source_get_value (self->csource, timestamp, &src_val); + if (G_LIKELY (ret)) { + GST_LOG_OBJECT (object, " new value %lf", src_val); + /* always set the value for first time, but then only if it changed + * this should limit g_object_notify invocations. + * FIXME: can we detect negative playback rates? + */ + if ((timestamp < last_sync) || (src_val != self->last_value)) { + GValue *dst_val = &self->cur_value; + + GST_LOG_OBJECT (object, " mapping %s to value of type %s", _self->name, + G_VALUE_TYPE_NAME (dst_val)); + /* run mapping function to convert gdouble to GValue */ + self->convert (self, src_val, dst_val); + /* we can make this faster + * http://bugzilla.gnome.org/show_bug.cgi?id=536939 + */ + g_object_set_property ((GObject *) object, _self->name, dst_val); + self->last_value = src_val; + } + } else { + GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name); + } + return (ret); +} + +static GValue * +gst_control_binding_direct_get_value (GstControlBinding * _self, + GstClockTime timestamp) +{ + GstControlBindingDirect *self = GST_CONTROL_BINDING_DIRECT (_self); + GValue *dst_val = NULL; + gdouble src_val; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_DIRECT (self), NULL); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); + + /* get current value via control source */ + if (gst_control_source_get_value (self->csource, timestamp, &src_val)) { + dst_val = g_new0 (GValue, 1); + g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec)); + self->convert (self, src_val, dst_val); + } else { + GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT, + _self->name, GST_TIME_ARGS (timestamp)); + } + + return dst_val; +} + +static gboolean +gst_control_binding_direct_get_value_array (GstControlBinding * _self, + GstClockTime timestamp, GstClockTime interval, guint n_values, + GValue * values) +{ + GstControlBindingDirect *self = GST_CONTROL_BINDING_DIRECT (_self); + gint i; + gdouble *src_val; + gboolean res = FALSE; + GType type; + GstControlBindingDirectConvert convert; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING_DIRECT (self), FALSE); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); + g_return_val_if_fail (values, FALSE); + + convert = self->convert; + type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec); + + src_val = g_new0 (gdouble, n_values); + if ((res = gst_control_source_get_value_array (self->csource, timestamp, + interval, n_values, src_val))) { + for (i = 0; i < n_values; i++) { + if (!isnan (src_val[i])) { + g_value_init (&values[i], type); + convert (self, src_val[i], &values[i]); + } else { + GST_LOG ("no control value for property %s at index %d", _self->name, + i); + } + } + } else { + GST_LOG ("failed to get control value for property %s at ts %" + GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); + } + g_free (src_val); + return res; +} + +/* mapping functions */ +#define DEFINE_CONVERT(type,Type,TYPE) \ +static void \ +convert_to_##type (GstControlBindingDirect *self, gdouble s, GValue *d) \ +{ \ + GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \ + g##type v; \ + \ + s = CLAMP (s, 0.0, 1.0); \ + v = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \ + g_value_set_##type (d, v); \ +} + +DEFINE_CONVERT (int, Int, INT); +DEFINE_CONVERT (uint, UInt, UINT); +DEFINE_CONVERT (long, Long, LONG); +DEFINE_CONVERT (ulong, ULong, ULONG); +DEFINE_CONVERT (int64, Int64, INT64); +DEFINE_CONVERT (uint64, UInt64, UINT64); +DEFINE_CONVERT (float, Float, FLOAT); +DEFINE_CONVERT (double, Double, DOUBLE); + +static void +convert_to_boolean (GstControlBindingDirect * self, gdouble s, GValue * d) +{ + s = CLAMP (s, 0.0, 1.0); + g_value_set_boolean (d, (gboolean) (s + 0.5)); +} + +static void +convert_to_enum (GstControlBindingDirect * self, gdouble s, GValue * d) +{ + GParamSpecEnum *pspec = + G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec); + GEnumClass *e = pspec->enum_class; + gint v; + + s = CLAMP (s, 0.0, 1.0); + v = s * (e->n_values - 1); + g_value_set_enum (d, e->values[v].value); +} + +/** + * gst_control_binding_direct_new: + * @object: the object of the property + * @property_name: the property-name to attach the control source + * @csource: the control source + * + * Create a new control-binding that attaches the #GstControlSource to the + * #GObject property. + * + * Returns: the new #GstControlBindingDirect + */ +GstControlBinding * +gst_control_binding_direct_new (GstObject * object, const gchar * property_name, + GstControlSource * csource) +{ + GstControlBindingDirect *self = NULL; + GParamSpec *pspec; + + GST_INFO_OBJECT (object, "trying to put property '%s' under control", + property_name); + + /* check if the object has a property of that name */ + if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), + property_name))) { + GST_DEBUG_OBJECT (object, " psec->flags : 0x%08x", pspec->flags); + + /* check if this param is witable && controlable && !construct-only */ + g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE | + GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) == + (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL); + + if ((self = (GstControlBindingDirect *) + g_object_newv (GST_TYPE_CONTROL_BINDING_DIRECT, 0, NULL))) { + GType type = G_PARAM_SPEC_VALUE_TYPE (pspec), base; + + // add pspec as a construction parameter and move below to construct() + ((GstControlBinding *) self)->pspec = pspec; + ((GstControlBinding *) self)->name = pspec->name; + self->csource = gst_object_ref (csource); + + g_value_init (&self->cur_value, type); + + base = type = G_PARAM_SPEC_VALUE_TYPE (pspec); + while ((type = g_type_parent (type))) + base = type; + + GST_DEBUG_OBJECT (object, " using type %s", g_type_name (base)); + + // select mapping function + // FIXME: only select mapping if super class hasn't set any? + switch (base) { + case G_TYPE_INT: + self->convert = convert_to_int; + break; + case G_TYPE_UINT: + self->convert = convert_to_uint; + break; + case G_TYPE_LONG: + self->convert = convert_to_long; + break; + case G_TYPE_ULONG: + self->convert = convert_to_ulong; + break; + case G_TYPE_INT64: + self->convert = convert_to_int64; + break; + case G_TYPE_UINT64: + self->convert = convert_to_uint64; + break; + case G_TYPE_FLOAT: + self->convert = convert_to_float; + break; + case G_TYPE_DOUBLE: + self->convert = convert_to_double; + break; + case G_TYPE_BOOLEAN: + self->convert = convert_to_boolean; + break; + case G_TYPE_ENUM: + self->convert = convert_to_enum; + break; + default: + // FIXME: return NULL? + GST_WARNING ("incomplete implementation for paramspec type '%s'", + G_PARAM_SPEC_TYPE_NAME (pspec)); + break; + } + } + } else { + GST_WARNING_OBJECT (object, "class '%s' has no property '%s'", + G_OBJECT_TYPE_NAME (object), property_name); + } + return (GstControlBinding *) self; +} + +/* functions */ + +/** + * gst_control_binding_direct_get_control_source: + * @self: the control binding + * + * Get the control source. + * + * Returns: the control source. Unref when done with it. + */ +GstControlSource * +gst_control_binding_direct_get_control_source (GstControlBindingDirect * self) +{ + g_return_val_if_fail (GST_IS_CONTROL_BINDING_DIRECT (self), NULL); + return g_object_ref (self->csource); +} diff --git a/libs/gst/controller/gstcontrolbindingdirect.h b/libs/gst/controller/gstcontrolbindingdirect.h new file mode 100644 index 000000000..09926a6fb --- /dev/null +++ b/libs/gst/controller/gstcontrolbindingdirect.h @@ -0,0 +1,106 @@ +/* GStreamer + * + * Copyright (C) 2011 Stefan Sauer + * + * gstcontrolbindingdirect.h: Direct attachment for control sources + * + * 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. + */ + +#ifndef __GST_CONTROL_BINDING_DIRECT_H__ +#define __GST_CONTROL_BINDING_DIRECT_H__ + +#include + +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_CONTROL_BINDING_DIRECT \ + (gst_control_binding_direct_get_type()) +#define GST_CONTROL_BINDING_DIRECT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONTROL_BINDING_DIRECT,GstControlBindingDirect)) +#define GST_CONTROL_BINDING_DIRECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONTROL_BINDING_DIRECT,GstControlBindingDirectClass)) +#define GST_IS_CONTROL_BINDING_DIRECT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONTROL_BINDING_DIRECT)) +#define GST_IS_CONTROL_BINDING_DIRECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONTROL_BINDING_DIRECT)) +#define GST_CONTROL_BINDING_DIRECT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CONTOL_SOURCE, GstControlBindingDirectClass)) + +typedef struct _GstControlBindingDirect GstControlBindingDirect; +typedef struct _GstControlBindingDirectClass GstControlBindingDirectClass; + +/** + * GstControlBindingDirectConvert: + * @self: the #GstControlBindingDirect instance + * @src_value: the value returned by the cotnrol source + * @dest_value: the target GValue + * + * Function to map a control-value to the target GValue. + */ +typedef void (* GstControlBindingDirectConvert) (GstControlBindingDirect *self, gdouble src_value, GValue *dest_value); + +/** + * GstControlBindingDirect: + * @name: name of the property of this binding + * + * The instance structure of #GstControlBindingDirect. + */ +struct _GstControlBindingDirect { + GstControlBinding parent; + + /*< private >*/ + GstControlSource *csource; /* GstControlSource for this property */ + GValue cur_value; + gdouble last_value; + + GstControlBindingDirectConvert convert; + + gpointer _gst_reserved[GST_PADDING]; +}; + +/** + * GstControlBindingDirectClass: + * @parent_class: Parent class + * @convert: Class method to convert control-values + * + * The class structure of #GstControlBindingDirect. + */ + +struct _GstControlBindingDirectClass +{ + GstControlBindingClass parent_class; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_control_binding_direct_get_type (void); + +/* Functions */ + +GstControlBinding * gst_control_binding_direct_new (GstObject * object, const gchar * property_name, + GstControlSource * csource); + +GstControlSource * gst_control_binding_direct_get_control_source (GstControlBindingDirect * self); + +G_END_DECLS + +#endif /* __GST_CONTROL_BINDING_DIRECT_H__ */ diff --git a/tests/benchmarks/controller.c b/tests/benchmarks/controller.c index 10e1fd7c7..abaf378e1 100644 --- a/tests/benchmarks/controller.c +++ b/tests/benchmarks/controller.c @@ -112,7 +112,7 @@ main (gint argc, gchar * argv[]) /* create and configure control source */ csource = gst_interpolation_control_source_new (); gst_object_add_control_binding (GST_OBJECT (src), - gst_control_binding_new (GST_OBJECT (src), "freq", + gst_control_binding_direct_new (GST_OBJECT (src), "freq", GST_CONTROL_SOURCE (csource))); g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); diff --git a/tests/check/gst/gstcontroller.c b/tests/check/gst/gstcontroller.c index 765abfc80..79fe2d985 100644 --- a/tests/check/gst/gstcontroller.c +++ b/tests/check/gst/gstcontroller.c @@ -328,7 +328,7 @@ GST_START_TEST (controller_new_fail1) cs = gst_test_control_source_new (); /* that property should not exist */ - cb = gst_control_binding_new (GST_OBJECT (elem), "_schrompf_", + cb = gst_control_binding_direct_new (GST_OBJECT (elem), "_schrompf_", GST_CONTROL_SOURCE (cs)); fail_unless (cb == NULL, NULL); @@ -349,7 +349,7 @@ GST_START_TEST (controller_new_fail2) cs = gst_test_control_source_new (); /* that property should exist and but is readonly */ - ASSERT_CRITICAL (cb = gst_control_binding_new (GST_OBJECT (elem), + ASSERT_CRITICAL (cb = gst_control_binding_direct_new (GST_OBJECT (elem), "readonly", GST_CONTROL_SOURCE (cs))); fail_unless (cb == NULL, NULL); @@ -370,7 +370,7 @@ GST_START_TEST (controller_new_fail3) cs = gst_test_control_source_new (); /* that property should exist and but is not controlable */ - ASSERT_CRITICAL (cb = gst_control_binding_new (GST_OBJECT (elem), + ASSERT_CRITICAL (cb = gst_control_binding_direct_new (GST_OBJECT (elem), "static", GST_CONTROL_SOURCE (cs))); fail_unless (cb == NULL, NULL); @@ -392,7 +392,7 @@ GST_START_TEST (controller_new_fail4) /* that property should exist and but is construct-only */ ASSERT_CRITICAL (cb = - gst_control_binding_new (GST_OBJECT (elem), "construct-only", + gst_control_binding_direct_new (GST_OBJECT (elem), "construct-only", GST_CONTROL_SOURCE (cs))); fail_unless (cb == NULL, NULL); @@ -414,7 +414,7 @@ GST_START_TEST (controller_new_okay1) cs = gst_test_control_source_new (); /* that property should exist and should be controllable */ - cb = gst_control_binding_new (GST_OBJECT (elem), "int", + cb = gst_control_binding_direct_new (GST_OBJECT (elem), "int", GST_CONTROL_SOURCE (cs)); fail_unless (cb != NULL, NULL); @@ -437,11 +437,11 @@ GST_START_TEST (controller_new_okay2) cs2 = gst_test_control_source_new (); /* these properties should exist and should be controllable */ - cb1 = gst_control_binding_new (GST_OBJECT (elem), "int", + cb1 = gst_control_binding_direct_new (GST_OBJECT (elem), "int", GST_CONTROL_SOURCE (cs1)); fail_unless (cb1 != NULL, NULL); - cb2 = gst_control_binding_new (GST_OBJECT (elem), "boolean", + cb2 = gst_control_binding_direct_new (GST_OBJECT (elem), "boolean", GST_CONTROL_SOURCE (cs2)); fail_unless (cb2 != NULL, NULL); @@ -466,7 +466,7 @@ GST_START_TEST (controller_param_twice) cs = gst_test_control_source_new (); /* that property should exist and should be controllable */ - cb = gst_control_binding_new (GST_OBJECT (elem), "int", + cb = gst_control_binding_direct_new (GST_OBJECT (elem), "int", GST_CONTROL_SOURCE (cs)); fail_unless (cb != NULL, NULL); cb = gst_object_ref (cb); @@ -527,7 +527,7 @@ GST_START_TEST (controller_controlsource_refcounts) fail_unless_equals_int (G_OBJECT (cs)->ref_count, 1); - cb = gst_control_binding_new (GST_OBJECT (elem), "int", cs); + cb = gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs); fail_unless (cb != NULL, NULL); fail_unless_equals_int (G_OBJECT (cs)->ref_count, 2); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), cb)); @@ -560,9 +560,9 @@ GST_START_TEST (controller_bind_twice) cs = (GstControlSource *) gst_test_control_source_new (); fail_unless (cs != NULL, NULL); - cb1 = gst_control_binding_new (GST_OBJECT (elem), "int", cs); + cb1 = gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs); fail_unless (cb1 != NULL, NULL); - cb2 = gst_control_binding_new (GST_OBJECT (elem), "double", cs); + cb2 = gst_control_binding_direct_new (GST_OBJECT (elem), "double", cs); fail_unless (cb2 != NULL, NULL); gst_object_unref (cb1); @@ -585,7 +585,7 @@ GST_START_TEST (controller_sync1) fail_unless (csource != NULL, NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", + gst_control_binding_direct_new (GST_OBJECT (elem), "int", (GstControlSource *) csource))); csource->value = 0.5; @@ -611,10 +611,10 @@ GST_START_TEST (controller_sync2) fail_unless (csource != NULL, NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", + gst_control_binding_direct_new (GST_OBJECT (elem), "int", (GstControlSource *) csource))); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "double", + gst_control_binding_direct_new (GST_OBJECT (elem), "double", (GstControlSource *) csource))); csource->value = 0.5; diff --git a/tests/check/libs/controller.c b/tests/check/libs/controller.c index 8c7f10ccd..7fc5d0b83 100644 --- a/tests/check/libs/controller.c +++ b/tests/check/libs/controller.c @@ -29,6 +29,7 @@ #include #include #include +#include /* enum for text element */ @@ -286,7 +287,7 @@ GST_START_TEST (controller_controlsource_empty1) fail_unless (csource != NULL, NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", + gst_control_binding_direct_new (GST_OBJECT (elem), "int", (GstControlSource *) csource))); /* don't fail on empty control point lists */ @@ -312,7 +313,7 @@ GST_START_TEST (controller_controlsource_empty2) fail_unless (csource != NULL, NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", + gst_control_binding_direct_new (GST_OBJECT (elem), "int", (GstControlSource *) csource))); /* set control values */ @@ -350,7 +351,7 @@ GST_START_TEST (controller_interpolation_none) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_NONE, NULL); @@ -402,7 +403,7 @@ GST_START_TEST (controller_interpolation_linear) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -442,7 +443,7 @@ GST_START_TEST (controller_interpolation_cubic) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "double", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "double", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL); @@ -491,7 +492,7 @@ GST_START_TEST (controller_interpolation_cubic_too_few_cp) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "double", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "double", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL); @@ -533,7 +534,7 @@ GST_START_TEST (controller_interpolation_unset) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_NONE, NULL); @@ -589,7 +590,7 @@ GST_START_TEST (controller_interpolation_unset_all) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_NONE, NULL); @@ -637,7 +638,7 @@ GST_START_TEST (controller_interpolation_linear_value_array) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -691,7 +692,7 @@ GST_START_TEST (controller_interpolation_linear_invalid_values) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "float", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "float", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -743,7 +744,7 @@ GST_START_TEST (controller_interpolation_linear_default_values) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -814,10 +815,10 @@ GST_START_TEST (controller_interpolation_linear_disabled) fail_unless (csource1 != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs1))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs1))); fail_unless (csource2 != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "double", cs2))); + gst_control_binding_direct_new (GST_OBJECT (elem), "double", cs2))); /* set interpolation mode */ g_object_set (csource1, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -939,7 +940,7 @@ GST_START_TEST (controller_interpolation_set_from_list) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -984,7 +985,7 @@ GST_START_TEST (controller_interpolation_linear_before_ts0) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -1031,7 +1032,7 @@ GST_START_TEST (controller_interpolation_linear_enums) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "enum", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "enum", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL); @@ -1075,7 +1076,7 @@ GST_START_TEST (controller_timed_value_count) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* set interpolation mode */ g_object_set (csource, "mode", GST_INTERPOLATION_MODE_NONE, NULL); @@ -1116,7 +1117,7 @@ GST_START_TEST (controller_lfo_sine) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_SINE, @@ -1170,7 +1171,7 @@ GST_START_TEST (controller_lfo_sine_timeshift) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_SINE, @@ -1224,7 +1225,7 @@ GST_START_TEST (controller_lfo_square) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_SQUARE, @@ -1278,7 +1279,7 @@ GST_START_TEST (controller_lfo_saw) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_SAW, @@ -1332,7 +1333,7 @@ GST_START_TEST (controller_lfo_rsaw) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_REVERSE_SAW, @@ -1386,7 +1387,7 @@ GST_START_TEST (controller_lfo_triangle) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* configure lfo */ g_object_set (csource, "waveform", GST_LFO_WAVEFORM_TRIANGLE, @@ -1440,7 +1441,7 @@ GST_START_TEST (controller_lfo_none) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); /* now pull in values for some timestamps */ gst_object_sync_values (GST_OBJECT (elem), 0 * GST_MSECOND); @@ -1492,7 +1493,7 @@ GST_START_TEST (controller_trigger_exact) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); fail_if (gst_control_source_get_value (cs, 0 * GST_SECOND, &raw_val)); @@ -1538,7 +1539,7 @@ GST_START_TEST (controller_trigger_tolerance) fail_unless (csource != NULL); fail_unless (gst_object_add_control_binding (GST_OBJECT (elem), - gst_control_binding_new (GST_OBJECT (elem), "int", cs))); + gst_control_binding_direct_new (GST_OBJECT (elem), "int", cs))); g_object_set (csource, "tolerance", G_GINT64_CONSTANT (10), NULL); diff --git a/tests/examples/controller/.gitignore b/tests/examples/controller/.gitignore index bbd65fff0..120e16c36 100644 --- a/tests/examples/controller/.gitignore +++ b/tests/examples/controller/.gitignore @@ -1,5 +1,6 @@ audio-example control-sources +text-color-example *.bb *.bbg *.da diff --git a/tests/examples/controller/Makefile.am b/tests/examples/controller/Makefile.am index c983f460c..aee420613 100644 --- a/tests/examples/controller/Makefile.am +++ b/tests/examples/controller/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = audio-example control-sources +noinst_PROGRAMS = audio-example control-sources text-color-example AM_CFLAGS = $(GST_OBJ_CFLAGS) -I$(top_builddir)/libs diff --git a/tests/examples/controller/audio-example.c b/tests/examples/controller/audio-example.c index 19a5d3c5b..aab338e3f 100644 --- a/tests/examples/controller/audio-example.c +++ b/tests/examples/controller/audio-example.c @@ -9,6 +9,7 @@ #include #include +#include gint main (gint argc, gchar ** argv) @@ -49,10 +50,10 @@ main (gint argc, gchar ** argv) csource2 = gst_interpolation_control_source_new (); gst_object_add_control_binding (GST_OBJECT_CAST (src), - gst_control_binding_new (GST_OBJECT_CAST (src), "volume", + gst_control_binding_direct_new (GST_OBJECT_CAST (src), "volume", GST_CONTROL_SOURCE (csource1))); gst_object_add_control_binding (GST_OBJECT_CAST (src), - gst_control_binding_new (GST_OBJECT_CAST (src), "freq", + gst_control_binding_direct_new (GST_OBJECT_CAST (src), "freq", GST_CONTROL_SOURCE (csource2))); /* set interpolation mode */ diff --git a/tests/examples/controller/control-sources.c b/tests/examples/controller/control-sources.c index a6e885889..263959ed5 100644 --- a/tests/examples/controller/control-sources.c +++ b/tests/examples/controller/control-sources.c @@ -15,6 +15,7 @@ #include #include #include +#include /* local test element */ @@ -192,7 +193,8 @@ test_interpolation (void) tvcs = (GstTimedValueControlSource *) ics; cs = (GstControlSource *) ics; - gst_object_add_control_binding (e, gst_control_binding_new (e, "int", cs)); + gst_object_add_control_binding (e, gst_control_binding_direct_new (e, "int", + cs)); gst_timed_value_control_source_set (tvcs, 0 * GST_SECOND, 0.0); gst_timed_value_control_source_set (tvcs, 10 * GST_SECOND, 1.0); @@ -275,7 +277,8 @@ test_lfo (void) lfocs = gst_lfo_control_source_new (); cs = (GstControlSource *) lfocs; - gst_object_add_control_binding (e, gst_control_binding_new (e, "int", cs)); + gst_object_add_control_binding (e, gst_control_binding_direct_new (e, "int", + cs)); g_object_set (lfocs, "frequency", (gdouble) 0.05, @@ -381,7 +384,8 @@ test_chained_lfo (void) lfocs1 = gst_lfo_control_source_new (); cs1 = (GstControlSource *) lfocs1; - gst_object_add_control_binding (e, gst_control_binding_new (e, "int", cs1)); + gst_object_add_control_binding (e, gst_control_binding_direct_new (e, "int", + cs1)); g_object_set (lfocs1, "waveform", GST_LFO_WAVEFORM_SINE, @@ -392,7 +396,7 @@ test_chained_lfo (void) cs2 = (GstControlSource *) lfocs2; gst_object_add_control_binding ((GstObject *) lfocs1, - gst_control_binding_new ((GstObject *) lfocs1, "amplitude", cs2)); + gst_control_binding_direct_new ((GstObject *) lfocs1, "amplitude", cs2)); g_object_set (lfocs2, "waveform", GST_LFO_WAVEFORM_SINE, diff --git a/tests/examples/controller/text-color-example.c b/tests/examples/controller/text-color-example.c new file mode 100644 index 000000000..e0e20e548 --- /dev/null +++ b/tests/examples/controller/text-color-example.c @@ -0,0 +1,120 @@ +/* + * text-color-example.c + * + * Builds a pipeline with [videotestsrc ! textoverlay ! ximagesink] and + * modulates color, text and text pos. + * + * Needs gst-plugin-base installed. + */ + +#include +#include +#include +#include +#include + +gint +main (gint argc, gchar ** argv) +{ + gint res = 1; + GstElement *src, *text, *sink; + GstElement *bin; + GstLFOControlSource *cs; + GstLFOControlSource *cs_r, *cs_g, *cs_b; + GstClock *clock; + GstClockID clock_id; + GstClockReturn wait_ret; + + gst_init (&argc, &argv); + + /* build pipeline */ + bin = gst_pipeline_new ("pipeline"); + clock = gst_pipeline_get_clock (GST_PIPELINE (bin)); + src = gst_element_factory_make ("videotestsrc", NULL); + if (!src) { + GST_WARNING ("need videotestsrc from gst-plugins-base"); + goto Error; + } + g_object_set (src, "pattern", /* checkers-8 */ 10, + NULL); + text = gst_element_factory_make ("textoverlay", NULL); + if (!text) { + GST_WARNING ("need textoverlay from gst-plugins-base"); + goto Error; + } + g_object_set (text, + "text", "GStreamer rocks!", + "font-desc", "Sans, 30", "halignment", /* position */ 4, + "valignment", /* position */ 3, + NULL); + sink = gst_element_factory_make ("ximagesink", NULL); + if (!sink) { + GST_WARNING ("need ximagesink from gst-plugins-base"); + goto Error; + } + + gst_bin_add_many (GST_BIN (bin), src, text, sink, NULL); + if (!gst_element_link_many (src, text, sink, NULL)) { + GST_WARNING ("can't link elements"); + goto Error; + } + + /* setup control sources */ + cs = gst_lfo_control_source_new (); + g_object_set (cs, + "frequency", (gdouble) 0.11, + "amplitude", (gdouble) 0.2, "offset", (gdouble) 0.5, NULL); + gst_object_add_control_binding (GST_OBJECT_CAST (text), + gst_control_binding_direct_new (GST_OBJECT_CAST (text), "xpos", + GST_CONTROL_SOURCE (cs))); + gst_object_unref (cs); + + cs = gst_lfo_control_source_new (); + g_object_set (cs, + "frequency", (gdouble) 0.04, + "amplitude", (gdouble) 0.4, "offset", (gdouble) 0.5, NULL); + gst_object_add_control_binding (GST_OBJECT_CAST (text), + gst_control_binding_direct_new (GST_OBJECT_CAST (text), "ypos", + GST_CONTROL_SOURCE (cs))); + gst_object_unref (cs); + + cs_r = gst_lfo_control_source_new (); + g_object_set (cs_r, + "frequency", (gdouble) 0.19, + "amplitude", (gdouble) 0.5, "offset", (gdouble) 0.5, NULL); + cs_g = gst_lfo_control_source_new (); + g_object_set (cs_g, + "frequency", (gdouble) 0.27, + "amplitude", (gdouble) 0.5, "offset", (gdouble) 0.5, NULL); + cs_b = gst_lfo_control_source_new (); + g_object_set (cs_b, + "frequency", (gdouble) 0.13, + "amplitude", (gdouble) 0.5, "offset", (gdouble) 0.5, NULL); + gst_object_add_control_binding (GST_OBJECT_CAST (text), + gst_control_binding_argb_new (GST_OBJECT_CAST (text), "color", NULL, + GST_CONTROL_SOURCE (cs_r), GST_CONTROL_SOURCE (cs_g), + GST_CONTROL_SOURCE (cs_b))); + gst_object_unref (cs_r); + gst_object_unref (cs_g); + gst_object_unref (cs_b); + + /* run for 10 seconds */ + clock_id = + gst_clock_new_single_shot_id (clock, + gst_clock_get_time (clock) + (30 * GST_SECOND)); + + if (gst_element_set_state (bin, GST_STATE_PLAYING)) { + if ((wait_ret = gst_clock_id_wait (clock_id, NULL)) != GST_CLOCK_OK) { + GST_WARNING ("clock_id_wait returned: %d", wait_ret); + } + gst_element_set_state (bin, GST_STATE_NULL); + } + + /* cleanup */ + gst_clock_id_unref (clock_id); + gst_object_unref (G_OBJECT (clock)); + gst_object_unref (G_OBJECT (bin)); + res = 0; +Error: + return (res); +} diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 157b1a7fa..6127ff32f 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -254,12 +254,10 @@ EXPORTS gst_clock_single_shot_id_reinit gst_clock_type_get_type gst_clock_unadjust_unlocked - gst_control_binding_get_control_source gst_control_binding_get_type gst_control_binding_get_value gst_control_binding_get_value_array gst_control_binding_is_disabled - gst_control_binding_new gst_control_binding_set_disabled gst_control_binding_sync_values gst_control_source_get_type -- cgit v1.2.3