3 * Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
5 * gstdirectcontrolbinding.c: Direct 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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 * SECTION:gstdirectcontrolbinding
24 * @short_description: direct attachment for control source sources
26 * A value mapping object that attaches control sources to gobject properties.
30 #include <glib-object.h>
33 #include "gstdirectcontrolbinding.h"
37 #define GST_CAT_DEFAULT control_binding_debug
38 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
40 static GObject *gst_direct_control_binding_constructor (GType type,
41 guint n_construct_params, GObjectConstructParam * construct_params);
42 static void gst_direct_control_binding_set_property (GObject * object,
43 guint prop_id, const GValue * value, GParamSpec * pspec);
44 static void gst_direct_control_binding_get_property (GObject * object,
45 guint prop_id, GValue * value, GParamSpec * pspec);
46 static void gst_direct_control_binding_dispose (GObject * object);
47 static void gst_direct_control_binding_finalize (GObject * object);
49 static gboolean gst_direct_control_binding_sync_values (GstControlBinding *
50 _self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync);
51 static GValue *gst_direct_control_binding_get_value (GstControlBinding * _self,
52 GstClockTime timestamp);
53 static gboolean gst_direct_control_binding_get_value_array (GstControlBinding *
54 _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
56 static gboolean gst_direct_control_binding_get_g_value_array (GstControlBinding
57 * _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
61 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstdirectcontrolbinding", 0, \
62 "dynamic parameter control source attachment");
64 #define gst_direct_control_binding_parent_class parent_class
65 G_DEFINE_TYPE_WITH_CODE (GstDirectControlBinding, gst_direct_control_binding,
66 GST_TYPE_CONTROL_BINDING, _do_init);
75 static GParamSpec *properties[PROP_LAST];
77 /* mapping functions */
79 #define DEFINE_CONVERT(type,Type,TYPE) \
81 convert_g_value_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
83 GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
86 s = CLAMP (s, 0.0, 1.0); \
87 v = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \
88 g_value_set_##type (d, v); \
92 convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_) \
94 GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
95 g##type *d = (g##type *)d_; \
97 s = CLAMP (s, 0.0, 1.0); \
98 *d = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \
102 DEFINE_CONVERT (int, Int, INT);
103 DEFINE_CONVERT (uint, UInt, UINT);
104 DEFINE_CONVERT (long, Long, LONG);
105 DEFINE_CONVERT (ulong, ULong, ULONG);
106 DEFINE_CONVERT (int64, Int64, INT64);
107 DEFINE_CONVERT (uint64, UInt64, UINT64);
108 DEFINE_CONVERT (float, Float, FLOAT);
109 DEFINE_CONVERT (double, Double, DOUBLE);
112 convert_g_value_to_boolean (GstDirectControlBinding * self, gdouble s,
115 s = CLAMP (s, 0.0, 1.0);
116 g_value_set_boolean (d, (gboolean) (s + 0.5));
120 convert_value_to_boolean (GstDirectControlBinding * self, gdouble s,
123 gboolean *d = (gboolean *) d_;
125 s = CLAMP (s, 0.0, 1.0);
126 *d = (gboolean) (s + 0.5);
130 convert_g_value_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
132 GParamSpecEnum *pspec =
133 G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
134 GEnumClass *e = pspec->enum_class;
137 s = CLAMP (s, 0.0, 1.0);
138 v = s * (e->n_values - 1);
139 g_value_set_enum (d, e->values[v].value);
143 convert_value_to_enum (GstDirectControlBinding * self, gdouble s, gpointer d_)
145 GParamSpecEnum *pspec =
146 G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
147 GEnumClass *e = pspec->enum_class;
148 gint *d = (gint *) d_;
150 s = CLAMP (s, 0.0, 1.0);
151 *d = e->values[(gint) (s * (e->n_values - 1))].value;
157 gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
159 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
160 GstControlBindingClass *control_binding_class =
161 GST_CONTROL_BINDING_CLASS (klass);
163 gobject_class->constructor = gst_direct_control_binding_constructor;
164 gobject_class->set_property = gst_direct_control_binding_set_property;
165 gobject_class->get_property = gst_direct_control_binding_get_property;
166 gobject_class->dispose = gst_direct_control_binding_dispose;
167 gobject_class->finalize = gst_direct_control_binding_finalize;
169 control_binding_class->sync_values = gst_direct_control_binding_sync_values;
170 control_binding_class->get_value = gst_direct_control_binding_get_value;
171 control_binding_class->get_value_array =
172 gst_direct_control_binding_get_value_array;
173 control_binding_class->get_g_value_array =
174 gst_direct_control_binding_get_g_value_array;
176 properties[PROP_CS] =
177 g_param_spec_object ("control-source", "ControlSource",
178 "The control source",
179 GST_TYPE_CONTROL_SOURCE,
180 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
182 g_object_class_install_properties (gobject_class, PROP_LAST, properties);
186 gst_direct_control_binding_init (GstDirectControlBinding * self)
191 gst_direct_control_binding_constructor (GType type, guint n_construct_params,
192 GObjectConstructParam * construct_params)
194 GstDirectControlBinding *self;
197 GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS (parent_class)->constructor
198 (type, n_construct_params, construct_params));
200 if (GST_CONTROL_BINDING_PSPEC (self)) {
203 base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (self));
204 g_value_init (&self->cur_value, type);
205 while ((type = g_type_parent (type)))
208 GST_DEBUG (" using type %s", g_type_name (base));
210 // select mapping function
213 self->convert_g_value = convert_g_value_to_int;
214 self->convert_value = convert_value_to_int;
215 self->byte_size = sizeof (gint);
218 self->convert_g_value = convert_g_value_to_uint;
219 self->convert_value = convert_value_to_uint;
220 self->byte_size = sizeof (guint);
223 self->convert_g_value = convert_g_value_to_long;
224 self->convert_value = convert_value_to_long;
225 self->byte_size = sizeof (glong);
228 self->convert_g_value = convert_g_value_to_ulong;
229 self->convert_value = convert_value_to_ulong;
230 self->byte_size = sizeof (gulong);
233 self->convert_g_value = convert_g_value_to_int64;
234 self->convert_value = convert_value_to_int64;
235 self->byte_size = sizeof (gint64);
238 self->convert_g_value = convert_g_value_to_uint64;
239 self->convert_value = convert_value_to_uint64;
240 self->byte_size = sizeof (guint64);
243 self->convert_g_value = convert_g_value_to_float;
244 self->convert_value = convert_value_to_float;
245 self->byte_size = sizeof (gfloat);
248 self->convert_g_value = convert_g_value_to_double;
249 self->convert_value = convert_value_to_double;
250 self->byte_size = sizeof (gdouble);
253 self->convert_g_value = convert_g_value_to_boolean;
254 self->convert_value = convert_value_to_boolean;
255 self->byte_size = sizeof (gboolean);
258 self->convert_g_value = convert_g_value_to_enum;
259 self->convert_value = convert_value_to_enum;
260 self->byte_size = sizeof (gint);
263 GST_WARNING ("incomplete implementation for paramspec type '%s'",
264 G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (self)));
265 GST_CONTROL_BINDING_PSPEC (self) = NULL;
269 return (GObject *) self;
273 gst_direct_control_binding_set_property (GObject * object, guint prop_id,
274 const GValue * value, GParamSpec * pspec)
276 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
280 self->cs = g_value_dup_object (value);
283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
289 gst_direct_control_binding_get_property (GObject * object, guint prop_id,
290 GValue * value, GParamSpec * pspec)
292 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
296 g_value_set_object (value, self->cs);
299 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
305 gst_direct_control_binding_dispose (GObject * object)
307 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
310 gst_object_replace ((GstObject **) & self->cs, NULL);
312 G_OBJECT_CLASS (parent_class)->dispose (object);
316 gst_direct_control_binding_finalize (GObject * object)
318 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
320 g_value_unset (&self->cur_value);
322 G_OBJECT_CLASS (parent_class)->finalize (object);
326 gst_direct_control_binding_sync_values (GstControlBinding * _self,
327 GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
329 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
333 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
334 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
336 GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT,
337 _self->name, GST_TIME_ARGS (timestamp));
339 ret = gst_control_source_get_value (self->cs, timestamp, &src_val);
340 if (G_LIKELY (ret)) {
341 GST_LOG_OBJECT (object, " new value %lf", src_val);
342 /* always set the value for first time, but then only if it changed
343 * this should limit g_object_notify invocations.
344 * FIXME: can we detect negative playback rates?
346 if ((timestamp < last_sync) || (src_val != self->last_value)) {
347 GValue *dst_val = &self->cur_value;
349 GST_LOG_OBJECT (object, " mapping %s to value of type %s", _self->name,
350 G_VALUE_TYPE_NAME (dst_val));
351 /* run mapping function to convert gdouble to GValue */
352 self->convert_g_value (self, src_val, dst_val);
353 /* we can make this faster
354 * http://bugzilla.gnome.org/show_bug.cgi?id=536939
356 g_object_set_property ((GObject *) object, _self->name, dst_val);
357 self->last_value = src_val;
360 GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name);
366 gst_direct_control_binding_get_value (GstControlBinding * _self,
367 GstClockTime timestamp)
369 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
370 GValue *dst_val = NULL;
373 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), NULL);
374 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
375 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
377 /* get current value via control source */
378 if (gst_control_source_get_value (self->cs, timestamp, &src_val)) {
379 dst_val = g_new0 (GValue, 1);
380 g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec));
381 self->convert_g_value (self, src_val, dst_val);
383 GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT,
384 _self->name, GST_TIME_ARGS (timestamp));
391 gst_direct_control_binding_get_value_array (GstControlBinding * _self,
392 GstClockTime timestamp, GstClockTime interval, guint n_values,
395 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
398 gboolean res = FALSE;
399 GstDirectControlBindingConvertValue convert;
401 guint8 *values = (guint8 *) values_;
403 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
404 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
405 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
406 g_return_val_if_fail (values, FALSE);
407 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
409 convert = self->convert_value;
410 byte_size = self->byte_size;
412 src_val = g_new0 (gdouble, n_values);
413 if ((res = gst_control_source_get_value_array (self->cs, timestamp,
414 interval, n_values, src_val))) {
415 for (i = 0; i < n_values; i++) {
416 if (!isnan (src_val[i])) {
417 convert (self, src_val[i], (gpointer) values);
419 GST_LOG ("no control value for property %s at index %d", _self->name,
425 GST_LOG ("failed to get control value for property %s at ts %"
426 GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
433 gst_direct_control_binding_get_g_value_array (GstControlBinding * _self,
434 GstClockTime timestamp, GstClockTime interval, guint n_values,
437 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
440 gboolean res = FALSE;
442 GstDirectControlBindingConvertGValue convert;
444 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
445 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
446 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
447 g_return_val_if_fail (values, FALSE);
448 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
450 convert = self->convert_g_value;
451 type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec);
453 src_val = g_new0 (gdouble, n_values);
454 if ((res = gst_control_source_get_value_array (self->cs, timestamp,
455 interval, n_values, src_val))) {
456 for (i = 0; i < n_values; i++) {
457 if (!isnan (src_val[i])) {
458 g_value_init (&values[i], type);
459 convert (self, src_val[i], &values[i]);
461 GST_LOG ("no control value for property %s at index %d", _self->name,
466 GST_LOG ("failed to get control value for property %s at ts %"
467 GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
476 * gst_direct_control_binding_new:
477 * @object: the object of the property
478 * @property_name: the property-name to attach the control source
479 * @csource: the control source
481 * Create a new control-binding that attaches the #GstControlSource to the
484 * Returns: (transfer floating): the new #GstDirectControlBinding
487 gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
488 GstControlSource * cs)
490 return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
491 "object", object, "name", property_name, "control-source", cs, NULL);