message/query: Simplify CONTEXT messages/queries to only contain a single type
[platform/upstream/gstreamer.git] / gst / gstcontrolbinding.c
1 /* GStreamer
2  *
3  * Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
4  *
5  * gstcontrolbinding.c: Attachment for control sources
6  *
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.
11  *
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.
16  *
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.
21  */
22 /**
23  * SECTION:gstcontrolbinding
24  * @short_description: attachment for control source sources
25  *
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
29  * bound property.
30  */
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
37  *
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
43  *      writeonly
44  */
45
46 #include "gst_private.h"
47
48 #include <glib-object.h>
49 #include <gst/gst.h>
50
51 #include "gstcontrolbinding.h"
52
53 #include <math.h>
54
55 #define GST_CAT_DEFAULT control_binding_debug
56 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
57
58 #define _do_init \
59   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolbinding", 0, \
60       "dynamic parameter control source attachment");
61
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);
70
71 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstControlBinding, gst_control_binding,
72     GST_TYPE_OBJECT, _do_init);
73
74 enum
75 {
76   PROP_0,
77   PROP_OBJECT,
78   PROP_NAME,
79   PROP_LAST
80 };
81
82 static GParamSpec *properties[PROP_LAST];
83
84 static void
85 gst_control_binding_class_init (GstControlBindingClass * klass)
86 {
87   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
88
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;
94
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);
99
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);
103
104
105   g_object_class_install_properties (gobject_class, PROP_LAST, properties);
106 }
107
108 static void
109 gst_control_binding_init (GstControlBinding * binding)
110 {
111 }
112
113 static GObject *
114 gst_control_binding_constructor (GType type, guint n_construct_params,
115     GObjectConstructParam * construct_params)
116 {
117   GstControlBinding *binding;
118   GParamSpec *pspec;
119
120   binding =
121       GST_CONTROL_BINDING (G_OBJECT_CLASS (gst_control_binding_parent_class)
122       ->constructor (type, n_construct_params, construct_params));
123
124   GST_INFO_OBJECT (binding->object, "trying to put property '%s' under control",
125       binding->name);
126
127   /* check if the object has a property of that name */
128   if ((pspec =
129           g_object_class_find_property (G_OBJECT_GET_CLASS (binding->object),
130               binding->name))) {
131     GST_DEBUG_OBJECT (binding->object, "  psec->flags : 0x%08x", pspec->flags);
132
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;
138     } else {
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));
143     }
144   } else {
145     GST_WARNING_OBJECT (binding->object, "class '%s' has no property '%s'",
146         G_OBJECT_TYPE_NAME (binding->object), binding->name);
147   }
148   return (GObject *) binding;
149 }
150
151 static void
152 gst_control_binding_dispose (GObject * object)
153 {
154   GstControlBinding *self = GST_CONTROL_BINDING (object);
155
156   /* we did not took a reference */
157   g_object_remove_weak_pointer ((GObject *) self->object,
158       (gpointer *) & self->object);
159   self->object = NULL;
160
161   ((GObjectClass *) gst_control_binding_parent_class)->dispose (object);
162 }
163
164 static void
165 gst_control_binding_finalize (GObject * object)
166 {
167   GstControlBinding *self = GST_CONTROL_BINDING (object);
168
169   g_free (self->name);
170
171   ((GObjectClass *) gst_control_binding_parent_class)->finalize (object);
172 }
173
174 static void
175 gst_control_binding_set_property (GObject * object, guint prop_id,
176     const GValue * value, GParamSpec * pspec)
177 {
178   GstControlBinding *self = GST_CONTROL_BINDING (object);
179
180   switch (prop_id) {
181     case PROP_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);
186       break;
187     case PROP_NAME:
188       self->name = g_value_dup_string (value);
189       break;
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193   }
194 }
195
196 static void
197 gst_control_binding_get_property (GObject * object, guint prop_id,
198     GValue * value, GParamSpec * pspec)
199 {
200   GstControlBinding *self = GST_CONTROL_BINDING (object);
201
202   switch (prop_id) {
203     case PROP_OBJECT:
204       g_value_set_object (value, self->object);
205       break;
206     case PROP_NAME:
207       g_value_set_string (value, self->name);
208       break;
209     default:
210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
211       break;
212   }
213 }
214
215 /* functions */
216
217 /**
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
223  *
224  * Sets the property of the @object, according to the #GstControlSources that
225  * handle them and for the given timestamp.
226  *
227  * If this function fails, it is most likely the application developers fault.
228  * Most probably the control sources are not setup correctly.
229  *
230  * Returns: %TRUE if the controller value could be applied to the object
231  * property, %FALSE otherwise
232  */
233 gboolean
234 gst_control_binding_sync_values (GstControlBinding * binding,
235     GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
236 {
237   GstControlBindingClass *klass;
238   gboolean ret = FALSE;
239
240   g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE);
241
242   if (binding->disabled)
243     return TRUE;
244
245   klass = GST_CONTROL_BINDING_GET_CLASS (binding);
246
247   if (G_LIKELY (klass->sync_values != NULL)) {
248     ret = klass->sync_values (binding, object, timestamp, last_sync);
249   } else {
250     GST_WARNING_OBJECT (binding, "missing sync_values implementation");
251   }
252   return ret;
253 }
254
255 /**
256  * gst_control_binding_get_value:
257  * @binding: the control binding
258  * @timestamp: the time the control-change should be read from
259  *
260  * Gets the value for the given controlled property at the requested time.
261  *
262  * Returns: the GValue of the property at the given time, or %NULL if the
263  * property isn't controlled.
264  */
265 GValue *
266 gst_control_binding_get_value (GstControlBinding * binding,
267     GstClockTime timestamp)
268 {
269   GstControlBindingClass *klass;
270   GValue *ret = NULL;
271
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);
274
275   klass = GST_CONTROL_BINDING_GET_CLASS (binding);
276
277   if (G_LIKELY (klass->get_value != NULL)) {
278     ret = klass->get_value (binding, timestamp);
279   } else {
280     GST_WARNING_OBJECT (binding, "missing get_value implementation");
281   }
282   return ret;
283 }
284
285 /**
286  * gst_control_binding_get_value_array:
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 to put control-values in
292  *
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.
296  *
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.
299  *
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.
303  *
304  * Returns: %TRUE if the given array could be filled, %FALSE otherwise
305  */
306 gboolean
307 gst_control_binding_get_value_array (GstControlBinding * binding,
308     GstClockTime timestamp, GstClockTime interval, guint n_values,
309     gpointer values)
310 {
311   GstControlBindingClass *klass;
312   gboolean ret = FALSE;
313
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);
318
319   klass = GST_CONTROL_BINDING_GET_CLASS (binding);
320
321   if (G_LIKELY (klass->get_value_array != NULL)) {
322     ret =
323         klass->get_value_array (binding, timestamp, interval, n_values, values);
324   } else {
325     GST_WARNING_OBJECT (binding, "missing get_value_array implementation");
326   }
327   return ret;
328 }
329
330 #define CONVERT_ARRAY(type,TYPE) \
331 { \
332   g##type *v = g_new (g##type,n_values); \
333   ret = gst_control_binding_get_value_array (binding, timestamp, interval, \
334       n_values, v); \
335   if (ret) { \
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]); \
339     } \
340   } \
341   g_free (v); \
342 }
343
344 /**
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 to put control-values in
351  *
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
354  * #GValue.
355  *
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.
358  *
359  * Returns: %TRUE if the given array could be filled, %FALSE otherwise
360  */
361 gboolean
362 gst_control_binding_get_g_value_array (GstControlBinding * binding,
363     GstClockTime timestamp, GstClockTime interval, guint n_values,
364     GValue * values)
365 {
366   GstControlBindingClass *klass;
367   gboolean ret = FALSE;
368
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);
373
374   klass = GST_CONTROL_BINDING_GET_CLASS (binding);
375
376   if (G_LIKELY (klass->get_g_value_array != NULL)) {
377     ret =
378         klass->get_g_value_array (binding, timestamp, interval, n_values,
379         values);
380   } else {
381     guint i;
382     GType type, base;
383
384     base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (binding));
385     while ((type = g_type_parent (type)))
386       base = type;
387
388     GST_INFO_OBJECT (binding, "missing get_g_value_array implementation, we're "
389         "emulating it");
390     switch (base) {
391       case G_TYPE_INT:
392         CONVERT_ARRAY (int, INT);
393         break;
394       case G_TYPE_UINT:
395         CONVERT_ARRAY (uint, UINT);
396         break;
397       case G_TYPE_LONG:
398         CONVERT_ARRAY (long, LONG);
399         break;
400       case G_TYPE_ULONG:
401         CONVERT_ARRAY (ulong, ULONG);
402         break;
403       case G_TYPE_INT64:
404         CONVERT_ARRAY (int64, INT64);
405         break;
406       case G_TYPE_UINT64:
407         CONVERT_ARRAY (uint64, UINT64);
408         break;
409       case G_TYPE_FLOAT:
410         CONVERT_ARRAY (float, FLOAT);
411         break;
412       case G_TYPE_DOUBLE:
413         CONVERT_ARRAY (double, DOUBLE);
414         break;
415       case G_TYPE_BOOLEAN:
416         CONVERT_ARRAY (boolean, BOOLEAN);
417         break;
418       case G_TYPE_ENUM:
419       {
420         gint *v = g_new (gint, n_values);
421         ret = gst_control_binding_get_value_array (binding, timestamp, interval,
422             n_values, v);
423         if (ret) {
424           for (i = 0; i < n_values; i++) {
425             g_value_init (&values[i], type);
426             g_value_set_enum (&values[i], v[i]);
427           }
428         }
429         g_free (v);
430       }
431         break;
432       default:
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;
436         break;
437     }
438   }
439   return ret;
440 }
441
442 /**
443  * gst_control_binding_set_disabled:
444  * @binding: the control binding
445  * @disabled: boolean that specifies whether to disable the controller
446  * or not.
447  *
448  * This function is used to disable a control binding for some time, i.e.
449  * gst_object_sync_values() will do nothing.
450  */
451 void
452 gst_control_binding_set_disabled (GstControlBinding * binding,
453     gboolean disabled)
454 {
455   g_return_if_fail (GST_IS_CONTROL_BINDING (binding));
456   binding->disabled = disabled;
457 }
458
459 /**
460  * gst_control_binding_is_disabled:
461  * @binding: the control binding
462  *
463  * Check if the control binding is disabled.
464  *
465  * Returns: %TRUE if the binding is inactive
466  */
467 gboolean
468 gst_control_binding_is_disabled (GstControlBinding * binding)
469 {
470   g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), TRUE);
471   return (binding->disabled == TRUE);
472 }