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