diff options
author | Stefan Sauer <ensonic@users.sf.net> | 2011-12-22 23:48:30 +0100 |
---|---|---|
committer | Stefan Sauer <ensonic@users.sf.net> | 2011-12-25 20:48:14 +0100 |
commit | 39d6b7462f44b4eb55b46ee17ff5e5c7a3d77e5f (patch) | |
tree | c1119ba95ceb4e6b2b84881118a0e54c0384b462 /gst | |
parent | a80401b22c6f8693e733767aec3086296ac6ed05 (diff) | |
download | gstreamer-39d6b7462f44b4eb55b46ee17ff5e5c7a3d77e5f.tar.gz |
controller: move GValue handling from control-sources to -binding
ControlSources are now gdouble based. A control source is mapped to a
particullar GObject property using a ControlBinding.
Diffstat (limited to 'gst')
-rw-r--r-- | gst/gstcontrolbinding.c | 195 | ||||
-rw-r--r-- | gst/gstcontrolbinding.h | 28 | ||||
-rw-r--r-- | gst/gstcontrolsource.c | 52 | ||||
-rw-r--r-- | gst/gstcontrolsource.h | 27 | ||||
-rw-r--r-- | gst/gstobject.c | 20 | ||||
-rw-r--r-- | gst/gstobject.h | 2 |
6 files changed, 220 insertions, 104 deletions
diff --git a/gst/gstcontrolbinding.c b/gst/gstcontrolbinding.c index 4bba851fd6..0bdb2fc258 100644 --- a/gst/gstcontrolbinding.c +++ b/gst/gstcontrolbinding.c @@ -33,6 +33,8 @@ #include "gstcontrolbinding.h" +#include <math.h> + #define GST_CAT_DEFAULT control_binding_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -66,8 +68,6 @@ gst_control_binding_dispose (GObject * object) GstControlBinding *self = GST_CONTROL_BINDING (object); if (self->csource) { - // FIXME: hack - self->csource->bound = FALSE; g_object_unref (self->csource); self->csource = NULL; } @@ -79,7 +79,35 @@ gst_control_binding_finalize (GObject * object) GstControlBinding *self = GST_CONTROL_BINDING (object); g_value_unset (&self->cur_value); - g_value_unset (&self->last_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)); } /** @@ -113,16 +141,59 @@ gst_control_binding_new (GstObject * object, const gchar * property_name, GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) == (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL); - if (gst_control_source_bind (csource, pspec)) { - if ((self = (GstControlBinding *) g_object_newv (GST_TYPE_CONTROL_BINDING, - 0, NULL))) { - self->pspec = pspec; - self->name = pspec->name; - self->csource = g_object_ref (csource); - self->disabled = FALSE; + 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)); - g_value_init (&self->cur_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_value_init (&self->last_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + // 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; + default: + // FIXME: return NULL? + GST_WARNING ("incomplete implementation for paramspec type '%s'", + G_PARAM_SPEC_TYPE_NAME (pspec)); + break; } } } else { @@ -154,7 +225,8 @@ gboolean gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync) { - GValue *value; + GValue *dst_val; + gdouble src_val; gboolean ret; g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), FALSE); @@ -165,20 +237,24 @@ gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, GST_LOG_OBJECT (object, "property '%s' at ts=%" G_GUINT64_FORMAT, self->name, timestamp); - value = &self->cur_value; - ret = gst_control_source_get_value (self->csource, timestamp, value); + 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) || - gst_value_compare (value, &self->last_value) != GST_VALUE_EQUAL) { + 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, value); - g_value_copy (value, &self->last_value); + 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); @@ -187,6 +263,87 @@ gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, } /** + * gst_control_binding_get_value: + * @self: the control binding + * @timestamp: the time the control-change should be read from + * + * Gets the value for the given controlled property at the requested time. + * + * Returns: the GValue of the property at the given time, or %NULL if the + * property isn't controlled. + */ +GValue * +gst_control_binding_get_value (GstControlBinding * self, GstClockTime timestamp) +{ + GValue *dst_val = NULL; + gdouble src_val; + + 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); + } + + return dst_val; +} + +/** + * gst_control_binding_get_value_array: + * @self: the control binding + * @timestamp: the time that should be processed + * @interval: the time spacing between subsequent values + * @n_values: the number of values + * @values: array to put control-values in + * + * Gets a number of values for the given controllered property starting at the + * requested time. The array @values need to hold enough space for @n_values of + * the same type as the objects property's type. + * + * This function is useful if one wants to e.g. draw a graph of the control + * curve or apply a control curve sample by sample. + * + * Returns: %TRUE if the given array could be filled, %FALSE otherwise + */ +gboolean +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; + + 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); + + 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]); + } + } + } + g_free (src_val); + return res; +} + + + +/** * gst_control_binding_get_control_source: * @self: the control binding * diff --git a/gst/gstcontrolbinding.h b/gst/gstcontrolbinding.h index e9ee23af74..64661abdc6 100644 --- a/gst/gstcontrolbinding.h +++ b/gst/gstcontrolbinding.h @@ -48,27 +48,43 @@ typedef struct _GstControlBinding GstControlBinding; typedef struct _GstControlBindingClass GstControlBindingClass; /** + * GstControlBindingConvert: + * @self: the #GstControlBinding 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 (* GstControlBindingConvert) (GstControlBinding *self, gdouble src_value, GValue *dest_value); + +/** * GstControlBinding: + * @name: name of the property of this binding * * The instance structure of #GstControlBinding. */ struct _GstControlBinding { GObject parent; - + /*< public >*/ - GParamSpec *pspec; /* GParamSpec for this property */ const gchar *name; /* name of the property */ + + /*< private >*/ + GParamSpec *pspec; /* GParamSpec for this property */ GstControlSource *csource; /* GstControlSource for this property */ gboolean disabled; - GValue cur_value, last_value; + GValue cur_value; + gdouble last_value; + + GstControlBindingConvert convert; - /*< private >*/ gpointer _gst_reserved[GST_PADDING]; }; /** * GstControlBindingClass: * @parent_class: Parent class + * @convert: Class method to convert control-values * * The class structure of #GstControlBinding. */ @@ -90,6 +106,10 @@ GstControlBinding * gst_control_binding_new (GstObject * object, 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); diff --git a/gst/gstcontrolsource.c b/gst/gstcontrolsource.c index 85f242d5fc..a2b116120c 100644 --- a/gst/gstcontrolsource.c +++ b/gst/gstcontrolsource.c @@ -61,10 +61,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstControlSource, gst_control_source, static void gst_control_source_class_init (GstControlSourceClass * klass) { - //GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - /* Has to be implemented by children */ - klass->bind = NULL; } static void @@ -72,7 +68,6 @@ gst_control_source_init (GstControlSource * self) { self->get_value = NULL; self->get_value_array = NULL; - self->bound = FALSE; } /** @@ -87,7 +82,7 @@ gst_control_source_init (GstControlSource * self) */ gboolean gst_control_source_get_value (GstControlSource * self, GstClockTime timestamp, - GValue * value) + gdouble * value) { g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE); @@ -102,23 +97,19 @@ gst_control_source_get_value (GstControlSource * self, GstClockTime timestamp, /** * gst_control_source_get_value_array: * @self: the #GstControlSource object - * @timestamp: the time that should be processed + * @timestamp: the first timestamp + * @interval: the time steps + * @n_values: the number of values to fetch * @value_array: array to put control-values in * - * Gets an array of values for one element property. - * - * All fields of @value_array must be filled correctly. Especially the - * @value_array->values array must be big enough to keep the requested amount - * of values. - * - * The type of the values in the array is the same as the property's type. + * Gets an array of values for for this #GstControlSource. * * Returns: %TRUE if the given array could be filled, %FALSE otherwise */ gboolean gst_control_source_get_value_array (GstControlSource * self, GstClockTime timestamp, GstClockTime interval, guint n_values, - gpointer values) + gdouble * values) { g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE); @@ -129,34 +120,3 @@ gst_control_source_get_value_array (GstControlSource * self, return FALSE; } } - -/** - * gst_control_source_bind: - * @self: the #GstControlSource object - * @pspec: #GParamSpec for the property for which this #GstControlSource should generate values. - * - * Binds a #GstControlSource to a specific property. This must be called only once for a - * #GstControlSource. - * - * Returns: %TRUE if the #GstControlSource was bound correctly, %FALSE otherwise. - */ -gboolean -gst_control_source_bind (GstControlSource * self, GParamSpec * pspec) -{ - gboolean ret = FALSE; - - g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE); - g_return_val_if_fail (GST_CONTROL_SOURCE_GET_CLASS (self)->bind, FALSE); - g_return_val_if_fail (!self->bound, FALSE); - - ret = GST_CONTROL_SOURCE_GET_CLASS (self)->bind (self, pspec); - - if (ret) { - GST_DEBUG ("bound control source for param %s", pspec->name); - self->bound = TRUE; - } else { - GST_DEBUG ("failed to bind control source for param %s", pspec->name); - } - - return ret; -} diff --git a/gst/gstcontrolsource.h b/gst/gstcontrolsource.h index 5cd2dc6ebd..1dc4bb02e7 100644 --- a/gst/gstcontrolsource.h +++ b/gst/gstcontrolsource.h @@ -59,7 +59,7 @@ typedef struct _GstValueArray GstValueArray; struct _GstTimedValue { GstClockTime timestamp; - GValue value; + gdouble value; }; /** @@ -74,7 +74,7 @@ struct _GstTimedValue * */ typedef gboolean (* GstControlSourceGetValue) (GstControlSource *self, - GstClockTime timestamp, GValue *value); + GstClockTime timestamp, gdouble *value); /** * GstControlSourceGetValueArray @@ -90,18 +90,7 @@ typedef gboolean (* GstControlSourceGetValue) (GstControlSource *self, * */ typedef gboolean (* GstControlSourceGetValueArray) (GstControlSource *self, - GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer values); - -/** - * GstControlSourceBind - * @self: the #GstControlSource instance - * @pspec: #GParamSpec that should be bound to - * - * Function for binding a #GstControlSource to a #GParamSpec. - * - * Returns: %TRUE if the property could be bound to the #GstControlSource, %FALSE otherwise. - */ -typedef gboolean (* GstControlSourceBind) (GstControlSource *self, GParamSpec *pspec); + GstClockTime timestamp, GstClockTime interval, guint n_values, gdouble *values); /** * GstControlSource: @@ -118,7 +107,6 @@ struct _GstControlSource { GstControlSourceGetValueArray get_value_array; /* Returns values for a property in a given timespan */ /*< private >*/ - gboolean bound; gpointer _gst_reserved[GST_PADDING]; }; @@ -134,8 +122,6 @@ struct _GstControlSourceClass { GObjectClass parent_class; - GstControlSourceBind bind; /* Binds the GstControlSource to a specific GParamSpec */ - /*< private >*/ gpointer _gst_reserved[GST_PADDING]; }; @@ -144,13 +130,10 @@ GType gst_control_source_get_type (void); /* Functions */ gboolean gst_control_source_get_value (GstControlSource *self, GstClockTime timestamp, - GValue *value); + gdouble *value); gboolean gst_control_source_get_value_array (GstControlSource *self, GstClockTime timestamp, GstClockTime interval, guint n_values, - gpointer values); - -gboolean gst_control_source_bind (GstControlSource *self, GParamSpec *pspec); - + gdouble *values); G_END_DECLS #endif /* __GST_CONTROL_SOURCE_H__ */ diff --git a/gst/gstobject.c b/gst/gstobject.c index 5b098fe8ac..ef42e88a7c 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -1109,6 +1109,8 @@ gst_object_sync_values (GstObject * object, GstClockTime timestamp) g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); GST_LOG_OBJECT (object, "sync_values"); + if (!object->control_bindings) + return TRUE; /* FIXME: this deadlocks */ /* GST_OBJECT_LOCK (object); */ @@ -1353,7 +1355,7 @@ gst_object_get_control_source (GstObject * object, const gchar * property_name) * @property_name: the name of the property to get * @timestamp: the time the control-change should be read from * - * Gets the value for the given controllered property at the requested time. + * Gets the value for the given controlled property at the requested time. * * Returns: the GValue of the property at the given time, or %NULL if the * property isn't controlled. @@ -1371,14 +1373,7 @@ gst_object_get_value (GstObject * object, const gchar * property_name, GST_OBJECT_LOCK (object); if ((binding = gst_object_find_control_binding (object, property_name))) { - val = g_new0 (GValue, 1); - g_value_init (val, G_PARAM_SPEC_VALUE_TYPE (binding->pspec)); - - /* get current value via control source */ - if (!gst_control_source_get_value (binding->csource, timestamp, val)) { - g_free (val); - val = NULL; - } + val = gst_control_binding_get_value (binding, timestamp); } GST_OBJECT_UNLOCK (object); @@ -1406,7 +1401,7 @@ gst_object_get_value (GstObject * object, const gchar * property_name, gboolean gst_object_get_value_array (GstObject * object, const gchar * property_name, GstClockTime timestamp, GstClockTime interval, guint n_values, - gpointer values) + GValue * values) { gboolean res = FALSE; GstControlBinding *binding; @@ -1419,8 +1414,9 @@ gst_object_get_value_array (GstObject * object, const gchar * property_name, GST_OBJECT_LOCK (object); if ((binding = gst_object_find_control_binding (object, property_name))) { - res = gst_control_source_get_value_array (binding->csource, timestamp, - interval, n_values, values); + /* FIXME: use binding: */ + res = gst_control_binding_get_value_array (binding, timestamp, interval, + n_values, values); } GST_OBJECT_UNLOCK (object); return res; diff --git a/gst/gstobject.h b/gst/gstobject.h index ec7925e7ef..193301dde1 100644 --- a/gst/gstobject.h +++ b/gst/gstobject.h @@ -257,7 +257,7 @@ GValue * gst_object_get_value (GstObject * object, const gchar GstClockTime timestamp); gboolean gst_object_get_value_array (GstObject * object, const gchar * property_name, GstClockTime timestamp, GstClockTime interval, - guint n_values, gpointer values); + guint n_values, GValue *values); GstClockTime gst_object_get_control_rate (GstObject * object); void gst_object_set_control_rate (GstObject * object, GstClockTime control_rate); |