controller: fix wrong order of calls in the docs.
[platform/upstream/gstreamer.git] / libs / gst / controller / gstcontroller.c
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  */
23
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 = gst_object_control_properties (object, "prop1", "prop2",...);
54  *   </para></listitem>
55  *   <listitem><para>
56  *     create a #GstControlSource.
57  *     csource = gst_interpolation_control_source_new ();
58  *     gst_interpolation_control_source_set_interpolation_mode(csource, mode);
59  *   </para></listitem>
60  *   <listitem><para>
61  *     Attach the #GstControlSource on the controller to a property.
62  *     gst_controller_set_control_source (controller, "prop1", csource);
63  *   </para></listitem>
64  *   <listitem><para>
65  *     Set the control values
66  *     gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
67  *     gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
68  *   </para></listitem>
69  *   <listitem><para>
70  *     start your pipeline
71  *   </para></listitem>
72  * </orderedlist>
73  */
74
75 #ifdef HAVE_CONFIG_H
76 #  include "config.h"
77 #endif
78
79 #include "gstcontroller.h"
80 #include "gstcontrollerprivate.h"
81 #include "gstcontrolsource.h"
82 #include "gstinterpolationcontrolsource.h"
83
84 #define GST_CAT_DEFAULT controller_debug
85 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
86
87 static GObjectClass *parent_class = NULL;
88 GQuark priv_gst_controller_key;
89
90 /* property ids */
91 enum
92 {
93   PROP_CONTROL_RATE = 1
94 };
95
96 struct _GstControllerPrivate
97 {
98   GstClockTime control_rate;
99   GstClockTime last_sync;
100 };
101
102 /* helper */
103 #ifndef GST_REMOVE_DEPRECATED
104 static void
105 gst_controlled_property_add_interpolation_control_source (GstControlledProperty
106     * self)
107 {
108   GstControlSource *csource =
109       GST_CONTROL_SOURCE (gst_interpolation_control_source_new ());
110
111   GST_INFO
112       ("Adding a GstInterpolationControlSource because of backward compatibility");
113   g_return_if_fail (!self->csource);
114   gst_control_source_bind (GST_CONTROL_SOURCE (csource), self->pspec);
115   self->csource = csource;
116 }
117 #endif
118
119 /*
120  * gst_controlled_property_new:
121  * @object: for which object the controlled property should be set up
122  * @name: the name of the property to be controlled
123  *
124  * Private method which initializes the fields of a new controlled property
125  * structure.
126  *
127  * Returns: a freshly allocated structure or %NULL
128  */
129 static GstControlledProperty *
130 gst_controlled_property_new (GObject * object, const gchar * name)
131 {
132   GstControlledProperty *prop = NULL;
133   GParamSpec *pspec;
134
135   GST_INFO ("trying to put property '%s' under control", name);
136
137   /* check if the object has a property of that name */
138   if ((pspec =
139           g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
140     GST_DEBUG ("  psec->flags : 0x%08x", pspec->flags);
141
142     /* check if this param is witable && controlable && !construct-only */
143     g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE |
144                 GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) ==
145         (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL);
146
147     if ((prop = g_slice_new (GstControlledProperty))) {
148       prop->pspec = pspec;
149       prop->name = pspec->name;
150       prop->csource = NULL;
151       prop->disabled = FALSE;
152       memset (&prop->last_value, 0, sizeof (GValue));
153       g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
154     }
155   } else {
156     GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
157         name);
158   }
159   return prop;
160 }
161
162 /*
163  * gst_controlled_property_free:
164  * @prop: the object to free
165  *
166  * Private method which frees all data allocated by a #GstControlledProperty
167  * instance.
168  */
169 static void
170 gst_controlled_property_free (GstControlledProperty * prop)
171 {
172   if (prop->csource)
173     g_object_unref (prop->csource);
174   g_value_unset (&prop->last_value);
175   g_slice_free (GstControlledProperty, prop);
176 }
177
178 /*
179  * gst_controller_find_controlled_property:
180  * @self: the controller object to search for a property in
181  * @name: the gobject property name to look for
182  *
183  * Searches the list of properties under control.
184  *
185  * Returns: a #GstControlledProperty object of %NULL if the property is not
186  * being controlled.
187  */
188 static GstControlledProperty *
189 gst_controller_find_controlled_property (GstController * self,
190     const gchar * name)
191 {
192   GstControlledProperty *prop;
193   GList *node;
194
195   for (node = self->properties; node; node = g_list_next (node)) {
196     prop = node->data;
197     /* FIXME: eventually use GQuark to speed it up */
198     if (!strcmp (prop->name, name)) {
199       return prop;
200     }
201   }
202   GST_DEBUG ("controller does not (yet) manage property '%s'", name);
203
204   return NULL;
205 }
206
207 /*
208  * gst_controller_add_property:
209  * @self: the controller object or %NULL if none yet exists
210  * @object: object to bind the property
211  * @name: name of projecty in @object
212  * @ref_existing: pointer to flag that tracks if we need to ref an existing
213  *   controller still
214  *
215  * Creates a new #GstControlledProperty if there is none for property @name yet.
216  * In case this is the first controlled propery, it creates the controller as
217  * well.
218  *
219  * Returns: a newly created controller object or reffed existing one with the
220  * given property bound.
221  */
222 static GstController *
223 gst_controller_add_property (GstController * self, GObject * object,
224     const gchar * name, gboolean * ref_existing)
225 {
226   /* test if this property isn't yet controlled */
227   if (!self || !gst_controller_find_controlled_property (self, name)) {
228     GstControlledProperty *prop;
229
230     /* create GstControlledProperty and add to self->propeties List */
231     if ((prop = gst_controlled_property_new (object, name))) {
232       /* if we don't have a controller object yet, now is the time to create one */
233       if (!self) {
234         self = g_object_newv (GST_TYPE_CONTROLLER, 0, NULL);
235         self->object = g_object_ref (object);
236         /* store the controller */
237         g_object_set_qdata (object, priv_gst_controller_key, self);
238         *ref_existing = FALSE;
239       } else {
240         /* only want one single _ref(), even for multiple properties */
241         if (*ref_existing) {
242           g_object_ref (self);
243           *ref_existing = FALSE;
244           GST_INFO ("returning existing controller");
245         }
246       }
247       self->properties = g_list_prepend (self->properties, prop);
248     }
249   } else {
250     GST_WARNING ("trying to control property %s again", name);
251     if (*ref_existing) {
252       g_object_ref (self);
253       *ref_existing = FALSE;
254     }
255   }
256   return self;
257 }
258
259 /* methods */
260
261 /**
262  * gst_controller_new_valist:
263  * @object: the object of which some properties should be controlled
264  * @var_args: %NULL terminated list of property names that should be controlled
265  *
266  * Creates a new GstController for the given object's properties
267  *
268  * Returns: the new controller.
269  */
270 GstController *
271 gst_controller_new_valist (GObject * object, va_list var_args)
272 {
273   GstController *self;
274   gboolean ref_existing = TRUE;
275   gchar *name;
276
277   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
278
279   GST_INFO ("setting up a new controller");
280
281   self = g_object_get_qdata (object, priv_gst_controller_key);
282   /* create GstControlledProperty for each property */
283   while ((name = va_arg (var_args, gchar *))) {
284     self = gst_controller_add_property (self, object, name, &ref_existing);
285   }
286   va_end (var_args);
287
288   if (self)
289     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
290   return self;
291 }
292
293 /**
294  * gst_controller_new_list:
295  * @object: the object of which some properties should be controlled
296  * @list: list of property names that should be controlled
297  *
298  * Creates a new GstController for the given object's properties
299  *
300  * Returns: the new controller.
301  */
302 GstController *
303 gst_controller_new_list (GObject * object, GList * list)
304 {
305   GstController *self;
306   gboolean ref_existing = TRUE;
307   gchar *name;
308   GList *node;
309
310   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
311
312   GST_INFO ("setting up a new controller");
313
314   self = g_object_get_qdata (object, priv_gst_controller_key);
315   /* create GstControlledProperty for each property */
316   for (node = list; node; node = g_list_next (node)) {
317     name = (gchar *) node->data;
318     self = gst_controller_add_property (self, object, name, &ref_existing);
319   }
320
321   if (self)
322     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
323   return self;
324 }
325
326 /**
327  * gst_controller_new:
328  * @object: the object of which some properties should be controlled
329  * @...: %NULL terminated list of property names that should be controlled
330  *
331  * Creates a new GstController for the given object's properties
332  *
333  * Returns: the new controller.
334  */
335 GstController *
336 gst_controller_new (GObject * object, ...)
337 {
338   GstController *self;
339   va_list var_args;
340
341   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
342
343   va_start (var_args, object);
344   self = gst_controller_new_valist (object, var_args);
345   va_end (var_args);
346
347   return self;
348 }
349
350 /**
351  * gst_controller_remove_properties_valist:
352  * @self: the controller object from which some properties should be removed
353  * @var_args: %NULL terminated list of property names that should be removed
354  *
355  * Removes the given object properties from the controller
356  *
357  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
358  */
359 gboolean
360 gst_controller_remove_properties_valist (GstController * self, va_list var_args)
361 {
362   gboolean res = TRUE;
363   GstControlledProperty *prop;
364   gchar *name;
365
366   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
367
368   while ((name = va_arg (var_args, gchar *))) {
369     /* find the property in the properties list of the controller, remove and free it */
370     g_mutex_lock (self->lock);
371     if ((prop = gst_controller_find_controlled_property (self, name))) {
372       self->properties = g_list_remove (self->properties, prop);
373       //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
374       gst_controlled_property_free (prop);
375     } else {
376       res = FALSE;
377     }
378     g_mutex_unlock (self->lock);
379   }
380
381   return res;
382 }
383
384 /**
385  * gst_controller_remove_properties_list:
386  * @self: the controller object from which some properties should be removed
387  * @list: #GList of property names that should be removed
388  *
389  * Removes the given object properties from the controller
390  *
391  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
392  */
393 gboolean
394 gst_controller_remove_properties_list (GstController * self, GList * list)
395 {
396   gboolean res = TRUE;
397   GstControlledProperty *prop;
398   gchar *name;
399   GList *tmp;
400
401   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
402
403   for (tmp = list; tmp; tmp = g_list_next (tmp)) {
404     name = (gchar *) tmp->data;
405
406     /* find the property in the properties list of the controller, remove and free it */
407     g_mutex_lock (self->lock);
408     if ((prop = gst_controller_find_controlled_property (self, name))) {
409       self->properties = g_list_remove (self->properties, prop);
410       //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
411       gst_controlled_property_free (prop);
412     } else {
413       res = FALSE;
414     }
415     g_mutex_unlock (self->lock);
416   }
417
418   return res;
419 }
420
421 /**
422  * gst_controller_remove_properties:
423  * @self: the controller object from which some properties should be removed
424  * @...: %NULL terminated list of property names that should be removed
425  *
426  * Removes the given object properties from the controller
427  *
428  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
429  */
430 gboolean
431 gst_controller_remove_properties (GstController * self, ...)
432 {
433   gboolean res;
434   va_list var_args;
435
436   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
437
438   va_start (var_args, self);
439   res = gst_controller_remove_properties_valist (self, var_args);
440   va_end (var_args);
441
442   return res;
443 }
444
445 /**
446  * gst_controller_set_property_disabled:
447  * @self: the #GstController which should be disabled
448  * @property_name: property to disable
449  * @disabled: boolean that specifies whether to disable the controller
450  * or not.
451  *
452  * This function is used to disable the #GstController on a property for
453  * some time, i.e. gst_controller_sync_values() will do nothing for the
454  * property.
455  *
456  * Since: 0.10.14
457  */
458
459 void
460 gst_controller_set_property_disabled (GstController * self,
461     const gchar * property_name, gboolean disabled)
462 {
463   GstControlledProperty *prop;
464
465   g_return_if_fail (GST_IS_CONTROLLER (self));
466   g_return_if_fail (property_name);
467
468   g_mutex_lock (self->lock);
469   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
470     prop->disabled = disabled;
471   }
472   g_mutex_unlock (self->lock);
473 }
474
475
476 /**
477  * gst_controller_set_disabled:
478  * @self: the #GstController which should be disabled
479  * @disabled: boolean that specifies whether to disable the controller
480  * or not.
481  *
482  * This function is used to disable all properties of the #GstController
483  * for some time, i.e. gst_controller_sync_values() will do nothing.
484  *
485  * Since: 0.10.14
486  */
487
488 void
489 gst_controller_set_disabled (GstController * self, gboolean disabled)
490 {
491   GList *node;
492   GstControlledProperty *prop;
493
494   g_return_if_fail (GST_IS_CONTROLLER (self));
495
496   g_mutex_lock (self->lock);
497   for (node = self->properties; node; node = node->next) {
498     prop = node->data;
499     prop->disabled = disabled;
500   }
501   g_mutex_unlock (self->lock);
502 }
503
504 /**
505  * gst_controller_set_control_source:
506  * @self: the controller object
507  * @property_name: name of the property for which the #GstControlSource should be set
508  * @csource: the #GstControlSource that should be used for the property
509  *
510  * Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
511  * for this property it will be unreferenced.
512  *
513  * Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
514  * couldn't be bound to the property, %TRUE if everything worked as expected.
515  *
516  * Since: 0.10.14
517  */
518 gboolean
519 gst_controller_set_control_source (GstController * self,
520     const gchar * property_name, GstControlSource * csource)
521 {
522   GstControlledProperty *prop;
523   gboolean ret = FALSE;
524
525   g_mutex_lock (self->lock);
526   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
527     GstControlSource *old = prop->csource;
528
529     if (csource && (ret = gst_control_source_bind (csource, prop->pspec))) {
530       g_object_ref (csource);
531       prop->csource = csource;
532     } else if (!csource) {
533       ret = TRUE;
534       prop->csource = NULL;
535     }
536
537     if (ret && old)
538       g_object_unref (old);
539   }
540   g_mutex_unlock (self->lock);
541
542   return ret;
543 }
544
545 /**
546  * gst_controller_get_control_source:
547  * @self: the controller object
548  * @property_name: name of the property for which the #GstControlSource should be get
549  *
550  * Gets the corresponding #GstControlSource for the property. This should be unreferenced
551  * again after use.
552  *
553  * Returns: the #GstControlSource for @property_name or NULL if the property is not
554  * controlled by this controller or no #GstControlSource was assigned yet.
555  *
556  * Since: 0.10.14
557  */
558 GstControlSource *
559 gst_controller_get_control_source (GstController * self,
560     const gchar * property_name)
561 {
562   GstControlledProperty *prop;
563   GstControlSource *ret = NULL;
564
565   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
566   g_return_val_if_fail (property_name, NULL);
567
568   g_mutex_lock (self->lock);
569   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
570     ret = prop->csource;
571   }
572   g_mutex_unlock (self->lock);
573
574   if (ret)
575     g_object_ref (ret);
576
577   return ret;
578 }
579
580 /**
581  * gst_controller_get:
582  * @self: the controller object which handles the properties
583  * @property_name: the name of the property to get
584  * @timestamp: the time the control-change should be read from
585  *
586  * Gets the value for the given controller-handled property at the requested
587  * time.
588  *
589  * Returns: the GValue of the property at the given time, or %NULL if the
590  * property isn't handled by the controller
591  */
592 GValue *
593 gst_controller_get (GstController * self, const gchar * property_name,
594     GstClockTime timestamp)
595 {
596   GstControlledProperty *prop;
597   GValue *val = NULL;
598
599   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
600   g_return_val_if_fail (property_name, NULL);
601   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
602
603   g_mutex_lock (self->lock);
604   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
605     val = g_new0 (GValue, 1);
606     g_value_init (val, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
607     if (prop->csource) {
608       gboolean res;
609
610       /* get current value via control source */
611       res = gst_control_source_get_value (prop->csource, timestamp, val);
612       if (!res) {
613         g_free (val);
614         val = NULL;
615       }
616     } else {
617       g_object_get_property (self->object, prop->name, val);
618     }
619   }
620   g_mutex_unlock (self->lock);
621
622   return val;
623 }
624
625 /**
626  * gst_controller_suggest_next_sync:
627  * @self: the controller that handles the values
628  *
629  * Returns a suggestion for timestamps where buffers should be split
630  * to get best controller results.
631  *
632  * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
633  * if no control-rate was set.
634  *
635  * Since: 0.10.13
636  */
637 GstClockTime
638 gst_controller_suggest_next_sync (GstController * self)
639 {
640   GstClockTime ret;
641
642   g_return_val_if_fail (GST_IS_CONTROLLER (self), GST_CLOCK_TIME_NONE);
643   g_return_val_if_fail (self->priv->control_rate != GST_CLOCK_TIME_NONE,
644       GST_CLOCK_TIME_NONE);
645
646   g_mutex_lock (self->lock);
647
648   /* TODO: Implement more logic, depending on interpolation mode
649    * and control points
650    * FIXME: we need playback direction
651    */
652   ret = self->priv->last_sync + self->priv->control_rate;
653
654   g_mutex_unlock (self->lock);
655
656   return ret;
657 }
658
659 /**
660  * gst_controller_sync_values:
661  * @self: the controller that handles the values
662  * @timestamp: the time that should be processed
663  *
664  * Sets the properties of the element, according to the controller that (maybe)
665  * handles them and for the given timestamp.
666  *
667  * If this function fails, it is most likely the application developers fault.
668  * Most probably the control sources are not setup correctly.
669  *
670  * Returns: %TRUE if the controller values could be applied to the object
671  * properties, %FALSE otherwise
672  */
673 gboolean
674 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
675 {
676   GstControlledProperty *prop;
677   GList *node;
678   gboolean ret = TRUE, val_ret;
679   GValue value = { 0, };
680
681   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
682   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
683
684   GST_LOG ("sync_values");
685
686   g_mutex_lock (self->lock);
687   g_object_freeze_notify (self->object);
688   /* go over the controlled properties of the controller */
689   for (node = self->properties; node; node = g_list_next (node)) {
690     prop = node->data;
691
692     if (!prop->csource || prop->disabled)
693       continue;
694
695     GST_LOG ("property '%s' at ts=%" G_GUINT64_FORMAT, prop->name, timestamp);
696
697     /* we can make this faster
698      * http://bugzilla.gnome.org/show_bug.cgi?id=536939
699      */
700     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
701     val_ret = gst_control_source_get_value (prop->csource, timestamp, &value);
702     if (G_LIKELY (val_ret)) {
703       /* always set the value for first time, but then only if it changed
704        * this should limit g_object_notify invocations.
705        * FIXME: can we detect negative playback rates?
706        */
707       if ((timestamp < self->priv->last_sync) ||
708           gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
709         g_object_set_property (self->object, prop->name, &value);
710         g_value_copy (&value, &prop->last_value);
711       }
712     } else {
713       GST_DEBUG ("no control value for param %s", prop->name);
714     }
715     g_value_unset (&value);
716     ret &= val_ret;
717   }
718   self->priv->last_sync = timestamp;
719   g_object_thaw_notify (self->object);
720
721   g_mutex_unlock (self->lock);
722
723   return ret;
724 }
725
726 /**
727  * gst_controller_get_value_arrays:
728  * @self: the controller that handles the values
729  * @timestamp: the time that should be processed
730  * @value_arrays: list to return the control-values in
731  *
732  * Function to be able to get an array of values for one or more given element
733  * properties.
734  *
735  * All fields of the %GstValueArray in the list must be filled correctly.
736  * Especially the GstValueArray->values arrays must be big enough to keep
737  * the requested amount of values.
738  *
739  * The types of the values in the array are the same as the property's type.
740  *
741  * <note><para>This doesn't modify the controlled GObject properties!</para></note>
742  *
743  * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
744  */
745 gboolean
746 gst_controller_get_value_arrays (GstController * self,
747     GstClockTime timestamp, GSList * value_arrays)
748 {
749   gboolean res = TRUE;
750   GSList *node;
751
752   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
753   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
754   g_return_val_if_fail (value_arrays, FALSE);
755
756   for (node = value_arrays; (res && node); node = g_slist_next (node)) {
757     res = gst_controller_get_value_array (self, timestamp, node->data);
758   }
759
760   return (res);
761 }
762
763 /**
764  * gst_controller_get_value_array:
765  * @self: the controller that handles the values
766  * @timestamp: the time that should be processed
767  * @value_array: array to put control-values in
768  *
769  * Function to be able to get an array of values for one element property.
770  *
771  * All fields of @value_array must be filled correctly. Especially the
772  * @value_array->values array must be big enough to keep the requested amount
773  * of values (as indicated by the nbsamples field).
774  *
775  * The type of the values in the array is the same as the property's type.
776  *
777  * <note><para>This doesn't modify the controlled GObject property!</para></note>
778  *
779  * Returns: %TRUE if the given array could be filled, %FALSE otherwise
780  */
781 gboolean
782 gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
783     GstValueArray * value_array)
784 {
785   gboolean res = FALSE;
786   GstControlledProperty *prop;
787
788   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
789   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
790   g_return_val_if_fail (value_array, FALSE);
791   g_return_val_if_fail (value_array->property_name, FALSE);
792   g_return_val_if_fail (value_array->values, FALSE);
793
794   g_mutex_lock (self->lock);
795
796   if ((prop =
797           gst_controller_find_controlled_property (self,
798               value_array->property_name))) {
799     /* get current value_array via control source */
800
801     if (!prop->csource)
802       goto out;
803
804     res =
805         gst_control_source_get_value_array (prop->csource, timestamp,
806         value_array);
807   }
808
809 out:
810   g_mutex_unlock (self->lock);
811   return res;
812 }
813
814 /* gobject handling */
815
816 static void
817 _gst_controller_get_property (GObject * object, guint property_id,
818     GValue * value, GParamSpec * pspec)
819 {
820   GstController *self = GST_CONTROLLER (object);
821
822   switch (property_id) {
823     case PROP_CONTROL_RATE:{
824       /* FIXME: don't change if element is playing, controller works for GObject
825          so this wont work
826
827          GstState c_state, p_state;
828          GstStateChangeReturn ret;
829
830          ret = gst_element_get_state (self->object, &c_state, &p_state, 0);
831          if ((ret == GST_STATE_CHANGE_SUCCESS &&
832          (c_state == GST_STATE_NULL || c_state == GST_STATE_READY)) ||
833          (ret == GST_STATE_CHANGE_ASYNC &&
834          (p_state == GST_STATE_NULL || p_state == GST_STATE_READY))) {
835        */
836       g_value_set_uint64 (value, self->priv->control_rate);
837       /*
838          }
839          else {
840          GST_WARNING ("Changing the control rate is only allowed if the elemnt"
841          " is in NULL or READY");
842          }
843        */
844     }
845       break;
846     default:{
847       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
848     }
849       break;
850   }
851 }
852
853 /* sets the given properties for this object */
854 static void
855 _gst_controller_set_property (GObject * object, guint property_id,
856     const GValue * value, GParamSpec * pspec)
857 {
858   GstController *self = GST_CONTROLLER (object);
859
860   switch (property_id) {
861     case PROP_CONTROL_RATE:{
862       self->priv->control_rate = g_value_get_uint64 (value);
863     }
864       break;
865     default:{
866       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
867     }
868       break;
869   }
870 }
871
872 static void
873 _gst_controller_dispose (GObject * object)
874 {
875   GstController *self = GST_CONTROLLER (object);
876
877   if (self->object != NULL) {
878     g_mutex_lock (self->lock);
879     /* free list of properties */
880     if (self->properties) {
881       GList *node;
882
883       for (node = self->properties; node; node = g_list_next (node)) {
884         GstControlledProperty *prop = node->data;
885
886         gst_controlled_property_free (prop);
887       }
888       g_list_free (self->properties);
889       self->properties = NULL;
890     }
891
892     /* remove controller from object's qdata list */
893     g_object_set_qdata (self->object, priv_gst_controller_key, NULL);
894     g_object_unref (self->object);
895     self->object = NULL;
896     g_mutex_unlock (self->lock);
897   }
898
899   if (G_OBJECT_CLASS (parent_class)->dispose)
900     (G_OBJECT_CLASS (parent_class)->dispose) (object);
901 }
902
903 static void
904 _gst_controller_finalize (GObject * object)
905 {
906   GstController *self = GST_CONTROLLER (object);
907
908   g_mutex_free (self->lock);
909
910   if (G_OBJECT_CLASS (parent_class)->finalize)
911     (G_OBJECT_CLASS (parent_class)->finalize) (object);
912 }
913
914 static void
915 _gst_controller_init (GTypeInstance * instance, gpointer g_class)
916 {
917   GstController *self = GST_CONTROLLER (instance);
918
919   self->lock = g_mutex_new ();
920   self->priv =
921       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_CONTROLLER,
922       GstControllerPrivate);
923   self->priv->last_sync = GST_CLOCK_TIME_NONE;
924   self->priv->control_rate = 100 * GST_MSECOND;
925 }
926
927 static void
928 _gst_controller_class_init (GstControllerClass * klass)
929 {
930   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
931
932   parent_class = g_type_class_peek_parent (klass);
933   g_type_class_add_private (klass, sizeof (GstControllerPrivate));
934
935   gobject_class->set_property = _gst_controller_set_property;
936   gobject_class->get_property = _gst_controller_get_property;
937   gobject_class->dispose = _gst_controller_dispose;
938   gobject_class->finalize = _gst_controller_finalize;
939
940   priv_gst_controller_key = g_quark_from_static_string ("gst::controller");
941
942   /* register properties */
943   g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
944       g_param_spec_uint64 ("control-rate",
945           "control rate",
946           "Controlled properties will be updated at least every control-rate nanoseconds",
947           1, G_MAXUINT, 100 * GST_MSECOND,
948           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
949
950   /* register signals */
951   /* set defaults for overridable methods */
952 }
953
954 GType
955 gst_controller_get_type (void)
956 {
957   static volatile gsize type = 0;
958
959   if (g_once_init_enter (&type)) {
960     GType _type;
961     static const GTypeInfo info = {
962       sizeof (GstControllerClass),
963       NULL,                     /* base_init */
964       NULL,                     /* base_finalize */
965       (GClassInitFunc) _gst_controller_class_init,      /* class_init */
966       NULL,                     /* class_finalize */
967       NULL,                     /* class_data */
968       sizeof (GstController),
969       0,                        /* n_preallocs */
970       (GInstanceInitFunc) _gst_controller_init, /* instance_init */
971       NULL                      /* value_table */
972     };
973     _type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
974     g_once_init_leave (&type, _type);
975   }
976   return type;
977 }
978
979 /* FIXME: backward compatibility functions */
980
981 /*
982  * gst_controlled_property_set_interpolation_mode:
983  * @self: the controlled property object to change
984  * @mode: the new interpolation mode
985  *
986  * Sets the given Interpolation mode for the controlled property and activates
987  * the respective interpolation hooks.
988  *
989  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
990  * directly.
991  *
992  * Returns: %TRUE for success
993  */
994 #ifndef GST_REMOVE_DEPRECATED
995 static gboolean
996 gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
997     GstInterpolateMode mode)
998 {
999   GstInterpolationControlSource *icsource;
1000
1001   /* FIXME: backward compat, add GstInterpolationControlSource */
1002   if (!self->csource)
1003     gst_controlled_property_add_interpolation_control_source (self);
1004
1005   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self->csource),
1006       FALSE);
1007
1008   icsource = GST_INTERPOLATION_CONTROL_SOURCE (self->csource);
1009
1010   return gst_interpolation_control_source_set_interpolation_mode (icsource,
1011       mode);
1012 }
1013 #endif
1014
1015 /**
1016  * gst_controller_set:
1017  * @self: the controller object which handles the properties
1018  * @property_name: the name of the property to set
1019  * @timestamp: the time the control-change is schedules for
1020  * @value: the control-value
1021  *
1022  * Set the value of given controller-handled property at a certain time.
1023  *
1024  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1025  * directly.
1026  *
1027  * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
1028  */
1029 #ifndef GST_REMOVE_DEPRECATED
1030 #ifdef GST_DISABLE_DEPRECATED
1031 gboolean
1032 gst_controller_set (GstController * self, const gchar * property_name,
1033     GstClockTime timestamp, GValue * value);
1034 #endif
1035 gboolean
1036 gst_controller_set (GstController * self, const gchar * property_name,
1037     GstClockTime timestamp, GValue * value)
1038 {
1039   gboolean res = FALSE;
1040   GstControlledProperty *prop;
1041
1042   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1043   g_return_val_if_fail (property_name, FALSE);
1044
1045   g_mutex_lock (self->lock);
1046   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1047     /* FIXME: backward compat, add GstInterpolationControlSource */
1048     if (!prop->csource)
1049       gst_controlled_property_add_interpolation_control_source (prop);
1050
1051     if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1052       goto out;
1053     res =
1054         gst_interpolation_control_source_set (GST_INTERPOLATION_CONTROL_SOURCE
1055         (prop->csource), timestamp, value);
1056   }
1057
1058 out:
1059   g_mutex_unlock (self->lock);
1060
1061   return res;
1062 }
1063 #endif
1064
1065 /**
1066  * gst_controller_set_from_list:
1067  * @self: the controller object which handles the properties
1068  * @property_name: the name of the property to set
1069  * @timedvalues: a list with #GstTimedValue items
1070  *
1071  * Sets multiple timed values at once.
1072  *
1073  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1074  * directly.
1075  *
1076  * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
1077  */
1078 #ifndef GST_REMOVE_DEPRECATED
1079 #ifdef GST_DISABLE_DEPRECATED
1080 gboolean
1081 gst_controller_set_from_list (GstController * self, const gchar * property_name,
1082     GSList * timedvalues);
1083 #endif
1084 gboolean
1085 gst_controller_set_from_list (GstController * self, const gchar * property_name,
1086     GSList * timedvalues)
1087 {
1088   gboolean res = FALSE;
1089   GstControlledProperty *prop;
1090
1091   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1092   g_return_val_if_fail (property_name, FALSE);
1093
1094   g_mutex_lock (self->lock);
1095   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1096     /* FIXME: backward compat, add GstInterpolationControlSource */
1097     if (!prop->csource)
1098       gst_controlled_property_add_interpolation_control_source (prop);
1099
1100     if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1101       goto out;
1102
1103     res =
1104         gst_interpolation_control_source_set_from_list
1105         (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource), timedvalues);
1106   }
1107
1108 out:
1109   g_mutex_unlock (self->lock);
1110
1111   return res;
1112 }
1113 #endif
1114
1115 /**
1116  * gst_controller_unset:
1117  * @self: the controller object which handles the properties
1118  * @property_name: the name of the property to unset
1119  * @timestamp: the time the control-change should be removed from
1120  *
1121  * Used to remove the value of given controller-handled property at a certain
1122  * time.
1123  *
1124  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1125  * directly.
1126  *
1127  * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
1128  */
1129 #ifndef GST_REMOVE_DEPRECATED
1130 #ifdef GST_DISABLE_DEPRECATED
1131 gboolean
1132 gst_controller_unset (GstController * self, const gchar * property_name,
1133     GstClockTime timestamp);
1134 #endif
1135 gboolean
1136 gst_controller_unset (GstController * self, const gchar * property_name,
1137     GstClockTime timestamp)
1138 {
1139   gboolean res = FALSE;
1140   GstControlledProperty *prop;
1141
1142   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1143   g_return_val_if_fail (property_name, FALSE);
1144   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
1145
1146   g_mutex_lock (self->lock);
1147   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1148     if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1149       goto out;
1150
1151     res =
1152         gst_interpolation_control_source_unset (GST_INTERPOLATION_CONTROL_SOURCE
1153         (prop->csource), timestamp);
1154   }
1155
1156 out:
1157   g_mutex_unlock (self->lock);
1158
1159   return res;
1160 }
1161 #endif
1162
1163 /**
1164  * gst_controller_unset_all:
1165  * @self: the controller object which handles the properties
1166  * @property_name: the name of the property to unset
1167  *
1168  * Used to remove all time-stamped values of given controller-handled property
1169  *
1170  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1171  * directly.
1172  *
1173  * Returns: %FALSE if the values couldn't be unset (ex : properties not handled
1174  * by controller), %TRUE otherwise
1175  * Since: 0.10.5
1176  */
1177 #ifndef GST_REMOVE_DEPRECATED
1178 #ifdef GST_DISABLE_DEPRECATED
1179 gboolean gst_controller_unset_all (GstController * self,
1180     const gchar * property_name);
1181 #endif
1182 gboolean
1183 gst_controller_unset_all (GstController * self, const gchar * property_name)
1184 {
1185   GstControlledProperty *prop;
1186
1187   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1188   g_return_val_if_fail (property_name, FALSE);
1189
1190   g_mutex_lock (self->lock);
1191   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1192     if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1193       goto out;
1194
1195     gst_interpolation_control_source_unset_all (GST_INTERPOLATION_CONTROL_SOURCE
1196         (prop->csource));
1197   }
1198
1199 out:
1200   g_mutex_unlock (self->lock);
1201
1202   return TRUE;
1203 }
1204 #endif
1205
1206 /**
1207  * gst_controller_get_all:
1208  * @self: the controller to get the list from
1209  * @property_name: the name of the property to get the list for
1210  *
1211  * Returns a read-only copy of the list of #GstTimedValue for the given property.
1212  * Free the list after done with it.
1213  *
1214  * <note><para>This doesn't modify the controlled GObject property!</para></note>
1215  *
1216  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1217  * directly.
1218  *
1219  * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
1220  */
1221 #ifndef GST_REMOVE_DEPRECATED
1222 #ifdef GST_DISABLE_DEPRECATED
1223 const GList *gst_controller_get_all (GstController * self,
1224     const gchar * property_name);
1225 #endif
1226 const GList *
1227 gst_controller_get_all (GstController * self, const gchar * property_name)
1228 {
1229   const GList *res = NULL;
1230   GstControlledProperty *prop;
1231
1232   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
1233   g_return_val_if_fail (property_name, NULL);
1234
1235   g_mutex_lock (self->lock);
1236   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1237     if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
1238       goto out;
1239
1240     res =
1241         gst_interpolation_control_source_get_all
1242         (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource));
1243   }
1244
1245 out:
1246   g_mutex_unlock (self->lock);
1247
1248   return res;
1249 }
1250 #endif
1251
1252 /**
1253  * gst_controller_set_interpolation_mode:
1254  * @self: the controller object
1255  * @property_name: the name of the property for which to change the interpolation
1256  * @mode: interpolation mode
1257  *
1258  * Sets the given interpolation mode on the given property.
1259  *
1260  * <note><para>User interpolation is not yet available and quadratic interpolation
1261  * is deprecated and maps to cubic interpolation.</para></note>
1262  *
1263  * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
1264  * directly.
1265  *
1266  * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
1267  */
1268 #ifndef GST_REMOVE_DEPRECATED
1269 #ifdef GST_DISABLE_DEPRECATED
1270 gboolean
1271 gst_controller_set_interpolation_mode (GstController * self,
1272     const gchar * property_name, GstInterpolateMode mode);
1273 #endif
1274 gboolean
1275 gst_controller_set_interpolation_mode (GstController * self,
1276     const gchar * property_name, GstInterpolateMode mode)
1277 {
1278   gboolean res = FALSE;
1279   GstControlledProperty *prop;
1280
1281   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
1282   g_return_val_if_fail (property_name, FALSE);
1283
1284   g_mutex_lock (self->lock);
1285   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
1286     res = gst_controlled_property_set_interpolation_mode (prop, mode);
1287   }
1288   g_mutex_unlock (self->lock);
1289
1290   return res;
1291 }
1292 #endif