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,
58 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstdirectcontrolbinding", 0, \
59 "dynamic parameter control source attachment");
61 G_DEFINE_TYPE_WITH_CODE (GstDirectControlBinding, gst_direct_control_binding,
62 GST_TYPE_CONTROL_BINDING, _do_init);
71 static GParamSpec *properties[PROP_LAST];
73 /* mapping functions */
75 #define DEFINE_CONVERT(type,Type,TYPE) \
77 convert_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
79 GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
82 s = CLAMP (s, 0.0, 1.0); \
83 v = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \
84 g_value_set_##type (d, v); \
87 DEFINE_CONVERT (int, Int, INT);
88 DEFINE_CONVERT (uint, UInt, UINT);
89 DEFINE_CONVERT (long, Long, LONG);
90 DEFINE_CONVERT (ulong, ULong, ULONG);
91 DEFINE_CONVERT (int64, Int64, INT64);
92 DEFINE_CONVERT (uint64, UInt64, UINT64);
93 DEFINE_CONVERT (float, Float, FLOAT);
94 DEFINE_CONVERT (double, Double, DOUBLE);
97 convert_to_boolean (GstDirectControlBinding * self, gdouble s, GValue * d)
99 s = CLAMP (s, 0.0, 1.0);
100 g_value_set_boolean (d, (gboolean) (s + 0.5));
104 convert_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
106 GParamSpecEnum *pspec =
107 G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
108 GEnumClass *e = pspec->enum_class;
111 s = CLAMP (s, 0.0, 1.0);
112 v = s * (e->n_values - 1);
113 g_value_set_enum (d, e->values[v].value);
119 gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
121 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
122 GstControlBindingClass *control_binding_class =
123 GST_CONTROL_BINDING_CLASS (klass);
125 gobject_class->constructor = gst_direct_control_binding_constructor;
126 gobject_class->set_property = gst_direct_control_binding_set_property;
127 gobject_class->get_property = gst_direct_control_binding_get_property;
128 gobject_class->dispose = gst_direct_control_binding_dispose;
129 gobject_class->finalize = gst_direct_control_binding_finalize;
131 control_binding_class->sync_values = gst_direct_control_binding_sync_values;
132 control_binding_class->get_value = gst_direct_control_binding_get_value;
133 control_binding_class->get_value_array =
134 gst_direct_control_binding_get_value_array;
136 properties[PROP_CS] =
137 g_param_spec_object ("control-source", "ControlSource",
138 "The control source",
139 GST_TYPE_CONTROL_SOURCE,
140 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
142 g_object_class_install_properties (gobject_class, PROP_LAST, properties);
146 gst_direct_control_binding_init (GstDirectControlBinding * self)
151 gst_direct_control_binding_constructor (GType type, guint n_construct_params,
152 GObjectConstructParam * construct_params)
154 GstDirectControlBinding *self;
157 GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS
158 (gst_direct_control_binding_parent_class)
159 ->constructor (type, n_construct_params, construct_params));
161 if (GST_CONTROL_BINDING_PSPEC (self)) {
164 base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (self));
165 g_value_init (&self->cur_value, type);
166 while ((type = g_type_parent (type)))
169 GST_DEBUG (" using type %s", g_type_name (base));
171 // select mapping function
174 self->convert = convert_to_int;
177 self->convert = convert_to_uint;
180 self->convert = convert_to_long;
183 self->convert = convert_to_ulong;
186 self->convert = convert_to_int64;
189 self->convert = convert_to_uint64;
192 self->convert = convert_to_float;
195 self->convert = convert_to_double;
198 self->convert = convert_to_boolean;
201 self->convert = convert_to_enum;
204 GST_WARNING ("incomplete implementation for paramspec type '%s'",
205 G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (self)));
206 GST_CONTROL_BINDING_PSPEC (self) = NULL;
210 return (GObject *) self;
214 gst_direct_control_binding_set_property (GObject * object, guint prop_id,
215 const GValue * value, GParamSpec * pspec)
217 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
221 self->cs = g_value_dup_object (value);
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230 gst_direct_control_binding_get_property (GObject * object, guint prop_id,
231 GValue * value, GParamSpec * pspec)
233 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
237 g_value_set_object (value, self->cs);
240 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
246 gst_direct_control_binding_dispose (GObject * object)
248 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
251 gst_object_replace ((GstObject **) & self->cs, NULL);
255 gst_direct_control_binding_finalize (GObject * object)
257 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
259 g_value_unset (&self->cur_value);
263 gst_direct_control_binding_sync_values (GstControlBinding * _self,
264 GstObject * object, GstClockTime timestamp, GstClockTime last_sync)
266 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
270 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
271 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
273 GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT,
274 _self->name, GST_TIME_ARGS (timestamp));
276 ret = gst_control_source_get_value (self->cs, timestamp, &src_val);
277 if (G_LIKELY (ret)) {
278 GST_LOG_OBJECT (object, " new value %lf", src_val);
279 /* always set the value for first time, but then only if it changed
280 * this should limit g_object_notify invocations.
281 * FIXME: can we detect negative playback rates?
283 if ((timestamp < last_sync) || (src_val != self->last_value)) {
284 GValue *dst_val = &self->cur_value;
286 GST_LOG_OBJECT (object, " mapping %s to value of type %s", _self->name,
287 G_VALUE_TYPE_NAME (dst_val));
288 /* run mapping function to convert gdouble to GValue */
289 self->convert (self, src_val, dst_val);
290 /* we can make this faster
291 * http://bugzilla.gnome.org/show_bug.cgi?id=536939
293 g_object_set_property ((GObject *) object, _self->name, dst_val);
294 self->last_value = src_val;
297 GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name);
303 gst_direct_control_binding_get_value (GstControlBinding * _self,
304 GstClockTime timestamp)
306 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
307 GValue *dst_val = NULL;
310 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), NULL);
311 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
312 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
314 /* get current value via control source */
315 if (gst_control_source_get_value (self->cs, timestamp, &src_val)) {
316 dst_val = g_new0 (GValue, 1);
317 g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec));
318 self->convert (self, src_val, dst_val);
320 GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT,
321 _self->name, GST_TIME_ARGS (timestamp));
328 gst_direct_control_binding_get_value_array (GstControlBinding * _self,
329 GstClockTime timestamp, GstClockTime interval, guint n_values,
332 GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
335 gboolean res = FALSE;
337 GstDirectControlBindingConvert convert;
339 g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
340 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
341 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
342 g_return_val_if_fail (values, FALSE);
343 g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
345 convert = self->convert;
346 type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec);
348 src_val = g_new0 (gdouble, n_values);
349 if ((res = gst_control_source_get_value_array (self->cs, timestamp,
350 interval, n_values, src_val))) {
351 for (i = 0; i < n_values; i++) {
352 if (!isnan (src_val[i])) {
353 g_value_init (&values[i], type);
354 convert (self, src_val[i], &values[i]);
356 GST_LOG ("no control value for property %s at index %d", _self->name,
361 GST_LOG ("failed to get control value for property %s at ts %"
362 GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
371 * gst_direct_control_binding_new:
372 * @object: the object of the property
373 * @property_name: the property-name to attach the control source
374 * @csource: the control source
376 * Create a new control-binding that attaches the #GstControlSource to the
379 * Returns: (transfer floating): the new #GstDirectControlBinding
382 gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
383 GstControlSource * cs)
385 return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
386 "object", object, "name", property_name, "control-source", cs, NULL);