3 * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
5 * gstcontroller.c: dynamic parameter control subsystem
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.
24 * SECTION:gstcontroller
25 * @short_description: dynamic parameter control subsystem
27 * The controller subsystem offers a lightweight way to adjust gobject
28 * properties over stream-time. It works by using time-stampled value pairs that
29 * are queued for element-properties. At run-time the elements continously pulls
30 * values changes for the current stream-time.
32 * What needs to be changed in a #GstElement?
33 * Very little - it is just two steps to make a plugin controllable!
36 * mark gobject-properties paramspecs that make sense to be controlled,
37 * by GST_PARAM_CONTROLLABLE.
40 * when processing data (get, chain, loop function) at the beginning call
41 * gst_object_sync_values(element,timestamp).
42 * This will made the controller to update all gobject properties that are under
43 * control with the current values based on timestamp.
47 * What needs to be done in applications?
48 * Again its not a lot to change.
51 * first put some properties under control, by calling
52 * controller = g_object_control_properties(object, "prop1", "prop2",...);
55 * set how the controller will smooth inbetween values.
56 * gst_controller_set_interpolation_mode(controller,"prop1",mode);
60 * gst_controller_set (controller, "prop1" ,0 * GST_SECOND, value1);
61 * gst_controller_set (controller, "prop1" ,1 * GST_SECOND, value2);
70 #include "gstcontroller.h"
72 #define GST_CAT_DEFAULT gst_controller_debug
73 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
75 static GObjectClass *parent_class = NULL;
76 GQuark __gst_controller_key;
79 /* imports from gst-interpolation.c */
82 * gst_controlled_property_find_timed_value_node (GstControlledProperty *
83 prop, GstClockTime timestamp);
84 extern GstInterpolateMethod *interpolation_methods[];
89 on_object_controlled_property_changed (const GObject * object, GParamSpec * arg,
92 GstControlledProperty *prop = GST_CONTROLLED_PROPERTY (user_data);
95 GST_INFO ("notify for '%s'", prop->name);
97 ctrl = g_object_get_qdata (G_OBJECT (object), __gst_controller_key);
98 g_return_if_fail (ctrl);
100 if (g_mutex_trylock (ctrl->lock)) {
101 if (!G_IS_VALUE (&prop->live_value.value)) {
102 g_value_init (&prop->live_value.value, prop->type);
104 g_object_get_property (G_OBJECT (object), prop->name,
105 &prop->live_value.value);
106 prop->live_value.timestamp = prop->last_value.timestamp;
107 g_mutex_unlock (ctrl->lock);
108 GST_DEBUG ("-> is live update : ts=%" G_GUINT64_FORMAT,
109 prop->live_value.timestamp);
116 * gst_timed_value_compare:
117 * @p1: a pointer to a #GstTimedValue
118 * @p2: a pointer to a #GstTimedValue
120 * Compare function for g_list operations that operates on two #GstTimedValue
124 gst_timed_value_compare (gconstpointer p1, gconstpointer p2)
126 GstClockTime ct1 = ((GstTimedValue *) p1)->timestamp;
127 GstClockTime ct2 = ((GstTimedValue *) p2)->timestamp;
129 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
130 /* this does not produce an gint :(
131 return ((ct1 - ct2));
136 * gst_timed_value_find:
137 * @p1: a pointer to a #GstTimedValue
138 * @p2: a pointer to a #GstClockTime
140 * Compare function for g_list operations that operates on a #GstTimedValue and
144 gst_timed_value_find (gconstpointer p1, gconstpointer p2)
146 GstClockTime ct1 = ((GstTimedValue *) p1)->timestamp;
147 GstClockTime ct2 = *(GstClockTime *) p2;
149 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
150 /* this does not produce an gint :(
151 return ((ct1 - ct2));
156 * gst_controlled_property_set_interpolation_mode:
157 * @self: the controlled property object to change
158 * @mode: the new interpolation mode
160 * Sets the given Interpolation mode for the controlled property and activates
161 * the respective interpolation hooks.
163 * Returns: %TRUE for success
166 gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
167 GstInterpolateMode mode)
171 self->interpolation = mode;
172 if (mode != GST_INTERPOLATE_USER) {
173 switch (self->type) {
175 self->get = interpolation_methods[mode]->get_int;
176 self->get_value_array =
177 interpolation_methods[mode]->get_int_value_array;
180 self->get = interpolation_methods[mode]->get_uint;
181 self->get_value_array =
182 interpolation_methods[mode]->get_uint_value_array;
185 self->get = interpolation_methods[mode]->get_long;
186 self->get_value_array =
187 interpolation_methods[mode]->get_long_value_array;
190 self->get = interpolation_methods[mode]->get_ulong;
191 self->get_value_array =
192 interpolation_methods[mode]->get_ulong_value_array;
195 self->get = interpolation_methods[mode]->get_float;
196 self->get_value_array =
197 interpolation_methods[mode]->get_float_value_array;
200 self->get = interpolation_methods[mode]->get_double;
201 self->get_value_array =
202 interpolation_methods[mode]->get_double_value_array;
205 self->get = interpolation_methods[mode]->get_boolean;
206 self->get_value_array =
207 interpolation_methods[mode]->get_boolean_value_array;
212 self->get_value_array = NULL;
214 if (!self->get) { /* || !self->get_value_array) */
215 GST_WARNING ("incomplete implementation for type '%d'", self->type);
219 /* TODO shouldn't this also get a GstInterpolateMethod *user_method
220 for the case mode==GST_INTERPOLATE_USER
228 * gst_controlled_property_new:
229 * @object: for which object the controlled property should be set up
230 * @name: the name of the property to be controlled
232 * Private method which initializes the fields of a new controlled property
235 * Returns: a freshly allocated structure or %NULL
237 static GstControlledProperty *
238 gst_controlled_property_new (GObject * object, const gchar * name)
240 GstControlledProperty *prop = NULL;
243 GST_INFO ("trying to put property '%s' under control", name);
245 /* check if the object has a property of that name */
247 g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
248 GST_DEBUG (" psec->flags : 0x%08x", pspec->flags);
250 /* check if this param is witable */
251 g_return_val_if_fail ((pspec->flags & G_PARAM_WRITABLE), NULL);
252 /* check if property is controlable */
253 g_return_val_if_fail ((pspec->flags & GST_PARAM_CONTROLLABLE), NULL);
254 /* check if this param is not construct-only */
255 g_return_val_if_fail (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY), NULL);
257 /* TODO do sanity checks
258 we don't control some pspec->value_type:
268 if ((prop = g_new0 (GstControlledProperty, 1))) {
271 prop->name = pspec->name; /* so we don't use the same mem twice */
272 prop->type = G_PARAM_SPEC_VALUE_TYPE (pspec);
273 gst_controlled_property_set_interpolation_mode (prop,
274 GST_INTERPOLATE_NONE);
275 /* prepare our gvalues */
276 g_value_init (&prop->default_value, prop->type);
277 g_value_init (&prop->result_value, prop->type);
278 g_value_init (&prop->last_value.value, prop->type);
279 switch (prop->type) {
281 GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
283 g_value_set_int (&prop->default_value, tpspec->default_value);
287 GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
289 g_value_set_uint (&prop->default_value, tpspec->default_value);
293 GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
295 g_value_set_long (&prop->default_value, tpspec->default_value);
299 GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
301 g_value_set_ulong (&prop->default_value, tpspec->default_value);
305 GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
307 g_value_set_float (&prop->default_value, tpspec->default_value);
310 GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
312 g_value_set_double (&prop->default_value, tpspec->default_value);
315 case G_TYPE_BOOLEAN:{
316 GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
318 g_value_set_boolean (&prop->default_value, tpspec->default_value);
322 GST_WARNING ("incomplete implementation for paramspec type '%s'",
323 G_PARAM_SPEC_TYPE_NAME (pspec));
325 /* TODO what about adding a timedval with timestamp=0 and value=default
326 * a bit easier for interpolators, example:
327 * first timestamp is at 5
328 * requested value if for timestamp=3
329 * LINEAR and Co. would need to interpolate from default value to value
332 signal_name = g_alloca (8 + 1 + strlen (name));
333 g_sprintf (signal_name, "notify::%s", name);
334 prop->notify_handler_id =
335 g_signal_connect (object, signal_name,
336 G_CALLBACK (on_object_controlled_property_changed), (gpointer) prop);
339 GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
347 * gst_controlled_property_free:
348 * @prop: the object to free
350 * Private method which frees all data allocated by a #GstControlledProperty
354 gst_controlled_property_free (GstControlledProperty * prop)
358 for (node = prop->values; node; node = g_list_next (node)) {
361 g_list_free (prop->values);
366 * gst_controller_find_controlled_property:
367 * @self: the controller object to search for a property in
368 * @name: the gobject property name to look for
370 * Searches the list of properties under control.
372 * Returns: a #GstControlledProperty object of %NULL if the property is not
375 static GstControlledProperty *
376 gst_controller_find_controlled_property (GstController * self,
379 GstControlledProperty *prop;
382 for (node = self->properties; node; node = g_list_next (node)) {
384 if (!strcmp (prop->name, name)) {
388 GST_DEBUG ("controller does not (yet) manage property '%s'", name);
396 * gst_controller_new_valist:
397 * @object: the object of which some properties should be controlled
398 * @var_args: %NULL terminated list of property names that should be controlled
400 * Creates a new GstController for the given object's properties
402 * Returns: the new controller.
406 gst_controller_new_valist (GObject * object, va_list var_args)
409 GstControlledProperty *prop;
412 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
414 GST_INFO ("setting up a new controller");
416 /* TODO should this method check if the given object implements GstParent and
417 if so instantiate a GstParentController ?
419 BilboEd: This is too specific to be put here, don't we want
420 GstController to be as generic as possible ?
422 Ensonic: So we will have gst_parent_controller_new as well and maybe a
423 convinience function that automatically chooses the right one (how to name it)?
424 GstParent will be in core after all.
427 self = g_object_get_qdata (object, __gst_controller_key);
428 /* create GstControlledProperty for each property */
429 while ((name = va_arg (var_args, gchar *))) {
430 /* test if this property isn't yet controlled */
431 if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
432 /* create GstControlledProperty and add to self->propeties List */
433 if ((prop = gst_controlled_property_new (object, name))) {
434 /* if we don't have a controller object yet, now is the time to create one */
436 self = g_object_new (GST_TYPE_CONTROLLER, NULL);
437 self->object = object;
438 /* store the controller */
439 g_object_set_qdata (object, __gst_controller_key, self);
441 GST_INFO ("returning existing controller");
443 self->properties = g_list_prepend (self->properties, prop);
446 GST_WARNING ("trying to control property again");
452 GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
457 * gst_controller_new_list:
458 * @object: the object of which some properties should be controlled
459 * @list: list of property names that should be controlled
461 * Creates a new GstController for the given object's properties
463 * Returns: the new controller.
467 gst_controller_new_list (GObject * object, GList * list)
470 GstControlledProperty *prop;
474 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
476 GST_INFO ("setting up a new controller");
478 self = g_object_get_qdata (object, __gst_controller_key);
479 /* create GstControlledProperty for each property */
480 for (node = list; node; node = g_list_next (node)) {
481 name = (gchar *) node->data;
482 /* test if this property isn't yet controlled */
483 if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
484 /* create GstControlledProperty and add to self->propeties List */
485 if ((prop = gst_controlled_property_new (object, name))) {
486 /* if we don't have a controller object yet, now is the time to create one */
488 self = g_object_new (GST_TYPE_CONTROLLER, NULL);
489 self->object = object;
490 /* store the controller */
491 g_object_set_qdata (object, __gst_controller_key, self);
493 GST_INFO ("returning existing controller");
495 self->properties = g_list_prepend (self->properties, prop);
498 GST_WARNING ("trying to control property again");
503 GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
508 * gst_controller_new:
509 * @object: the object of which some properties should be controlled
510 * @...: %NULL terminated list of property names that should be controlled
512 * Creates a new GstController for the given object's properties
514 * Returns: the new controller.
518 gst_controller_new (GObject * object, ...)
523 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
525 va_start (var_args, object);
526 self = gst_controller_new_valist (object, var_args);
533 * gst_controller_remove_properties_valist:
534 * @self: the controller object from which some properties should be removed
535 * @var_args: %NULL terminated list of property names that should be removed
537 * Removes the given object properties from the controller
539 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
543 gst_controller_remove_properties_valist (GstController * self, va_list var_args)
546 GstControlledProperty *prop;
549 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
551 while ((name = va_arg (var_args, gchar *))) {
552 /* find the property in the properties list of the controller, remove and free it */
553 g_mutex_lock (self->lock);
554 if ((prop = gst_controller_find_controlled_property (self, name))) {
555 self->properties = g_list_remove (self->properties, prop);
556 g_signal_handler_disconnect (self->object, prop->notify_handler_id);
557 gst_controlled_property_free (prop);
561 g_mutex_unlock (self->lock);
568 * gst_controller_remove_properties_list:
569 * @self: the controller object from which some properties should be removed
570 * @list: #GList of property names that should be removed
572 * Removes the given object properties from the controller
574 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
578 gst_controller_remove_properties_list (GstController * self, GList * list)
581 GstControlledProperty *prop;
585 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
587 for (tmp = list; tmp; tmp = g_list_next (tmp)) {
588 name = (gchar *) tmp->data;
590 /* find the property in the properties list of the controller, remove and free it */
591 g_mutex_lock (self->lock);
592 if ((prop = gst_controller_find_controlled_property (self, name))) {
593 self->properties = g_list_remove (self->properties, prop);
594 g_signal_handler_disconnect (self->object, prop->notify_handler_id);
595 gst_controlled_property_free (prop);
599 g_mutex_unlock (self->lock);
606 * gst_controller_remove_properties:
607 * @self: the controller object from which some properties should be removed
608 * @...: %NULL terminated list of property names that should be removed
610 * Removes the given object properties from the controller
612 * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
616 gst_controller_remove_properties (GstController * self, ...)
621 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
623 va_start (var_args, self);
624 res = gst_controller_remove_properties_valist (self, var_args);
631 * gst_controller_set:
632 * @self: the controller object which handles the properties
633 * @property_name: the name of the property to set
634 * @timestamp: the time the control-change is schedules for
635 * @value: the control-value
637 * Set the value of given controller-handled property at a certain time.
639 * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
643 gst_controller_set (GstController * self, gchar * property_name,
644 GstClockTime timestamp, GValue * value)
646 gboolean res = FALSE;
647 GstControlledProperty *prop;
649 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
650 g_return_val_if_fail (property_name, FALSE);
651 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
652 g_return_val_if_fail (G_IS_VALUE (value), FALSE);
654 g_mutex_lock (self->lock);
655 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
656 if (G_VALUE_TYPE (value) == prop->type) {
660 /* check if a timed_value for the timestamp already exists */
661 if ((node = g_list_find_custom (prop->values, ×tamp,
662 gst_timed_value_find))) {
664 memcpy (&tv->value, value, sizeof (GValue));
666 /* create a new GstTimedValue */
667 tv = g_new (GstTimedValue, 1);
668 tv->timestamp = timestamp;
669 memcpy (&tv->value, value, sizeof (GValue));
670 /* and sort it into the prop->values list */
672 g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
676 GST_WARNING ("incompatible value type for property '%s'", prop->name);
679 g_mutex_unlock (self->lock);
685 * gst_controller_set_from_list:
686 * @self: the controller object which handles the properties
687 * @property_name: the name of the property to set
688 * @timedvalues: a list with #GstTimedValue items
690 * Sets multiple timed values at once.
692 * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
697 gst_controller_set_from_list (GstController * self, gchar * property_name,
698 GSList * timedvalues)
700 gboolean res = FALSE;
701 GstControlledProperty *prop;
705 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
706 g_return_val_if_fail (property_name, FALSE);
708 g_mutex_lock (self->lock);
709 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
710 for (node = timedvalues; node; node = g_slist_next (node)) {
712 if (G_VALUE_TYPE (&tv->value) == prop->type) {
713 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (tv->timestamp), FALSE);
714 /* TODO copy the timed value or just link in? */
716 g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
719 GST_WARNING ("incompatible value type for property '%s'", prop->name);
723 g_mutex_unlock (self->lock);
729 * gst_controller_unset:
730 * @self: the controller object which handles the properties
731 * @property_name: the name of the property to unset
732 * @timestamp: the time the control-change should be removed from
734 * Used to remove the value of given controller-handled property at a certain
737 * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
741 gst_controller_unset (GstController * self, gchar * property_name,
742 GstClockTime timestamp)
744 gboolean res = FALSE;
745 GstControlledProperty *prop;
747 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
748 g_return_val_if_fail (property_name, FALSE);
749 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
751 g_mutex_lock (self->lock);
752 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
753 prop->values = g_list_remove (prop->values, prop);
756 g_mutex_unlock (self->lock);
762 * gst_controller_get:
763 * @self: the controller object which handles the properties
764 * @property_name: the name of the property to get
765 * @timestamp: the time the control-change should be read from
767 * Gets the value for the given controller-handled property at the requested
770 * Returns: the GValue of the property at the given time, or %NULL if the property isn't handled by the controller
774 gst_controller_get (GstController * self, gchar * property_name,
775 GstClockTime timestamp)
777 GstControlledProperty *prop;
780 g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
781 g_return_val_if_fail (property_name, NULL);
782 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
784 g_mutex_lock (self->lock);
785 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
786 /* get current value via interpolator */
787 val = prop->get (prop, timestamp);
789 g_mutex_unlock (self->lock);
795 * gst_controller_get_all:
796 * @self: the controller to get the list from
797 * @property_name: the name of the property to get the list for
799 * Returns a read-only copy of the list of GstTimedValue for the given property.
800 * Free the list after done with it.
802 * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
806 gst_controller_get_all (GstController * self, gchar * property_name)
809 GstControlledProperty *prop;
811 g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
812 g_return_val_if_fail (property_name, NULL);
814 g_mutex_lock (self->lock);
815 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
816 res = g_list_copy (prop->values);
818 g_mutex_unlock (self->lock);
824 * gst_controller_sync_values:
825 * @self: the controller that handles the values
826 * @timestamp: the time that should be processed
828 * Sets the properties of the element, according to the controller that (maybe)
829 * handles them and for the given timestamp.
831 * Returns: %TRUE if the controller values could be applied to the object
832 * properties, %FALSE otherwise
836 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
838 GstControlledProperty *prop;
843 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
844 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
846 GST_INFO ("sync_values");
848 g_mutex_lock (self->lock);
849 /* go over the controlled properties of the controller */
850 for (node = self->properties; node; node = g_list_next (node)) {
852 GST_DEBUG (" property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
856 if (G_IS_VALUE (&prop->live_value.value)) {
858 gst_controlled_property_find_timed_value_node (prop, timestamp);
860 GST_DEBUG (" no control changes in the queue");
863 GstTimedValue *tv = lnode->data;
865 if (prop->live_value.timestamp < tv->timestamp) {
866 g_value_unset (&prop->live_value.value);
867 GST_DEBUG (" live value resetted");
868 } else if (prop->live_value.timestamp < timestamp) {
874 /* get current value via interpolator */
875 value = prop->get (prop, timestamp);
876 prop->last_value.timestamp = timestamp;
877 g_value_copy (value, &prop->last_value.value);
878 g_object_set_property (self->object, prop->name, value);
881 g_mutex_unlock (self->lock);
882 /* TODO what can here go wrong, to return FALSE ?
883 BilboEd : Nothing I guess, as long as all the checks are made when creating the controller,
884 adding/removing controlled properties, etc...
891 * gst_controller_get_value_arrays:
892 * @self: the controller that handles the values
893 * @timestamp: the time that should be processed
894 * @value_arrays: list to return the control-values in
896 * Function to be able to get an array of values for one or more given element
899 * If the GstValueArray->values array in list nodes is NULL, it will be created
901 * The type of the values in the array are the same as the property's type.
903 * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
907 gst_controller_get_value_arrays (GstController * self,
908 GstClockTime timestamp, GSList * value_arrays)
913 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
914 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
915 g_return_val_if_fail (value_arrays, FALSE);
917 for (node = value_arrays; (res && node); node = g_slist_next (node)) {
918 res = gst_controller_get_value_array (self, timestamp, node->data);
925 * gst_controller_get_value_array:
926 * @self: the controller that handles the values
927 * @timestamp: the time that should be processed
928 * @value_array: array to put control-values in
930 * Function to be able to get an array of values for one element properties
932 * If the GstValueArray->values array is NULL, it will be created by the function.
933 * The type of the values in the array are the same as the property's type.
935 * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
939 gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
940 GstValueArray * value_array)
942 gboolean res = FALSE;
943 GstControlledProperty *prop;
945 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
946 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
947 g_return_val_if_fail (value_array, FALSE);
948 g_return_val_if_fail (value_array->property_name, FALSE);
950 /* TODO and if GstValueArray->values is not NULL, the caller is resposible that
951 is is big enough for nbsamples values, right?
954 g_mutex_lock (self->lock);
956 gst_controller_find_controlled_property (self,
957 value_array->property_name))) {
958 if (!value_array->values) {
959 /* TODO from where to get the base size
960 value_array->values=g_new(sizeof(???),nbsamples);
963 /* get current value_array via interpolator */
964 res = prop->get_value_array (prop, timestamp, value_array);
966 g_mutex_unlock (self->lock);
971 * gst_controller_set_interpolation_mode:
972 * @self: the controller object
973 * @property_name: the name of the property for which to change the interpolation
974 * @mode: interpolation mode
976 * Sets the given interpolation mode on the given property.
978 * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
982 gst_controller_set_interpolation_mode (GstController * self,
983 gchar * property_name, GstInterpolateMode mode)
985 gboolean res = FALSE;
986 GstControlledProperty *prop;
988 g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
989 g_return_val_if_fail (property_name, FALSE);
991 g_mutex_lock (self->lock);
992 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
993 /* TODO shouldn't this also get a GstInterpolateMethod *user_method
994 for the case mode==GST_INTERPOLATE_USER
996 gst_controlled_property_set_interpolation_mode (prop, mode);
999 g_mutex_unlock (self->lock);
1006 gst_controller_set_live_value(GstController * self, gchar *property_name,
1007 GstClockTime timestamp, GValue *value)
1009 GstControlledProperty *prop;
1011 g_return_if_fail (GST_IS_CONTROLLER (self));
1012 g_return_if_fail (property_name);
1014 g_mutex_lock (self->lock);
1015 if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1016 g_value_unset (&prop->live_value.value);
1017 g_value_init (&prop->live_value.value, prop->type);
1018 g_value_copy (value, &prop->live_value.value);
1019 prop->live_value.timestamp = timestamp;
1021 g_mutex_unlock (self->lock);
1026 /* gobject handling */
1029 _gst_controller_finalize (GObject * object)
1031 GstController *self = GST_CONTROLLER (object);
1033 GstControlledProperty *prop;
1035 /* free list of properties */
1036 if (self->properties) {
1037 for (node = self->properties; node; node = g_list_next (node)) {
1039 g_signal_handler_disconnect (self->object, prop->notify_handler_id);
1040 gst_controlled_property_free (prop);
1042 g_list_free (self->properties);
1043 self->properties = NULL;
1045 g_mutex_free (self->lock);
1046 /* remove controller from objects qdata list */
1047 g_object_set_qdata (self->object, __gst_controller_key, NULL);
1049 if (G_OBJECT_CLASS (parent_class)->finalize)
1050 (G_OBJECT_CLASS (parent_class)->finalize) (object);
1054 _gst_controller_init (GTypeInstance * instance, gpointer g_class)
1056 GstController *self = GST_CONTROLLER (instance);
1058 self->lock = g_mutex_new ();
1063 _gst_controller_class_init (GstControllerClass * klass)
1065 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1067 parent_class = g_type_class_ref (G_TYPE_OBJECT);
1069 gobject_class->finalize = _gst_controller_finalize;
1071 __gst_controller_key = g_quark_from_string ("gst::controller");
1073 /* register properties */
1074 /* register signals */
1075 /* set defaults for overridable methods */
1076 /* TODO which of theses do we need ?
1082 gst_controller_get_type (void)
1084 static GType type = 0;
1087 static const GTypeInfo info = {
1088 sizeof (GstControllerClass),
1089 NULL, /* base_init */
1090 NULL, /* base_finalize */
1091 (GClassInitFunc) _gst_controller_class_init, /* class_init */
1092 NULL, /* class_finalize */
1093 NULL, /* class_data */
1094 sizeof (GstController),
1095 0, /* n_preallocs */
1096 (GInstanceInitFunc) _gst_controller_init, /* instance_init */
1097 NULL /* value_table */
1099 type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);