3df8f979a859e97ce95b5de38c9c5f2566f0019f
1 /* GStreamer
2 *
3 * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
4 * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
5 *
6 * gstcontroller.c: dynamic parameter control subsystem
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
24 /**
25 * SECTION:gstcontroller
26 * @short_description: dynamic parameter control subsystem
27 *
28 * The controller subsystem offers a lightweight way to adjust gobject
29 * properties over stream-time. It works by using time-stamped value pairs that
30 * are queued for element-properties. At run-time the elements continously pull
31 * values changes for the current stream-time.
32 *
33 * What needs to be changed in a #GstElement?
34 * Very little - it is just two steps to make a plugin controllable!
35 * <orderedlist>
36 * <listitem><para>
37 * mark gobject-properties paramspecs that make sense to be controlled,
38 * by GST_PARAM_CONTROLLABLE.
39 * </para></listitem>
40 * <listitem><para>
41 * when processing data (get, chain, loop function) at the beginning call
42 * gst_object_sync_values(element,timestamp).
43 * This will made the controller to update all gobject properties that are under
44 * control with the current values based on timestamp.
45 * </para></listitem>
46 * </orderedlist>
47 *
48 * What needs to be done in applications?
49 * Again its not a lot to change.
50 * <orderedlist>
51 * <listitem><para>
52 * first put some properties under control, by calling
53 * controller = g_object_control_properties(object, "prop1", "prop2",...);
54 * </para></listitem>
55 * <listitem><para>
56 * Get a #GstControlSource for the property and set it up.
57 * csource = gst_interpolation_control_source_new ();
58 * gst_interpolation_control_source_set_interpolation_mode(csource, mode);
59 * gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
60 * gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
61 * </para></listitem>
62 * <listitem><para>
63 * Set the #GstControlSource in the controller.
64 * gst_controller_set_control_source (controller, "prop1", csource);
65 * </para></listitem>
66 * <listitem><para>
67 * start your pipeline
68 * </para></listitem>
69 * </orderedlist>
70 */
72 #ifdef HAVE_CONFIG_H
73 # include "config.h"
74 #endif
76 #include "gstcontroller.h"
77 #include "gstcontrollerprivate.h"
78 #include "gstcontrolsource.h"
79 #include "gstinterpolationcontrolsource.h"
81 #define GST_CAT_DEFAULT gst_controller_debug
82 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
84 static GObjectClass *parent_class = NULL;
85 GQuark __gst_controller_key;
87 /* property ids */
88 enum
89 {
90 PROP_CONTROL_RATE = 1
91 };
93 struct _GstControllerPrivate
94 {
95 GstClockTime control_rate;
96 GstClockTime last_sync;
97 };
99 /* helper */
101 static void
102 gst_controlled_property_add_interpolation_control_source (GstControlledProperty
103 * self)
104 {
105 GstControlSource *csource =
106 GST_CONTROL_SOURCE (gst_interpolation_control_source_new ());
108 GST_INFO
109 ("Adding a GstInterpolationControlSource because of backward compatibility");
110 g_return_if_fail (!self->csource);
111 gst_control_source_bind (GST_CONTROL_SOURCE (csource), self->pspec);
112 self->csource = csource;
113 }
115 /*
116 * gst_controlled_property_new:
117 * @object: for which object the controlled property should be set up
118 * @name: the name of the property to be controlled
119 *
120 * Private method which initializes the fields of a new controlled property
121 * structure.
122 *
123 * Returns: a freshly allocated structure or %NULL
124 */
125 static GstControlledProperty *
126 gst_controlled_property_new (GObject * object, const gchar * name)
127 {
128 GstControlledProperty *prop = NULL;
129 GParamSpec *pspec;
131 GST_INFO ("trying to put property '%s' under control", name);
133 /* check if the object has a property of that name */
134 if ((pspec =
135 g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
136 GST_DEBUG (" psec->flags : 0x%08x", pspec->flags);
138 /* check if this param is witable */
139 g_return_val_if_fail ((pspec->flags & G_PARAM_WRITABLE), NULL);
140 /* check if property is controlable */
141 g_return_val_if_fail ((pspec->flags & GST_PARAM_CONTROLLABLE), NULL);
142 /* check if this param is not construct-only */
143 g_return_val_if_fail (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY), NULL);
145 if ((prop = g_new0 (GstControlledProperty, 1))) {
146 prop->pspec = pspec;
147 prop->name = pspec->name;
148 prop->disabled = FALSE;
149 }
150 } else {
151 GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
152 name);
153 }
154 return prop;
155 }
157 /*
158 * gst_controlled_property_free:
159 * @prop: the object to free
160 *
161 * Private method which frees all data allocated by a #GstControlledProperty
162 * instance.
163 */
164 static void
165 gst_controlled_property_free (GstControlledProperty * prop)
166 {
167 if (prop->csource)
168 g_object_unref (prop->csource);
169 g_free (prop);
170 }
172 /*
173 * gst_controller_find_controlled_property:
174 * @self: the controller object to search for a property in
175 * @name: the gobject property name to look for
176 *
177 * Searches the list of properties under control.
178 *
179 * Returns: a #GstControlledProperty object of %NULL if the property is not
180 * being controlled.
181 */
182 static GstControlledProperty *
183 gst_controller_find_controlled_property (GstController * self,
184 const gchar * name)
185 {
186 GstControlledProperty *prop;
187 GList *node;
189 for (node = self->properties; node; node = g_list_next (node)) {
190 prop = node->data;
191 if (!strcmp (prop->name, name)) {
192 return prop;
193 }
194 }
195 GST_DEBUG ("controller does not (yet) manage property '%s'", name);
197 return NULL;
198 }
200 /* methods */
202 /**
203 * gst_controller_new_valist:
204 * @object: the object of which some properties should be controlled
205 * @var_args: %NULL terminated list of property names that should be controlled
206 *
207 * Creates a new GstController for the given object's properties
208 *
209 * Returns: the new controller.
210 */
211 GstController *
212 gst_controller_new_valist (GObject * object, va_list var_args)
213 {
214 GstController *self;
215 GstControlledProperty *prop;
216 gboolean ref_existing = TRUE;
217 gchar *name;
219 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
221 GST_INFO ("setting up a new controller");
223 self = g_object_get_qdata (object, __gst_controller_key);
224 /* create GstControlledProperty for each property */
225 while ((name = va_arg (var_args, gchar *))) {
226 /* test if this property isn't yet controlled */
227 if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
228 /* create GstControlledProperty and add to self->propeties List */
229 if ((prop = gst_controlled_property_new (object, name))) {
230 /* if we don't have a controller object yet, now is the time to create one */
231 if (!self) {
232 self = g_object_new (GST_TYPE_CONTROLLER, NULL);
233 self->object = g_object_ref (object);
234 /* store the controller */
235 g_object_set_qdata (object, __gst_controller_key, self);
236 ref_existing = FALSE;
237 } else {
238 /* only want one single _ref(), even for multiple properties */
239 if (ref_existing) {
240 g_object_ref (self);
241 ref_existing = FALSE;
242 GST_INFO ("returning existing controller");
243 }
244 }
245 self->properties = g_list_prepend (self->properties, prop);
246 }
247 } else {
248 GST_WARNING ("trying to control property again");
249 if (ref_existing) {
250 g_object_ref (self);
251 ref_existing = FALSE;
252 }
253 }
254 }
255 va_end (var_args);
257 if (self)
258 GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
259 return self;
260 }
262 /**
263 * gst_controller_new_list:
264 * @object: the object of which some properties should be controlled
265 * @list: list of property names that should be controlled
266 *
267 * Creates a new GstController for the given object's properties
268 *
269 * Returns: the new controller.
270 */
271 GstController *
272 gst_controller_new_list (GObject * object, GList * list)
273 {
274 GstController *self;
275 GstControlledProperty *prop;
276 gboolean ref_existing = TRUE;
277 gchar *name;
278 GList *node;
280 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
282 GST_INFO ("setting up a new controller");
284 self = g_object_get_qdata (object, __gst_controller_key);
285 /* create GstControlledProperty for each property */
286 for (node = list; node; node = g_list_next (node)) {
287 name = (gchar *) node->data;
288 /* test if this property isn't yet controlled */
289 if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
290 /* create GstControlledProperty and add to self->propeties List */
291 if ((prop = gst_controlled_property_new (object, name))) {
292 /* if we don't have a controller object yet, now is the time to create one */
293 if (!self) {
294 self = g_object_new (GST_TYPE_CONTROLLER, NULL);
295 self->object = g_object_ref (object);
296 /* store the controller */
297 g_object_set_qdata (object, __gst_controller_key, self);
298 ref_existing = FALSE;
299 } else {
300 /* only want one single _ref(), even for multiple properties */
301 if (ref_existing) {
302 g_object_ref (self);
303 ref_existing = FALSE;
304 GST_INFO ("returning existing controller");
305 }
306 }
307 self->properties = g_list_prepend (self->properties, prop);
308 }
309 } else {
310 GST_WARNING ("trying to control property again");
311 if (ref_existing) {
312 g_object_ref (self);
313 ref_existing = FALSE;
314 }
315 }
316 }
318 if (self)
319 GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
320 return self;
321 }
323 /**
324 * gst_controller_new:
325 * @object: the object of which some properties should be controlled
326 * @...: %NULL terminated list of property names that should be controlled
327 *
328 * Creates a new GstController for the given object's properties
329 *
330 * Returns: the new controller.
331 */
332 GstController *
333 gst_controller_new (GObject * object, ...)
334 {
335 GstController *self;
336 va_list var_args;
338 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
340 va_start (var_args, object);
341 self = gst_controller_new_valist (object, var_args);
342 va_end (var_args);
344 return self;
345 }
347 /**
348 * gst_controller_remove_properties_valist:
349 * @self: the controller object from which some properties should be removed
350 * @var_args: %NULL terminated list of property names that should be removed
351 *
352 * Removes the given object properties from the controller
353 *
354 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
355 */
356 gboolean
357 gst_controller_remove_properties_valist (GstController * self, va_list var_args)
358 {
359 gboolean res = TRUE;
360 GstControlledProperty *prop;
361 gchar *name;
363 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
365 while ((name = va_arg (var_args, gchar *))) {
366 /* find the property in the properties list of the controller, remove and free it */
367 g_mutex_lock (self->lock);
368 if ((prop = gst_controller_find_controlled_property (self, name))) {
369 self->properties = g_list_remove (self->properties, prop);
370 //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
371 gst_controlled_property_free (prop);
372 } else {
373 res = FALSE;
374 }
375 g_mutex_unlock (self->lock);
376 }
378 return res;
379 }
381 /**
382 * gst_controller_remove_properties_list:
383 * @self: the controller object from which some properties should be removed
384 * @list: #GList of property names that should be removed
385 *
386 * Removes the given object properties from the controller
387 *
388 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
389 */
390 gboolean
391 gst_controller_remove_properties_list (GstController * self, GList * list)
392 {
393 gboolean res = TRUE;
394 GstControlledProperty *prop;
395 gchar *name;
396 GList *tmp;
398 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
400 for (tmp = list; tmp; tmp = g_list_next (tmp)) {
401 name = (gchar *) tmp->data;
403 /* find the property in the properties list of the controller, remove and free it */
404 g_mutex_lock (self->lock);
405 if ((prop = gst_controller_find_controlled_property (self, name))) {
406 self->properties = g_list_remove (self->properties, prop);
407 //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
408 gst_controlled_property_free (prop);
409 } else {
410 res = FALSE;
411 }
412 g_mutex_unlock (self->lock);
413 }
415 return res;
416 }
418 /**
419 * gst_controller_remove_properties:
420 * @self: the controller object from which some properties should be removed
421 * @...: %NULL terminated list of property names that should be removed
422 *
423 * Removes the given object properties from the controller
424 *
425 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
426 */
427 gboolean
428 gst_controller_remove_properties (GstController * self, ...)
429 {
430 gboolean res;
431 va_list var_args;
433 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
435 va_start (var_args, self);
436 res = gst_controller_remove_properties_valist (self, var_args);
437 va_end (var_args);
439 return res;
440 }
442 /**
443 * gst_controller_set_property_disabled:
444 * @self: the #GstController which should be disabled
445 * @property_name: property to disable
446 * @disabled: boolean that specifies whether to disable the controller
447 * or not.
448 *
449 * This function is used to disable the #GstController on a property for
450 * some time, i.e. gst_controller_sync_values() will do nothing for the
451 * property.
452 *
453 * Since: 0.10.14
454 */
456 void
457 gst_controller_set_property_disabled (GstController * self,
458 gchar * property_name, gboolean disabled)
459 {
460 GstControlledProperty *prop;
462 g_return_if_fail (GST_IS_CONTROLLER (self));
463 g_return_if_fail (property_name);
465 g_mutex_lock (self->lock);
466 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
467 prop->disabled = disabled;
468 }
469 g_mutex_unlock (self->lock);
470 }
473 /**
474 * gst_controller_set_disabled:
475 * @self: the #GstController which should be disabled
476 * @disabled: boolean that specifies whether to disable the controller
477 * or not.
478 *
479 * This function is used to disable all properties of the #GstController
480 * for some time, i.e. gst_controller_sync_values() will do nothing.
481 *
482 * Since: 0.10.14
483 */
485 void
486 gst_controller_set_disabled (GstController * self, gboolean disabled)
487 {
488 GList *node;
489 GstControlledProperty *prop;
491 g_return_if_fail (GST_IS_CONTROLLER (self));
493 g_mutex_lock (self->lock);
494 for (node = self->properties; node; node = node->next) {
495 prop = node->data;
496 prop->disabled = disabled;
497 }
498 g_mutex_unlock (self->lock);
499 }
501 /**
502 * gst_controller_set_control_source:
503 * @self: the controller object
504 * @property_name: name of the property for which the #GstControlSource should be set
505 * @csource: the #GstControlSource that should be used for the property
506 *
507 * Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
508 * for this property it will be unreferenced.
509 *
510 * Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
511 * couldn't be bound to the property, %TRUE if everything worked as expected.
512 *
513 * Since: 0.10.14
514 */
515 gboolean
516 gst_controller_set_control_source (GstController * self, gchar * property_name,
517 GstControlSource * csource)
518 {
519 GstControlledProperty *prop;
520 gboolean ret = FALSE;
522 g_mutex_lock (self->lock);
523 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
524 GstControlSource *old = prop->csource;
526 if (csource && (ret = gst_control_source_bind (csource, prop->pspec))) {
527 g_object_ref (csource);
528 prop->csource = csource;
529 } else if (!csource) {
530 ret = TRUE;
531 prop->csource = NULL;
532 }
534 if (ret && old)
535 g_object_unref (old);
536 }
537 g_mutex_unlock (self->lock);
539 return ret;
540 }
542 /**
543 * gst_controller_get_control_source:
544 * @self: the controller object
545 * @property_name: name of the property for which the #GstControlSource should be get
546 *
547 * Gets the corresponding #GstControlSource for the property. This should be unreferenced
548 * again after use.
549 *
550 * Returns: the #GstControlSource for @property_name or NULL if the property is not
551 * controlled by this controller or no #GstControlSource was assigned yet.
552 *
553 * Since: 0.10.14
554 */
555 GstControlSource *
556 gst_controller_get_control_source (GstController * self, gchar * property_name)
557 {
558 GstControlledProperty *prop;
559 GstControlSource *ret = NULL;
561 g_mutex_lock (self->lock);
562 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
563 ret = prop->csource;
564 }
565 g_mutex_unlock (self->lock);
567 if (ret)
568 g_object_ref (ret);
570 return ret;
571 }
573 /**
574 * gst_controller_get:
575 * @self: the controller object which handles the properties
576 * @property_name: the name of the property to get
577 * @timestamp: the time the control-change should be read from
578 *
579 * Gets the value for the given controller-handled property at the requested
580 * time.
581 *
582 * Returns: the GValue of the property at the given time, or %NULL if the property isn't handled by the controller
583 */
584 GValue *
585 gst_controller_get (GstController * self, gchar * property_name,
586 GstClockTime timestamp)
587 {
588 GstControlledProperty *prop;
589 GValue *val = NULL;
591 g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
592 g_return_val_if_fail (property_name, NULL);
593 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
595 g_mutex_lock (self->lock);
596 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
597 val = g_new0 (GValue, 1);
598 g_value_init (val, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
599 if (prop->csource) {
600 gboolean res;
602 /* get current value via control source */
603 res = gst_control_source_get_value (prop->csource, timestamp, val);
604 if (!res) {
605 g_free (val);
606 val = FALSE;
607 }
608 } else {
609 g_object_get_property (self->object, prop->name, val);
610 }
611 }
612 g_mutex_unlock (self->lock);
614 return val;
615 }
617 /**
618 * gst_controller_suggest_next_sync:
619 * @self: the controller that handles the values
620 *
621 * Returns a suggestion for timestamps where buffers should be split
622 * to get best controller results.
623 *
624 * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
625 * if no control-rate was set.
626 *
627 * Since: 0.10.13
628 */
629 GstClockTime
630 gst_controller_suggest_next_sync (GstController * self)
631 {
632 GstClockTime ret;
634 g_return_val_if_fail (GST_IS_CONTROLLER (self), GST_CLOCK_TIME_NONE);
635 g_return_val_if_fail (self->priv->control_rate != GST_CLOCK_TIME_NONE,
636 GST_CLOCK_TIME_NONE);
638 g_mutex_lock (self->lock);
640 /* TODO: Implement more logic, depending on interpolation mode
641 * and control points */
642 ret = self->priv->last_sync + self->priv->control_rate;
644 g_mutex_unlock (self->lock);
646 return ret;
647 }
649 /**
650 * gst_controller_sync_values:
651 * @self: the controller that handles the values
652 * @timestamp: the time that should be processed
653 *
654 * Sets the properties of the element, according to the controller that (maybe)
655 * handles them and for the given timestamp.
656 *
657 * Returns: %TRUE if the controller values could be applied to the object
658 * properties, %FALSE otherwise
659 */
660 gboolean
661 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
662 {
663 GstControlledProperty *prop;
664 GList *node;
665 gboolean ret = FALSE;
667 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
668 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
670 GST_LOG ("sync_values");
672 g_mutex_lock (self->lock);
673 /* go over the controlled properties of the controller */
674 for (node = self->properties; node; node = g_list_next (node)) {
675 GValue value = { 0, };
676 prop = node->data;
678 GST_DEBUG (" property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
679 timestamp);
681 if (!prop->csource || prop->disabled)
682 continue;
684 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
685 ret = gst_control_source_get_value (prop->csource, timestamp, &value);
686 if (ret) {
687 g_object_set_property (self->object, prop->name, &value);
688 g_value_unset (&value);
689 }
690 }
691 self->priv->last_sync = timestamp;
693 g_mutex_unlock (self->lock);
695 return ret;
696 }
698 /**
699 * gst_controller_get_value_arrays:
700 * @self: the controller that handles the values
701 * @timestamp: the time that should be processed
702 * @value_arrays: list to return the control-values in
703 *
704 * Function to be able to get an array of values for one or more given element
705 * properties.
706 *
707 * All fields of the %GstValueArray in the list must be filled correctly.
708 * Especially the GstValueArray->values arrays must be big enough to keep
709 * the requested amount of values.
710 *
711 * The types of the values in the array are the same as the property's type.
712 *
713 * <note><para>This doesn't modify the controlled GObject properties!</para></note>
714 *
715 * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
716 */
717 gboolean
718 gst_controller_get_value_arrays (GstController * self,
719 GstClockTime timestamp, GSList * value_arrays)
720 {
721 gboolean res = TRUE;
722 GSList *node;
724 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
725 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
726 g_return_val_if_fail (value_arrays, FALSE);
728 for (node = value_arrays; (res && node); node = g_slist_next (node)) {
729 res = gst_controller_get_value_array (self, timestamp, node->data);
730 }
732 return (res);
733 }
735 /**
736 * gst_controller_get_value_array:
737 * @self: the controller that handles the values
738 * @timestamp: the time that should be processed
739 * @value_array: array to put control-values in
740 *
741 * Function to be able to get an array of values for one element property.
742 *
743 * All fields of @value_array must be filled correctly. Especially the
744 * @value_array->values array must be big enough to keep the requested amount
745 * of values.
746 *
747 * The type of the values in the array is the same as the property's type.
748 *
749 * <note><para>This doesn't modify the controlled GObject property!</para></note>
750 *
751 * Returns: %TRUE if the given array could be filled, %FALSE otherwise
752 */
753 gboolean
754 gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
755 GstValueArray * value_array)
756 {
757 gboolean res = FALSE;
758 GstControlledProperty *prop;
760 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
761 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
762 g_return_val_if_fail (value_array, FALSE);
763 g_return_val_if_fail (value_array->property_name, FALSE);
764 g_return_val_if_fail (value_array->values, FALSE);
766 g_mutex_lock (self->lock);
768 if ((prop =
769 gst_controller_find_controlled_property (self,
770 value_array->property_name))) {
771 /* get current value_array via control source */
773 if (!prop->csource)
774 goto out;
776 res =
777 gst_control_source_get_value_array (prop->csource, timestamp,
778 value_array);
779 }
781 out:
782 g_mutex_unlock (self->lock);
783 return res;
784 }
786 /* gobject handling */
788 static void
789 _gst_controller_get_property (GObject * object, guint property_id,
790 GValue * value, GParamSpec * pspec)
791 {
792 GstController *self = GST_CONTROLLER (object);
794 switch (property_id) {
795 case PROP_CONTROL_RATE:{
796 /* FIXME: don't change if element is playing, controller works for GObject
797 so this wont work
799 GstState c_state, p_state;
800 GstStateChangeReturn ret;
802 ret = gst_element_get_state (self->object, &c_state, &p_state, 0);
803 if ((ret == GST_STATE_CHANGE_SUCCESS &&
804 (c_state == GST_STATE_NULL || c_state == GST_STATE_READY)) ||
805 (ret == GST_STATE_CHANGE_ASYNC &&
806 (p_state == GST_STATE_NULL || p_state == GST_STATE_READY))) {
807 */
808 g_value_set_uint64 (value, self->priv->control_rate);
809 /*
810 }
811 else {
812 GST_WARNING ("Changing the control rate is only allowed if the elemnt"
813 " is in NULL or READY");
814 }
815 */
816 }
817 break;
818 default:{
819 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
820 }
821 break;
822 }
823 }
825 /* sets the given properties for this object */
826 static void
827 _gst_controller_set_property (GObject * object, guint property_id,
828 const GValue * value, GParamSpec * pspec)
829 {
830 GstController *self = GST_CONTROLLER (object);
832 switch (property_id) {
833 case PROP_CONTROL_RATE:{
834 self->priv->control_rate = g_value_get_uint64 (value);
835 }
836 break;
837 default:{
838 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
839 }
840 break;
841 }
842 }
844 static void
845 _gst_controller_dispose (GObject * object)
846 {
847 GstController *self = GST_CONTROLLER (object);
849 if (self->object != NULL) {
850 g_mutex_lock (self->lock);
851 /* free list of properties */
852 if (self->properties) {
853 GList *node;
855 for (node = self->properties; node; node = g_list_next (node)) {
856 GstControlledProperty *prop = node->data;
858 gst_controlled_property_free (prop);
859 }
860 g_list_free (self->properties);
861 self->properties = NULL;
862 }
864 /* remove controller from object's qdata list */
865 g_object_set_qdata (self->object, __gst_controller_key, NULL);
866 g_object_unref (self->object);
867 self->object = NULL;
868 g_mutex_unlock (self->lock);
869 }
871 if (G_OBJECT_CLASS (parent_class)->dispose)
872 (G_OBJECT_CLASS (parent_class)->dispose) (object);
873 }
875 static void
876 _gst_controller_finalize (GObject * object)
877 {
878 GstController *self = GST_CONTROLLER (object);
880 g_mutex_free (self->lock);
882 if (G_OBJECT_CLASS (parent_class)->finalize)
883 (G_OBJECT_CLASS (parent_class)->finalize) (object);
884 }
886 static void
887 _gst_controller_init (GTypeInstance * instance, gpointer g_class)
888 {
889 GstController *self = GST_CONTROLLER (instance);
891 self->lock = g_mutex_new ();
892 self->priv =
893 G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_CONTROLLER,
894 GstControllerPrivate);
895 self->priv->last_sync = GST_CLOCK_TIME_NONE;
896 self->priv->control_rate = 100 * GST_MSECOND;
897 }
899 static void
900 _gst_controller_class_init (GstControllerClass * klass)
901 {
902 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
904 parent_class = g_type_class_peek_parent (klass);
905 g_type_class_add_private (klass, sizeof (GstControllerPrivate));
907 gobject_class->set_property = _gst_controller_set_property;
908 gobject_class->get_property = _gst_controller_get_property;
909 gobject_class->dispose = _gst_controller_dispose;
910 gobject_class->finalize = _gst_controller_finalize;
912 __gst_controller_key = g_quark_from_string ("gst::controller");
914 /* register properties */
915 g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
916 g_param_spec_uint64 ("control-rate",
917 "control rate",
918 "Controlled properties will be updated at least every control-rate nanoseconds",
919 1, G_MAXUINT, 100 * GST_MSECOND, G_PARAM_READWRITE));
921 /* register signals */
922 /* set defaults for overridable methods */
923 }
925 GType
926 gst_controller_get_type ()
927 {
928 static GType type = 0;
930 if (type == 0) {
931 static const GTypeInfo info = {
932 sizeof (GstControllerClass),
933 NULL, /* base_init */
934 NULL, /* base_finalize */
935 (GClassInitFunc) _gst_controller_class_init, /* class_init */
936 NULL, /* class_finalize */
937 NULL, /* class_data */
938 sizeof (GstController),
939 0, /* n_preallocs */
940 (GInstanceInitFunc) _gst_controller_init, /* instance_init */
941 NULL /* value_table */
942 };
943 type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
944 }
945 return type;
946 }
948 /* FIXME: backward compatibility functions */
950 /*
951 * gst_controlled_property_set_interpolation_mode:
952 * @self: the controlled property object to change
953 * @mode: the new interpolation mode
954 *
955 * Sets the given Interpolation mode for the controlled property and activates
956 * the respective interpolation hooks.
957 *
958 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
959 * directly.
960 *
961 * Returns: %TRUE for success
962 */
963 static gboolean
964 gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
965 GstInterpolateMode mode)
966 {
967 GstInterpolationControlSource *icsource;
969 /* FIXME: backward compat, add GstInterpolationControlSource */
970 if (!self->csource)
971 gst_controlled_property_add_interpolation_control_source (self);
973 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self->csource),
974 FALSE);
976 icsource = GST_INTERPOLATION_CONTROL_SOURCE (self->csource);
978 return gst_interpolation_control_source_set_interpolation_mode (icsource,
979 mode);
980 }
982 /**
983 * gst_controller_set:
984 * @self: the controller object which handles the properties
985 * @property_name: the name of the property to set
986 * @timestamp: the time the control-change is schedules for
987 * @value: the control-value
988 *
989 * Set the value of given controller-handled property at a certain time.
990 *
991 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
992 * directly.
993 *
994 * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
995 */
996 gboolean
997 gst_controller_set (GstController * self, gchar * property_name,
998 GstClockTime timestamp, GValue * value)
999 {
1000 gboolean res = FALSE;
1001 GstControlledProperty *prop;
1003 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1004 g_return_val_if_fail (property_name, FALSE);
1006 g_mutex_lock (self->lock);
1007 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1008 /* FIXME: backward compat, add GstInterpolationControlSource */
1009 if (!prop->csource)
1010 gst_controlled_property_add_interpolation_control_source (prop);
1012 if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1013 goto out;
1014 res =
1015 gst_interpolation_control_source_set (GST_INTERPOLATION_CONTROL_SOURCE
1016 (prop->csource), timestamp, value);
1017 }
1019 out:
1020 g_mutex_unlock (self->lock);
1022 return res;
1023 }
1025 /**
1026 * gst_controller_set_from_list:
1027 * @self: the controller object which handles the properties
1028 * @property_name: the name of the property to set
1029 * @timedvalues: a list with #GstTimedValue items
1030 *
1031 * Sets multiple timed values at once.
1032 *
1033 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1034 * directly.
1035 *
1036 * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
1037 */
1039 gboolean
1040 gst_controller_set_from_list (GstController * self, gchar * property_name,
1041 GSList * timedvalues)
1042 {
1043 gboolean res = FALSE;
1044 GstControlledProperty *prop;
1046 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1047 g_return_val_if_fail (property_name, FALSE);
1049 g_mutex_lock (self->lock);
1050 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1051 /* FIXME: backward compat, add GstInterpolationControlSource */
1052 if (!prop->csource)
1053 gst_controlled_property_add_interpolation_control_source (prop);
1055 if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1056 goto out;
1058 res =
1059 gst_interpolation_control_source_set_from_list
1060 (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource), timedvalues);
1061 }
1063 out:
1064 g_mutex_unlock (self->lock);
1066 return res;
1067 }
1069 /**
1070 * gst_controller_unset:
1071 * @self: the controller object which handles the properties
1072 * @property_name: the name of the property to unset
1073 * @timestamp: the time the control-change should be removed from
1074 *
1075 * Used to remove the value of given controller-handled property at a certain
1076 * time.
1077 *
1078 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1079 * directly.
1080 *
1081 * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
1082 */
1083 gboolean
1084 gst_controller_unset (GstController * self, gchar * property_name,
1085 GstClockTime timestamp)
1086 {
1087 gboolean res = FALSE;
1088 GstControlledProperty *prop;
1090 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1091 g_return_val_if_fail (property_name, FALSE);
1092 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
1094 g_mutex_lock (self->lock);
1095 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1096 if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1097 goto out;
1099 res =
1100 gst_interpolation_control_source_unset (GST_INTERPOLATION_CONTROL_SOURCE
1101 (prop->csource), timestamp);
1102 }
1104 out:
1105 g_mutex_unlock (self->lock);
1107 return res;
1108 }
1110 /**
1111 * gst_controller_unset_all:
1112 * @self: the controller object which handles the properties
1113 * @property_name: the name of the property to unset
1114 *
1115 * Used to remove all time-stamped values of given controller-handled property
1116 *
1117 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1118 * directly.
1119 *
1120 * Returns: %FALSE if the values couldn't be unset (ex : properties not handled
1121 * by controller), %TRUE otherwise
1122 * Since: 0.10.5
1123 */
1124 gboolean
1125 gst_controller_unset_all (GstController * self, gchar * property_name)
1126 {
1127 GstControlledProperty *prop;
1129 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1130 g_return_val_if_fail (property_name, FALSE);
1132 g_mutex_lock (self->lock);
1133 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1134 if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1135 goto out;
1137 gst_interpolation_control_source_unset_all (GST_INTERPOLATION_CONTROL_SOURCE
1138 (prop->csource));
1139 }
1141 out:
1142 g_mutex_unlock (self->lock);
1144 return TRUE;
1145 }
1147 /**
1148 * gst_controller_get_all:
1149 * @self: the controller to get the list from
1150 * @property_name: the name of the property to get the list for
1151 *
1152 * Returns a read-only copy of the list of #GstTimedValue for the given property.
1153 * Free the list after done with it.
1154 *
1155 * <note><para>This doesn't modify the controlled GObject property!</para></note>
1156 *
1157 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1158 * directly.
1159 *
1160 * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
1161 */
1162 const GList *
1163 gst_controller_get_all (GstController * self, gchar * property_name)
1164 {
1165 const GList *res = NULL;
1166 GstControlledProperty *prop;
1168 g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
1169 g_return_val_if_fail (property_name, NULL);
1171 g_mutex_lock (self->lock);
1172 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1173 if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1174 goto out;
1176 res =
1177 gst_interpolation_control_source_get_all
1178 (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource));
1179 }
1181 out:
1182 g_mutex_unlock (self->lock);
1184 return res;
1185 }
1187 /**
1188 * gst_controller_set_interpolation_mode:
1189 * @self: the controller object
1190 * @property_name: the name of the property for which to change the interpolation
1191 * @mode: interpolation mode
1192 *
1193 * Sets the given interpolation mode on the given property.
1194 *
1195 * <note><para>User interpolation is not yet available and quadratic interpolation
1196 * is deprecated and maps to cubic interpolation.</para></note>
1197 *
1198 * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1199 * directly.
1200 *
1201 * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
1202 */
1203 gboolean
1204 gst_controller_set_interpolation_mode (GstController * self,
1205 gchar * property_name, GstInterpolateMode mode)
1206 {
1207 gboolean res = FALSE;
1208 GstControlledProperty *prop;
1210 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1211 g_return_val_if_fail (property_name, FALSE);
1213 g_mutex_lock (self->lock);
1214 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1215 res = gst_controlled_property_set_interpolation_mode (prop, mode);
1216 }
1217 g_mutex_unlock (self->lock);
1219 return res;
1220 }