X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstcontrolbinding.c;h=568f82f7109ffeb8bf45e731d94e860b89cd4888;hb=94ba1cea88788fd3ad72fadcc2ceb7884ed6df50;hp=b9b7bd89ab93ad055c62fd36a21e82e18da8e6ea;hpb=304047b13d72ea87efd03ec768b75fa09d374fac;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstcontrolbinding.c b/gst/gstcontrolbinding.c index b9b7bd8..568f82f 100644 --- a/gst/gstcontrolbinding.c +++ b/gst/gstcontrolbinding.c @@ -16,14 +16,18 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** * SECTION:gstcontrolbinding + * @title: GstControlBinding * @short_description: attachment for control source sources * - * A value mapping object that attaches control sources to gobject properties. + * A base class for value mapping objects that attaches control sources to gobject + * properties. Such an object is taking one or more #GstControlSource instances, + * combines them and maps the resulting value to the type and value range of the + * bound property. */ /* FIXME(ensonic): should we make gst_object_add_control_binding() internal * - we create the control_binding for a certain object anyway @@ -31,6 +35,13 @@ * gst_control_binding_constructor() * - the weak-ref on object is not nice, as is the same as gst_object_parent() * once the object is added to the parent + * + * - another option would be to defer what is done in _constructor to when + * the parent is set (need to listen to the signal then) + * then basically I could + * a) remove the obj arg and wait the binding to be added or + * b) add the binding from constructor, unref object there and make obj + * writeonly */ #include "gst_private.h" @@ -42,6 +53,11 @@ #include +struct _GstControlBindingPrivate +{ + GWeakRef object; +}; + #define GST_CAT_DEFAULT control_binding_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -59,7 +75,7 @@ static void gst_control_binding_dispose (GObject * object); static void gst_control_binding_finalize (GObject * object); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstControlBinding, gst_control_binding, - GST_TYPE_OBJECT, _do_init); + GST_TYPE_OBJECT, G_ADD_PRIVATE (GstControlBinding) _do_init); enum { @@ -96,40 +112,58 @@ gst_control_binding_class_init (GstControlBindingClass * klass) } static void -gst_control_binding_init (GstControlBinding * self) +gst_control_binding_init (GstControlBinding * binding) { + binding->ABI.abi.priv = gst_control_binding_get_instance_private (binding); + g_weak_ref_init (&binding->ABI.abi.priv->object, NULL); } static GObject * gst_control_binding_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params) { - GstControlBinding *self; + GstControlBinding *binding; GParamSpec *pspec; + GstObject *object; - self = GST_CONTROL_BINDING (G_OBJECT_CLASS (gst_control_binding_parent_class) + binding = + GST_CONTROL_BINDING (G_OBJECT_CLASS (gst_control_binding_parent_class) ->constructor (type, n_construct_params, construct_params)); - GST_INFO_OBJECT (self->object, "trying to put property '%s' under control", - self->name); + object = g_weak_ref_get (&binding->ABI.abi.priv->object); + if (!object) { + GST_WARNING_OBJECT (object, "no object set"); + return (GObject *) binding; + } + + GST_INFO_OBJECT (object, "trying to put property '%s' under control", + binding->name); /* check if the object has a property of that name */ if ((pspec = - g_object_class_find_property (G_OBJECT_GET_CLASS (self->object), - self->name))) { - GST_DEBUG_OBJECT (self->object, " psec->flags : 0x%08x", pspec->flags); + g_object_class_find_property (G_OBJECT_GET_CLASS (object), + binding->name))) { + GST_DEBUG_OBJECT (object, " psec->flags : 0x%08x", pspec->flags); /* check if this param is witable && controlable && !construct-only */ if ((pspec->flags & (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) == (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE)) { - self->pspec = pspec; + binding->pspec = pspec; + } else { + GST_WARNING_OBJECT (object, + "property '%s' on class '%s' needs to " + "be writeable, controlable and not construct_only", binding->name, + G_OBJECT_TYPE_NAME (object)); } } else { - GST_WARNING_OBJECT (self->object, "class '%s' has no property '%s'", - G_OBJECT_TYPE_NAME (self->object), self->name); + GST_WARNING_OBJECT (object, "class '%s' has no property '%s'", + G_OBJECT_TYPE_NAME (object), binding->name); } - return (GObject *) self; + + gst_object_unref (object); + + return (GObject *) binding; } static void @@ -138,9 +172,11 @@ gst_control_binding_dispose (GObject * object) GstControlBinding *self = GST_CONTROL_BINDING (object); /* we did not took a reference */ - g_object_remove_weak_pointer ((GObject *) self->object, - (gpointer *) & self->object); - self->object = NULL; + if (self->__object) + g_object_remove_weak_pointer ((GObject *) self->__object, + (gpointer *) & self->__object); + self->__object = NULL; + g_weak_ref_clear (&self->ABI.abi.priv->object); ((GObjectClass *) gst_control_binding_parent_class)->dispose (object); } @@ -164,9 +200,11 @@ gst_control_binding_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: /* do not ref to avoid a ref cycle */ - self->object = g_value_get_object (value); - g_object_add_weak_pointer ((GObject *) self->object, - (gpointer *) & self->object); + self->__object = g_value_get_object (value); + g_object_add_weak_pointer ((GObject *) self->__object, + (gpointer *) & self->__object); + + g_weak_ref_set (&self->ABI.abi.priv->object, self->__object); break; case PROP_NAME: self->name = g_value_dup_string (value); @@ -185,7 +223,7 @@ gst_control_binding_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: - g_value_set_object (value, self->object); + g_value_take_object (value, g_weak_ref_get (&self->ABI.abi.priv->object)); break; case PROP_NAME: g_value_set_string (value, self->name); @@ -200,7 +238,7 @@ gst_control_binding_get_property (GObject * object, guint prop_id, /** * gst_control_binding_sync_values: - * @self: the control binding + * @binding: the control binding * @object: the object that has controlled properties * @timestamp: the time that should be processed * @last_sync: the last time this was called @@ -215,99 +253,217 @@ gst_control_binding_get_property (GObject * object, guint prop_id, * property, %FALSE otherwise */ gboolean -gst_control_binding_sync_values (GstControlBinding * self, GstObject * object, - GstClockTime timestamp, GstClockTime last_sync) +gst_control_binding_sync_values (GstControlBinding * binding, + GstObject * object, GstClockTime timestamp, GstClockTime last_sync) { GstControlBindingClass *klass; gboolean ret = FALSE; - g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), FALSE); + g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE); - if (self->disabled) + if (binding->disabled) return TRUE; - klass = GST_CONTROL_BINDING_GET_CLASS (self); + klass = GST_CONTROL_BINDING_GET_CLASS (binding); if (G_LIKELY (klass->sync_values != NULL)) { - ret = klass->sync_values (self, object, timestamp, last_sync); + ret = klass->sync_values (binding, object, timestamp, last_sync); } else { - GST_WARNING_OBJECT (self, "missing sync_values implementation"); + GST_WARNING_OBJECT (binding, "missing sync_values implementation"); } return ret; } /** * gst_control_binding_get_value: - * @self: the control binding + * @binding: 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. + * Returns: (nullable): 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) +gst_control_binding_get_value (GstControlBinding * binding, + GstClockTime timestamp) { GstControlBindingClass *klass; GValue *ret = NULL; - g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), NULL); + g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), NULL); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); - klass = GST_CONTROL_BINDING_GET_CLASS (self); + klass = GST_CONTROL_BINDING_GET_CLASS (binding); if (G_LIKELY (klass->get_value != NULL)) { - ret = klass->get_value (self, timestamp); + ret = klass->get_value (binding, timestamp); } else { - GST_WARNING_OBJECT (self, "missing get_value implementation"); + GST_WARNING_OBJECT (binding, "missing get_value implementation"); } return ret; } /** - * gst_control_binding_get_value_array: - * @self: the control binding + * gst_control_binding_get_value_array: (skip) + * @binding: 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 + * @values: (array length=n_values): array to put control-values in * - * Gets a number of values for the given controllered property starting at the + * Gets a number of values for the given controlled 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. * + * The values are unboxed and ready to be used. The similar function + * gst_control_binding_get_g_value_array() returns the array as #GValues and is + * more suitable for bindings. + * * Returns: %TRUE if the given array could be filled, %FALSE otherwise */ gboolean -gst_control_binding_get_value_array (GstControlBinding * self, +gst_control_binding_get_value_array (GstControlBinding * binding, GstClockTime timestamp, GstClockTime interval, guint n_values, - GValue * values) + gpointer values) { GstControlBindingClass *klass; gboolean ret = FALSE; - g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), FALSE); + g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), 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); - klass = GST_CONTROL_BINDING_GET_CLASS (self); + klass = GST_CONTROL_BINDING_GET_CLASS (binding); if (G_LIKELY (klass->get_value_array != NULL)) { - ret = klass->get_value_array (self, timestamp, interval, n_values, values); + ret = + klass->get_value_array (binding, timestamp, interval, n_values, values); } else { - GST_WARNING_OBJECT (self, "missing get_value_array implementation"); + GST_WARNING_OBJECT (binding, "missing get_value_array implementation"); + } + return ret; +} + +#define CONVERT_ARRAY(type,TYPE) \ +{ \ + g##type *v = g_new (g##type,n_values); \ + ret = gst_control_binding_get_value_array (binding, timestamp, interval, \ + n_values, v); \ + if (ret) { \ + for (i = 0; i < n_values; i++) { \ + g_value_init (&values[i], G_TYPE_##TYPE); \ + g_value_set_##type (&values[i], v[i]); \ + } \ + } \ + g_free (v); \ +} + +/** + * gst_control_binding_get_g_value_array: + * @binding: 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 length=n_values): array to put control-values in + * + * Gets a number of #GValues for the given controlled property starting at the + * requested time. The array @values need to hold enough space for @n_values of + * #GValue. + * + * 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_g_value_array (GstControlBinding * binding, + GstClockTime timestamp, GstClockTime interval, guint n_values, + GValue * values) +{ + GstControlBindingClass *klass; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), 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); + + klass = GST_CONTROL_BINDING_GET_CLASS (binding); + + if (G_LIKELY (klass->get_g_value_array != NULL)) { + ret = + klass->get_g_value_array (binding, timestamp, interval, n_values, + values); + } else { + guint i; + GType type, base; + + base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (binding)); + while ((type = g_type_parent (type))) + base = type; + + GST_INFO_OBJECT (binding, "missing get_g_value_array implementation, we're " + "emulating it"); + switch (base) { + case G_TYPE_INT: + CONVERT_ARRAY (int, INT); + break; + case G_TYPE_UINT: + CONVERT_ARRAY (uint, UINT); + break; + case G_TYPE_LONG: + CONVERT_ARRAY (long, LONG); + break; + case G_TYPE_ULONG: + CONVERT_ARRAY (ulong, ULONG); + break; + case G_TYPE_INT64: + CONVERT_ARRAY (int64, INT64); + break; + case G_TYPE_UINT64: + CONVERT_ARRAY (uint64, UINT64); + break; + case G_TYPE_FLOAT: + CONVERT_ARRAY (float, FLOAT); + break; + case G_TYPE_DOUBLE: + CONVERT_ARRAY (double, DOUBLE); + break; + case G_TYPE_BOOLEAN: + CONVERT_ARRAY (boolean, BOOLEAN); + break; + case G_TYPE_ENUM: + { + gint *v = g_new (gint, n_values); + ret = gst_control_binding_get_value_array (binding, timestamp, interval, + n_values, v); + if (ret) { + for (i = 0; i < n_values; i++) { + g_value_init (&values[i], type); + g_value_set_enum (&values[i], v[i]); + } + } + g_free (v); + } + break; + default: + GST_WARNING ("incomplete implementation for paramspec type '%s'", + G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (binding))); + GST_CONTROL_BINDING_PSPEC (binding) = NULL; + break; + } } return ret; } /** * gst_control_binding_set_disabled: - * @self: the control binding + * @binding: the control binding * @disabled: boolean that specifies whether to disable the controller * or not. * @@ -315,23 +471,24 @@ gst_control_binding_get_value_array (GstControlBinding * self, * gst_object_sync_values() will do nothing. */ void -gst_control_binding_set_disabled (GstControlBinding * self, gboolean disabled) +gst_control_binding_set_disabled (GstControlBinding * binding, + gboolean disabled) { - g_return_if_fail (GST_IS_CONTROL_BINDING (self)); - self->disabled = disabled; + g_return_if_fail (GST_IS_CONTROL_BINDING (binding)); + binding->disabled = disabled; } /** * gst_control_binding_is_disabled: - * @self: the control binding + * @binding: the control binding * * Check if the control binding is disabled. * * Returns: %TRUE if the binding is inactive */ gboolean -gst_control_binding_is_disabled (GstControlBinding * self) +gst_control_binding_is_disabled (GstControlBinding * binding) { - g_return_val_if_fail (GST_IS_CONTROL_BINDING (self), TRUE); - return (self->disabled == TRUE); + g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), TRUE); + return ! !binding->disabled; }