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