3 * Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
5 * gstcontrolbinding.c: Attachment for control sources
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 * SECTION:gstcontrolbinding
24 * @short_description: attachment for control source sources
26 * A base class for value mapping objects that attaches control sources to gobject
27 * properties. Such an object is taking one or more #GstControlSource instances,
28 * combines them and maps the resulting value to the type and value range of the
31 /* FIXME(ensonic): should we make gst_object_add_control_binding() internal
32 * - we create the control_binding for a certain object anyway
33 * - we could call gst_object_add_control_binding() at the end of
34 * gst_control_binding_constructor()
35 * - the weak-ref on object is not nice, as is the same as gst_object_parent()
36 * once the object is added to the parent
38 * - another option would be to defer what is done in _constructor to when
39 * the parent is set (need to listen to the signal then)
40 * then basically I could
41 * a) remove the obj arg and wait the binding to be added or
42 * b) add the binding from constructor, unref object there and make obj
46 #include "gst_private.h"
48 #include <glib-object.h>
51 #include "gstcontrolbinding.h"
55 #define GST_CAT_DEFAULT control_binding_debug
56 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
59 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbinding", 0, \
60 "dynamic parameter control source attachment");
62 static GObject *gst_control_binding_constructor (GType type,
63 guint n_construct_params, GObjectConstructParam * construct_params);
64 static void gst_control_binding_set_property (GObject * object, guint prop_id,
65 const GValue * value, GParamSpec * pspec);
66 static void gst_control_binding_get_property (GObject * object, guint prop_id,
67 GValue * value, GParamSpec * pspec);
68 static void gst_control_binding_dispose (GObject * object);
69 static void gst_control_binding_finalize (GObject * object);
71 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstControlBinding, gst_control_binding,
72 GST_TYPE_OBJECT, _do_init);
82 static GParamSpec *properties[PROP_LAST];
85 gst_control_binding_class_init (GstControlBindingClass * klass)
87 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
89 gobject_class->constructor = gst_control_binding_constructor;
90 gobject_class->set_property = gst_control_binding_set_property;
91 gobject_class->get_property = gst_control_binding_get_property;
92 gobject_class->dispose = gst_control_binding_dispose;
93 gobject_class->finalize = gst_control_binding_finalize;
95 properties[PROP_OBJECT] =
96 g_param_spec_object ("object", "Object",
97 "The object of the property", GST_TYPE_OBJECT,
98 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
100 properties[PROP_NAME] =
101 g_param_spec_string ("name", "Name", "The name of the property", NULL,
102 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
105 g_object_class_install_properties (gobject_class, PROP_LAST, properties);
109 gst_control_binding_init (GstControlBinding * binding)
114 gst_control_binding_constructor (GType type, guint n_construct_params,
115 GObjectConstructParam * construct_params)
117 GstControlBinding *binding;
121 GST_CONTROL_BINDING (G_OBJECT_CLASS (gst_control_binding_parent_class)
122 ->constructor (type, n_construct_params, construct_params));
124 GST_INFO_OBJECT (binding->object, "trying to put property '%s' under control",
127 /* check if the object has a property of that name */
129 g_object_class_find_property (G_OBJECT_GET_CLASS (binding->object),
131 GST_DEBUG_OBJECT (binding->object, " psec->flags : 0x%08x", pspec->flags);
133 /* check if this param is witable && controlable && !construct-only */
134 if ((pspec->flags & (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE |
135 G_PARAM_CONSTRUCT_ONLY)) ==
136 (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE)) {
137 binding->pspec = pspec;
139 GST_WARNING_OBJECT (binding->object,
140 "property '%s' on class '%s' needs to "
141 "be writeable, controlable and not construct_only", binding->name,
142 G_OBJECT_TYPE_NAME (binding->object));
145 GST_WARNING_OBJECT (binding->object, "class '%s' has no property '%s'",
146 G_OBJECT_TYPE_NAME (binding->object), binding->name);
148 return (GObject *) binding;
152 gst_control_binding_dispose (GObject * object)
154 GstControlBinding *self = GST_CONTROL_BINDING (object);
156 /* we did not took a reference */
157 g_object_remove_weak_pointer ((GObject *) self->object,
158 (gpointer *) & self->object);
161 ((GObjectClass *) gst_control_binding_parent_class)->dispose (object);
165 gst_control_binding_finalize (GObject * object)
167 GstControlBinding *self = GST_CONTROL_BINDING (object);
171 ((GObjectClass *) gst_control_binding_parent_class)->finalize (object);
175 gst_control_binding_set_property (GObject * object, guint prop_id,
176 const GValue * value, GParamSpec * pspec)
178 GstControlBinding *self = GST_CONTROL_BINDING (object);
182 /* do not ref to avoid a ref cycle */
183 self->object = g_value_get_object (value);
184 g_object_add_weak_pointer ((GObject *) self->object,
185 (gpointer *) & self->object);
188 self->name = g_value_dup_string (value);
191 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197 gst_control_binding_get_property (GObject * object, guint prop_id,
198 GValue * value, GParamSpec * pspec)
200 GstControlBinding *self = GST_CONTROL_BINDING (object);
204 g_value_set_object (value, self->object);
207 g_value_set_string (value, self->name);
210 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
218 * gst_control_binding_sync_values:
219 * @binding: the control binding
220 * @object: the object that has controlled properties
221 * @timestamp: the time that should be processed
222 * @last_sync: the last time this was called
224 * Sets the property of the @object, according to the #GstControlSources that
225 * handle them and for the given timestamp.
227 * If this function fails, it is most likely the application developers fault.
228 * Most probably the control sources are not setup correctly.
230 * Returns: %TRUE if the controller value could be applied to the object
231 * property, %FALSE otherwise
234 gst_control_binding_sync_values (GstControlBinding * binding,
235 GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
237 GstControlBindingClass *klass;
238 gboolean ret = FALSE;
240 g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE);
242 if (binding->disabled)
245 klass = GST_CONTROL_BINDING_GET_CLASS (binding);
247 if (G_LIKELY (klass->sync_values != NULL)) {
248 ret = klass->sync_values (binding, object, timestamp, last_sync);
250 GST_WARNING_OBJECT (binding, "missing sync_values implementation");
256 * gst_control_binding_get_value:
257 * @binding: the control binding
258 * @timestamp: the time the control-change should be read from
260 * Gets the value for the given controlled property at the requested time.
262 * Returns: (nullable): the GValue of the property at the given time,
263 * or %NULL if the property isn't controlled.
266 gst_control_binding_get_value (GstControlBinding * binding,
267 GstClockTime timestamp)
269 GstControlBindingClass *klass;
272 g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), NULL);
273 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
275 klass = GST_CONTROL_BINDING_GET_CLASS (binding);
277 if (G_LIKELY (klass->get_value != NULL)) {
278 ret = klass->get_value (binding, timestamp);
280 GST_WARNING_OBJECT (binding, "missing get_value implementation");
286 * gst_control_binding_get_value_array: (skip)
287 * @binding: the control binding
288 * @timestamp: the time that should be processed
289 * @interval: the time spacing between subsequent values
290 * @n_values: the number of values
291 * @values: (array length=n_values): array to put control-values in
293 * Gets a number of values for the given controlled property starting at the
294 * requested time. The array @values need to hold enough space for @n_values of
295 * the same type as the objects property's type.
297 * This function is useful if one wants to e.g. draw a graph of the control
298 * curve or apply a control curve sample by sample.
300 * The values are unboxed and ready to be used. The similar function
301 * gst_control_binding_get_g_value_array() returns the array as #GValues and is
302 * more suitable for bindings.
304 * Returns: %TRUE if the given array could be filled, %FALSE otherwise
307 gst_control_binding_get_value_array (GstControlBinding * binding,
308 GstClockTime timestamp, GstClockTime interval, guint n_values,
311 GstControlBindingClass *klass;
312 gboolean ret = FALSE;
314 g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE);
315 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
316 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
317 g_return_val_if_fail (values, FALSE);
319 klass = GST_CONTROL_BINDING_GET_CLASS (binding);
321 if (G_LIKELY (klass->get_value_array != NULL)) {
323 klass->get_value_array (binding, timestamp, interval, n_values, values);
325 GST_WARNING_OBJECT (binding, "missing get_value_array implementation");
330 #define CONVERT_ARRAY(type,TYPE) \
332 g##type *v = g_new (g##type,n_values); \
333 ret = gst_control_binding_get_value_array (binding, timestamp, interval, \
336 for (i = 0; i < n_values; i++) { \
337 g_value_init (&values[i], G_TYPE_##TYPE); \
338 g_value_set_##type (&values[i], v[i]); \
345 * gst_control_binding_get_g_value_array:
346 * @binding: the control binding
347 * @timestamp: the time that should be processed
348 * @interval: the time spacing between subsequent values
349 * @n_values: the number of values
350 * @values: (array length=n_values): array to put control-values in
352 * Gets a number of #GValues for the given controlled property starting at the
353 * requested time. The array @values need to hold enough space for @n_values of
356 * This function is useful if one wants to e.g. draw a graph of the control
357 * curve or apply a control curve sample by sample.
359 * Returns: %TRUE if the given array could be filled, %FALSE otherwise
362 gst_control_binding_get_g_value_array (GstControlBinding * binding,
363 GstClockTime timestamp, GstClockTime interval, guint n_values,
366 GstControlBindingClass *klass;
367 gboolean ret = FALSE;
369 g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE);
370 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
371 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
372 g_return_val_if_fail (values, FALSE);
374 klass = GST_CONTROL_BINDING_GET_CLASS (binding);
376 if (G_LIKELY (klass->get_g_value_array != NULL)) {
378 klass->get_g_value_array (binding, timestamp, interval, n_values,
384 base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (binding));
385 while ((type = g_type_parent (type)))
388 GST_INFO_OBJECT (binding, "missing get_g_value_array implementation, we're "
392 CONVERT_ARRAY (int, INT);
395 CONVERT_ARRAY (uint, UINT);
398 CONVERT_ARRAY (long, LONG);
401 CONVERT_ARRAY (ulong, ULONG);
404 CONVERT_ARRAY (int64, INT64);
407 CONVERT_ARRAY (uint64, UINT64);
410 CONVERT_ARRAY (float, FLOAT);
413 CONVERT_ARRAY (double, DOUBLE);
416 CONVERT_ARRAY (boolean, BOOLEAN);
420 gint *v = g_new (gint, n_values);
421 ret = gst_control_binding_get_value_array (binding, timestamp, interval,
424 for (i = 0; i < n_values; i++) {
425 g_value_init (&values[i], type);
426 g_value_set_enum (&values[i], v[i]);
433 GST_WARNING ("incomplete implementation for paramspec type '%s'",
434 G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (binding)));
435 GST_CONTROL_BINDING_PSPEC (binding) = NULL;
443 * gst_control_binding_set_disabled:
444 * @binding: the control binding
445 * @disabled: boolean that specifies whether to disable the controller
448 * This function is used to disable a control binding for some time, i.e.
449 * gst_object_sync_values() will do nothing.
452 gst_control_binding_set_disabled (GstControlBinding * binding,
455 g_return_if_fail (GST_IS_CONTROL_BINDING (binding));
456 binding->disabled = disabled;
460 * gst_control_binding_is_disabled:
461 * @binding: the control binding
463 * Check if the control binding is disabled.
465 * Returns: %TRUE if the binding is inactive
468 gst_control_binding_is_disabled (GstControlBinding * binding)
470 g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), TRUE);
471 return (binding->disabled == TRUE);