691655665882a9bd20dcef380ff7fc41cfaf1556
[platform/upstream/gstreamer.git] / libs / gst / controller / gstdirectcontrolbinding.c
1 /* GStreamer
2  *
3  * Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
4  *
5  * gstdirectcontrolbinding.c: Direct 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:gstdirectcontrolbinding
24  * @short_description: direct attachment for control sources
25  *
26  * A value mapping object that attaches control sources to gobject properties. It
27  * will map the control values [0.0 ... 1.0] to the target property range. If a
28  * control value is outside of the range, it will be clipped.
29  */
30
31 #include <glib-object.h>
32 #include <gst/gst.h>
33
34 #include "gstdirectcontrolbinding.h"
35
36 #include <gst/math-compat.h>
37
38 #define GST_CAT_DEFAULT control_binding_debug
39 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
40
41
42 static GObject *gst_direct_control_binding_constructor (GType type,
43     guint n_construct_params, GObjectConstructParam * construct_params);
44 static void gst_direct_control_binding_set_property (GObject * object,
45     guint prop_id, const GValue * value, GParamSpec * pspec);
46 static void gst_direct_control_binding_get_property (GObject * object,
47     guint prop_id, GValue * value, GParamSpec * pspec);
48 static void gst_direct_control_binding_dispose (GObject * object);
49 static void gst_direct_control_binding_finalize (GObject * object);
50
51 static gboolean gst_direct_control_binding_sync_values (GstControlBinding *
52     _self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync);
53 static GValue *gst_direct_control_binding_get_value (GstControlBinding * _self,
54     GstClockTime timestamp);
55 static gboolean gst_direct_control_binding_get_value_array (GstControlBinding *
56     _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
57     gpointer values);
58 static gboolean gst_direct_control_binding_get_g_value_array (GstControlBinding
59     * _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
60     GValue * values);
61
62 #define _do_init \
63   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstdirectcontrolbinding", 0, \
64       "dynamic parameter control source attachment");
65
66 #define gst_direct_control_binding_parent_class parent_class
67 G_DEFINE_TYPE_WITH_CODE (GstDirectControlBinding, gst_direct_control_binding,
68     GST_TYPE_CONTROL_BINDING, _do_init);
69
70 enum
71 {
72   PROP_0,
73   PROP_CS,
74   PROP_ABSOLUTE,
75   PROP_LAST
76 };
77
78 static GParamSpec *properties[PROP_LAST];
79
80 /* mapping functions */
81
82 #define DEFINE_CONVERT(type,Type,TYPE,ROUNDING_OP) \
83 static void \
84 convert_g_value_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
85 { \
86   GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
87   g##type v; \
88   \
89   s = CLAMP (s, 0.0, 1.0); \
90   v = (g##type) ROUNDING_OP (pspec->minimum * (1-s)) + (g##type) ROUNDING_OP (pspec->maximum * s); \
91   g_value_set_##type (d, v); \
92 } \
93 \
94 static void \
95 convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_) \
96 { \
97   GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
98   g##type *d = (g##type *)d_; \
99   \
100   s = CLAMP (s, 0.0, 1.0); \
101   *d = (g##type) ROUNDING_OP (pspec->minimum * (1-s)) + (g##type) ROUNDING_OP (pspec->maximum * s); \
102 } \
103 \
104 static void \
105 abs_convert_g_value_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
106 { \
107   g##type v; \
108   v = (g##type) ROUNDING_OP (s); \
109   g_value_set_##type (d, v); \
110 } \
111 \
112 static void \
113 abs_convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_) \
114 { \
115   g##type *d = (g##type *)d_; \
116   *d = (g##type) ROUNDING_OP (s); \
117 }
118
119 DEFINE_CONVERT (int, Int, INT, rint);
120 DEFINE_CONVERT (uint, UInt, UINT, rint);
121 DEFINE_CONVERT (long, Long, LONG, rint);
122 DEFINE_CONVERT (ulong, ULong, ULONG, rint);
123 DEFINE_CONVERT (int64, Int64, INT64, rint);
124 DEFINE_CONVERT (uint64, UInt64, UINT64, rint);
125 DEFINE_CONVERT (float, Float, FLOAT, /*NOOP*/);
126 DEFINE_CONVERT (double, Double, DOUBLE, /*NOOP*/);
127
128 static void
129 convert_g_value_to_boolean (GstDirectControlBinding * self, gdouble s,
130     GValue * d)
131 {
132   s = CLAMP (s, 0.0, 1.0);
133   g_value_set_boolean (d, (gboolean) (s + 0.5));
134 }
135
136 static void
137 convert_value_to_boolean (GstDirectControlBinding * self, gdouble s,
138     gpointer d_)
139 {
140   gboolean *d = (gboolean *) d_;
141
142   s = CLAMP (s, 0.0, 1.0);
143   *d = (gboolean) (s + 0.5);
144 }
145
146 static void
147 convert_g_value_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
148 {
149   GParamSpecEnum *pspec =
150       G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
151   GEnumClass *e = pspec->enum_class;
152   gint v;
153
154   s = CLAMP (s, 0.0, 1.0);
155   v = s * (e->n_values - 1);
156   g_value_set_enum (d, e->values[v].value);
157 }
158
159 static void
160 convert_value_to_enum (GstDirectControlBinding * self, gdouble s, gpointer d_)
161 {
162   GParamSpecEnum *pspec =
163       G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
164   GEnumClass *e = pspec->enum_class;
165   gint *d = (gint *) d_;
166
167   s = CLAMP (s, 0.0, 1.0);
168   *d = e->values[(gint) (s * (e->n_values - 1))].value;
169 }
170
171 /* vmethods */
172
173 static void
174 gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
175 {
176   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
177   GstControlBindingClass *control_binding_class =
178       GST_CONTROL_BINDING_CLASS (klass);
179
180   gobject_class->constructor = gst_direct_control_binding_constructor;
181   gobject_class->set_property = gst_direct_control_binding_set_property;
182   gobject_class->get_property = gst_direct_control_binding_get_property;
183   gobject_class->dispose = gst_direct_control_binding_dispose;
184   gobject_class->finalize = gst_direct_control_binding_finalize;
185
186   control_binding_class->sync_values = gst_direct_control_binding_sync_values;
187   control_binding_class->get_value = gst_direct_control_binding_get_value;
188   control_binding_class->get_value_array =
189       gst_direct_control_binding_get_value_array;
190   control_binding_class->get_g_value_array =
191       gst_direct_control_binding_get_g_value_array;
192
193   properties[PROP_CS] =
194       g_param_spec_object ("control-source", "ControlSource",
195       "The control source",
196       GST_TYPE_CONTROL_SOURCE,
197       G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
198
199   properties[PROP_ABSOLUTE] =
200       g_param_spec_boolean ("absolute", "Absolute",
201       "Whether the control values are absolute",
202       FALSE,
203       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
204
205   g_object_class_install_properties (gobject_class, PROP_LAST, properties);
206 }
207
208 static void
209 gst_direct_control_binding_init (GstDirectControlBinding * self)
210 {
211 }
212
213 static GObject *
214 gst_direct_control_binding_constructor (GType type, guint n_construct_params,
215     GObjectConstructParam * construct_params)
216 {
217   GstDirectControlBinding *self;
218
219   self =
220       GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS (parent_class)->constructor
221       (type, n_construct_params, construct_params));
222
223   if (GST_CONTROL_BINDING_PSPEC (self)) {
224     GType type, base;
225
226     base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (self));
227     g_value_init (&self->cur_value, type);
228     while ((type = g_type_parent (type)))
229       base = type;
230
231     GST_DEBUG ("  using type %s", g_type_name (base));
232
233     /* select mapping function */
234
235 #define SET_CONVERT_FUNCTION(type) \
236     if (self->want_absolute) { \
237         self->convert_g_value = abs_convert_g_value_to_##type; \
238         self->convert_value = abs_convert_value_to_##type; \
239     } \
240     else { \
241         self->convert_g_value = convert_g_value_to_##type; \
242         self->convert_value = convert_value_to_##type; \
243     } \
244     self->byte_size = sizeof (g##type);
245
246
247     switch (base) {
248       case G_TYPE_INT:
249         SET_CONVERT_FUNCTION (int);
250         break;
251       case G_TYPE_UINT:
252         SET_CONVERT_FUNCTION (uint);
253         break;
254       case G_TYPE_LONG:
255         SET_CONVERT_FUNCTION (long);
256         break;
257       case G_TYPE_ULONG:
258         SET_CONVERT_FUNCTION (ulong);
259         break;
260       case G_TYPE_INT64:
261         SET_CONVERT_FUNCTION (int64);
262         break;
263       case G_TYPE_UINT64:
264         SET_CONVERT_FUNCTION (uint64);
265         break;
266       case G_TYPE_FLOAT:
267         SET_CONVERT_FUNCTION (float);
268         break;
269       case G_TYPE_DOUBLE:
270         SET_CONVERT_FUNCTION (double);
271         break;
272       case G_TYPE_BOOLEAN:
273         self->convert_g_value = convert_g_value_to_boolean;
274         self->convert_value = convert_value_to_boolean;
275         self->byte_size = sizeof (gboolean);
276         break;
277       case G_TYPE_ENUM:
278         self->convert_g_value = convert_g_value_to_enum;
279         self->convert_value = convert_value_to_enum;
280         self->byte_size = sizeof (gint);
281         break;
282       default:
283         GST_WARNING ("incomplete implementation for paramspec type '%s'",
284             G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (self)));
285         GST_CONTROL_BINDING_PSPEC (self) = NULL;
286         break;
287     }
288   }
289   return (GObject *) self;
290 }
291
292 static void
293 gst_direct_control_binding_set_property (GObject * object, guint prop_id,
294     const GValue * value, GParamSpec * pspec)
295 {
296   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
297
298   switch (prop_id) {
299     case PROP_CS:
300       self->cs = g_value_dup_object (value);
301       break;
302     case PROP_ABSOLUTE:
303       self->want_absolute = g_value_get_boolean (value);
304       break;
305     default:
306       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307       break;
308   }
309 }
310
311 static void
312 gst_direct_control_binding_get_property (GObject * object, guint prop_id,
313     GValue * value, GParamSpec * pspec)
314 {
315   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
316
317   switch (prop_id) {
318     case PROP_CS:
319       g_value_set_object (value, self->cs);
320       break;
321     case PROP_ABSOLUTE:
322       g_value_set_boolean (value, self->want_absolute);
323       break;
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326       break;
327   }
328 }
329
330 static void
331 gst_direct_control_binding_dispose (GObject * object)
332 {
333   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
334
335   if (self->cs)
336     gst_object_replace ((GstObject **) & self->cs, NULL);
337
338   G_OBJECT_CLASS (parent_class)->dispose (object);
339 }
340
341 static void
342 gst_direct_control_binding_finalize (GObject * object)
343 {
344   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
345
346   g_value_unset (&self->cur_value);
347
348   G_OBJECT_CLASS (parent_class)->finalize (object);
349 }
350
351 static gboolean
352 gst_direct_control_binding_sync_values (GstControlBinding * _self,
353     GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
354 {
355   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
356   gdouble src_val;
357   gboolean ret;
358
359   g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
360   g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
361
362   GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT,
363       _self->name, GST_TIME_ARGS (timestamp));
364
365   ret = gst_control_source_get_value (self->cs, timestamp, &src_val);
366   if (G_LIKELY (ret)) {
367     GST_LOG_OBJECT (object, "  new value %lf", src_val);
368     /* always set the value for first time, but then only if it changed
369      * this should limit g_object_notify invocations.
370      * FIXME: can we detect negative playback rates?
371      */
372     if ((timestamp < last_sync) || (src_val != self->last_value)) {
373       GValue *dst_val = &self->cur_value;
374
375       GST_LOG_OBJECT (object, "  mapping %s to value of type %s", _self->name,
376           G_VALUE_TYPE_NAME (dst_val));
377       /* run mapping function to convert gdouble to GValue */
378       self->convert_g_value (self, src_val, dst_val);
379       /* we can make this faster
380        * http://bugzilla.gnome.org/show_bug.cgi?id=536939
381        */
382       g_object_set_property ((GObject *) object, _self->name, dst_val);
383       self->last_value = src_val;
384     }
385   } else {
386     GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name);
387   }
388   return (ret);
389 }
390
391 static GValue *
392 gst_direct_control_binding_get_value (GstControlBinding * _self,
393     GstClockTime timestamp)
394 {
395   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
396   GValue *dst_val = NULL;
397   gdouble src_val;
398
399   g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), NULL);
400   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
401   g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
402
403   /* get current value via control source */
404   if (gst_control_source_get_value (self->cs, timestamp, &src_val)) {
405     dst_val = g_new0 (GValue, 1);
406     g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec));
407     self->convert_g_value (self, src_val, dst_val);
408   } else {
409     GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT,
410         _self->name, GST_TIME_ARGS (timestamp));
411   }
412
413   return dst_val;
414 }
415
416 static gboolean
417 gst_direct_control_binding_get_value_array (GstControlBinding * _self,
418     GstClockTime timestamp, GstClockTime interval, guint n_values,
419     gpointer values_)
420 {
421   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
422   gint i;
423   gdouble *src_val;
424   gboolean res = FALSE;
425   GstDirectControlBindingConvertValue convert;
426   gint byte_size;
427   guint8 *values = (guint8 *) values_;
428
429   g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
430   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
431   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
432   g_return_val_if_fail (values, FALSE);
433   g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
434
435   convert = self->convert_value;
436   byte_size = self->byte_size;
437
438   src_val = g_new0 (gdouble, n_values);
439   if ((res = gst_control_source_get_value_array (self->cs, timestamp,
440               interval, n_values, src_val))) {
441     for (i = 0; i < n_values; i++) {
442       /* we will only get NAN for sparse control sources, such as triggers */
443       if (!isnan (src_val[i])) {
444         convert (self, src_val[i], (gpointer) values);
445       } else {
446         GST_LOG ("no control value for property %s at index %d", _self->name,
447             i);
448       }
449       values += byte_size;
450     }
451   } else {
452     GST_LOG ("failed to get control value for property %s at ts %"
453         GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
454   }
455   g_free (src_val);
456   return res;
457 }
458
459 static gboolean
460 gst_direct_control_binding_get_g_value_array (GstControlBinding * _self,
461     GstClockTime timestamp, GstClockTime interval, guint n_values,
462     GValue * values)
463 {
464   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
465   gint i;
466   gdouble *src_val;
467   gboolean res = FALSE;
468   GType type;
469   GstDirectControlBindingConvertGValue convert;
470
471   g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
472   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
473   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
474   g_return_val_if_fail (values, FALSE);
475   g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
476
477   convert = self->convert_g_value;
478   type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec);
479
480   src_val = g_new0 (gdouble, n_values);
481   if ((res = gst_control_source_get_value_array (self->cs, timestamp,
482               interval, n_values, src_val))) {
483     for (i = 0; i < n_values; i++) {
484       /* we will only get NAN for sparse control sources, such as triggers */
485       if (!isnan (src_val[i])) {
486         g_value_init (&values[i], type);
487         convert (self, src_val[i], &values[i]);
488       } else {
489         GST_LOG ("no control value for property %s at index %d", _self->name,
490             i);
491       }
492     }
493   } else {
494     GST_LOG ("failed to get control value for property %s at ts %"
495         GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
496   }
497   g_free (src_val);
498   return res;
499 }
500
501 /* functions */
502
503 /**
504  * gst_direct_control_binding_new:
505  * @object: the object of the property
506  * @property_name: the property-name to attach the control source
507  * @cs: the control source
508  *
509  * Create a new control-binding that attaches the #GstControlSource to the
510  * #GObject property.
511  *
512  * Returns: (transfer floating): the new #GstDirectControlBinding
513  */
514 GstControlBinding *
515 gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
516     GstControlSource * cs)
517 {
518   return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
519       "object", object, "name", property_name, "control-source", cs, NULL);
520 }
521
522 /**
523  * gst_direct_control_binding_new_absolute:
524  * @object: the object of the property
525  * @property_name: the property-name to attach the control source
526  * @cs: the control source
527  *
528  * Create a new control-binding that attaches the #GstControlSource to the
529  * #GObject property.
530  *
531  * Returns: (transfer floating): the new #GstDirectControlBinding
532  *
533  * Since: 1.6
534  */
535 GstControlBinding *
536 gst_direct_control_binding_new_absolute (GstObject * object,
537     const gchar * property_name, GstControlSource * cs)
538 {
539   return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
540       "object", object, "name", property_name, "control-source", cs, "absolute",
541       TRUE, NULL);
542 }