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