controller: Add g-i annotations and remove "Since:" markers
[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 /*
102  * gst_controlled_property_new:
103  * @object: for which object the controlled property should be set up
104  * @name: the name of the property to be controlled
105  *
106  * Private method which initializes the fields of a new controlled property
107  * structure.
108  *
109  * Returns: a freshly allocated structure or %NULL
110  */
111 static GstControlledProperty *
112 gst_controlled_property_new (GObject * object, const gchar * name)
113 {
114   GstControlledProperty *prop = NULL;
115   GParamSpec *pspec;
116
117   GST_INFO ("trying to put property '%s' under control", name);
118
119   /* check if the object has a property of that name */
120   if ((pspec =
121           g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
122     GST_DEBUG ("  psec->flags : 0x%08x", pspec->flags);
123
124     /* check if this param is witable && controlable && !construct-only */
125     g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE |
126                 GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) ==
127         (G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL);
128
129     if ((prop = g_slice_new (GstControlledProperty))) {
130       prop->pspec = pspec;
131       prop->name = pspec->name;
132       prop->csource = NULL;
133       prop->disabled = FALSE;
134       memset (&prop->last_value, 0, sizeof (GValue));
135       g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
136     }
137   } else {
138     GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
139         name);
140   }
141   return prop;
142 }
143
144 /*
145  * gst_controlled_property_free:
146  * @prop: the object to free
147  *
148  * Private method which frees all data allocated by a #GstControlledProperty
149  * instance.
150  */
151 static void
152 gst_controlled_property_free (GstControlledProperty * prop)
153 {
154   if (prop->csource)
155     g_object_unref (prop->csource);
156   g_value_unset (&prop->last_value);
157   g_slice_free (GstControlledProperty, prop);
158 }
159
160 /*
161  * gst_controller_find_controlled_property:
162  * @self: the controller object to search for a property in
163  * @name: the gobject property name to look for
164  *
165  * Searches the list of properties under control.
166  *
167  * Returns: a #GstControlledProperty object of %NULL if the property is not
168  * being controlled.
169  */
170 static GstControlledProperty *
171 gst_controller_find_controlled_property (GstController * self,
172     const gchar * name)
173 {
174   GstControlledProperty *prop;
175   GList *node;
176
177   for (node = self->properties; node; node = g_list_next (node)) {
178     prop = node->data;
179     /* FIXME: eventually use GQuark to speed it up */
180     if (!strcmp (prop->name, name)) {
181       return prop;
182     }
183   }
184   GST_DEBUG ("controller does not (yet) manage property '%s'", name);
185
186   return NULL;
187 }
188
189 /*
190  * gst_controller_add_property:
191  * @self: the controller object or %NULL if none yet exists
192  * @object: object to bind the property
193  * @name: name of projecty in @object
194  * @ref_existing: pointer to flag that tracks if we need to ref an existing
195  *   controller still
196  *
197  * Creates a new #GstControlledProperty if there is none for property @name yet.
198  * In case this is the first controlled propery, it creates the controller as
199  * well.
200  *
201  * Returns: a newly created controller object or reffed existing one with the
202  * given property bound.
203  */
204 static GstController *
205 gst_controller_add_property (GstController * self, GObject * object,
206     const gchar * name, gboolean * ref_existing)
207 {
208   /* test if this property isn't yet controlled */
209   if (!self || !gst_controller_find_controlled_property (self, name)) {
210     GstControlledProperty *prop;
211
212     /* create GstControlledProperty and add to self->propeties List */
213     if ((prop = gst_controlled_property_new (object, name))) {
214       /* if we don't have a controller object yet, now is the time to create one */
215       if (!self) {
216         self = g_object_newv (GST_TYPE_CONTROLLER, 0, NULL);
217         self->object = g_object_ref (object);
218         /* store the controller */
219         g_object_set_qdata (object, priv_gst_controller_key, self);
220         *ref_existing = FALSE;
221       } else {
222         /* only want one single _ref(), even for multiple properties */
223         if (*ref_existing) {
224           g_object_ref (self);
225           *ref_existing = FALSE;
226           GST_INFO ("returning existing controller");
227         }
228       }
229       self->properties = g_list_prepend (self->properties, prop);
230     }
231   } else {
232     GST_WARNING ("trying to control property %s again", name);
233     if (*ref_existing) {
234       g_object_ref (self);
235       *ref_existing = FALSE;
236     }
237   }
238   return self;
239 }
240
241 /* methods */
242
243 /**
244  * gst_controller_new_valist:
245  * @object: the object of which some properties should be controlled
246  * @var_args: %NULL terminated list of property names that should be controlled
247  *
248  * Creates a new GstController for the given object's properties
249  *
250  * Returns: the new controller.
251  */
252 GstController *
253 gst_controller_new_valist (GObject * object, va_list var_args)
254 {
255   GstController *self;
256   gboolean ref_existing = TRUE;
257   gchar *name;
258
259   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
260
261   GST_INFO ("setting up a new controller");
262
263   self = g_object_get_qdata (object, priv_gst_controller_key);
264   /* create GstControlledProperty for each property */
265   while ((name = va_arg (var_args, gchar *))) {
266     self = gst_controller_add_property (self, object, name, &ref_existing);
267   }
268   va_end (var_args);
269
270   if (self)
271     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
272   return self;
273 }
274
275 /**
276  * gst_controller_new_list:
277  * @object: the object of which some properties should be controlled
278  * @list: (transfer none) (element-type utf8): list of property names
279  *   that should be controlled
280  *
281  * Creates a new GstController for the given object's properties
282  *
283  * Rename to: gst_controller_new
284  *
285  * Returns: the new controller.
286  */
287 GstController *
288 gst_controller_new_list (GObject * object, GList * list)
289 {
290   GstController *self;
291   gboolean ref_existing = TRUE;
292   gchar *name;
293   GList *node;
294
295   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
296
297   GST_INFO ("setting up a new controller");
298
299   self = g_object_get_qdata (object, priv_gst_controller_key);
300   /* create GstControlledProperty for each property */
301   for (node = list; node; node = g_list_next (node)) {
302     name = (gchar *) node->data;
303     self = gst_controller_add_property (self, object, name, &ref_existing);
304   }
305
306   if (self)
307     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
308   return self;
309 }
310
311 /**
312  * gst_controller_new:
313  * @object: the object of which some properties should be controlled
314  * @...: %NULL terminated list of property names that should be controlled
315  *
316  * Creates a new GstController for the given object's properties
317  *
318  * Returns: the new controller.
319  */
320 GstController *
321 gst_controller_new (GObject * object, ...)
322 {
323   GstController *self;
324   va_list var_args;
325
326   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
327
328   va_start (var_args, object);
329   self = gst_controller_new_valist (object, var_args);
330   va_end (var_args);
331
332   return self;
333 }
334
335 /**
336  * gst_controller_remove_properties_valist:
337  * @self: the controller object from which some properties should be removed
338  * @var_args: %NULL terminated list of property names that should be removed
339  *
340  * Removes the given object properties from the controller
341  *
342  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
343  */
344 gboolean
345 gst_controller_remove_properties_valist (GstController * self, va_list var_args)
346 {
347   gboolean res = TRUE;
348   GstControlledProperty *prop;
349   gchar *name;
350
351   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
352
353   while ((name = va_arg (var_args, gchar *))) {
354     /* find the property in the properties list of the controller, remove and free it */
355     g_mutex_lock (self->lock);
356     if ((prop = gst_controller_find_controlled_property (self, name))) {
357       self->properties = g_list_remove (self->properties, prop);
358       //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
359       gst_controlled_property_free (prop);
360     } else {
361       res = FALSE;
362     }
363     g_mutex_unlock (self->lock);
364   }
365
366   return res;
367 }
368
369 /**
370  * gst_controller_remove_properties_list:
371  * @self: the controller object from which some properties should be removed
372  * @list: (transfer none) (element-type utf8): #GList of property names that
373  *   should be removed
374  *
375  * Removes the given object properties from the controller
376  *
377  * Rename to: gst_controller_remove_properties
378  *
379  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
380  */
381 gboolean
382 gst_controller_remove_properties_list (GstController * self, GList * list)
383 {
384   gboolean res = TRUE;
385   GstControlledProperty *prop;
386   gchar *name;
387   GList *tmp;
388
389   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
390
391   for (tmp = list; tmp; tmp = g_list_next (tmp)) {
392     name = (gchar *) tmp->data;
393
394     /* find the property in the properties list of the controller, remove and free it */
395     g_mutex_lock (self->lock);
396     if ((prop = gst_controller_find_controlled_property (self, name))) {
397       self->properties = g_list_remove (self->properties, prop);
398       //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
399       gst_controlled_property_free (prop);
400     } else {
401       res = FALSE;
402     }
403     g_mutex_unlock (self->lock);
404   }
405
406   return res;
407 }
408
409 /**
410  * gst_controller_remove_properties:
411  * @self: the controller object from which some properties should be removed
412  * @...: %NULL terminated list of property names that should be removed
413  *
414  * Removes the given object properties from the controller
415  *
416  * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
417  */
418 gboolean
419 gst_controller_remove_properties (GstController * self, ...)
420 {
421   gboolean res;
422   va_list var_args;
423
424   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
425
426   va_start (var_args, self);
427   res = gst_controller_remove_properties_valist (self, var_args);
428   va_end (var_args);
429
430   return res;
431 }
432
433 /**
434  * gst_controller_set_property_disabled:
435  * @self: the #GstController which should be disabled
436  * @property_name: property to disable
437  * @disabled: boolean that specifies whether to disable the controller
438  * or not.
439  *
440  * This function is used to disable the #GstController on a property for
441  * some time, i.e. gst_controller_sync_values() will do nothing for the
442  * property.
443  */
444
445 void
446 gst_controller_set_property_disabled (GstController * self,
447     const gchar * property_name, gboolean disabled)
448 {
449   GstControlledProperty *prop;
450
451   g_return_if_fail (GST_IS_CONTROLLER (self));
452   g_return_if_fail (property_name);
453
454   g_mutex_lock (self->lock);
455   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
456     prop->disabled = disabled;
457   }
458   g_mutex_unlock (self->lock);
459 }
460
461
462 /**
463  * gst_controller_set_disabled:
464  * @self: the #GstController which should be disabled
465  * @disabled: boolean that specifies whether to disable the controller
466  * or not.
467  *
468  * This function is used to disable all properties of the #GstController
469  * for some time, i.e. gst_controller_sync_values() will do nothing.
470  */
471
472 void
473 gst_controller_set_disabled (GstController * self, gboolean disabled)
474 {
475   GList *node;
476   GstControlledProperty *prop;
477
478   g_return_if_fail (GST_IS_CONTROLLER (self));
479
480   g_mutex_lock (self->lock);
481   for (node = self->properties; node; node = node->next) {
482     prop = node->data;
483     prop->disabled = disabled;
484   }
485   g_mutex_unlock (self->lock);
486 }
487
488 /**
489  * gst_controller_set_control_source:
490  * @self: the controller object
491  * @property_name: name of the property for which the #GstControlSource should be set
492  * @csource: the #GstControlSource that should be used for the property
493  *
494  * Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
495  * for this property it will be unreferenced.
496  *
497  * Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
498  * couldn't be bound to the property, %TRUE if everything worked as expected.
499  */
500 gboolean
501 gst_controller_set_control_source (GstController * self,
502     const gchar * property_name, GstControlSource * csource)
503 {
504   GstControlledProperty *prop;
505   gboolean ret = FALSE;
506
507   g_mutex_lock (self->lock);
508   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
509     GstControlSource *old = prop->csource;
510
511     if (csource && (ret = gst_control_source_bind (csource, prop->pspec))) {
512       g_object_ref (csource);
513       prop->csource = csource;
514     } else if (!csource) {
515       ret = TRUE;
516       prop->csource = NULL;
517     }
518
519     if (ret && old)
520       g_object_unref (old);
521   }
522   g_mutex_unlock (self->lock);
523
524   return ret;
525 }
526
527 /**
528  * gst_controller_get_control_source:
529  * @self: the controller object
530  * @property_name: name of the property for which the #GstControlSource should be get
531  *
532  * Gets the corresponding #GstControlSource for the property. This should be unreferenced
533  * again after use.
534  *
535  * Returns: (transfer full): the #GstControlSource for @property_name or NULL if
536  * the property is not controlled by this controller or no #GstControlSource was
537  * assigned yet.
538  */
539 GstControlSource *
540 gst_controller_get_control_source (GstController * self,
541     const gchar * property_name)
542 {
543   GstControlledProperty *prop;
544   GstControlSource *ret = NULL;
545
546   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
547   g_return_val_if_fail (property_name, NULL);
548
549   g_mutex_lock (self->lock);
550   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
551     ret = prop->csource;
552   }
553   g_mutex_unlock (self->lock);
554
555   if (ret)
556     g_object_ref (ret);
557
558   return ret;
559 }
560
561 /**
562  * gst_controller_get:
563  * @self: the controller object which handles the properties
564  * @property_name: the name of the property to get
565  * @timestamp: the time the control-change should be read from
566  *
567  * Gets the value for the given controller-handled property at the requested
568  * time.
569  *
570  * Returns: the GValue of the property at the given time, or %NULL if the
571  * property isn't handled by the controller
572  */
573 GValue *
574 gst_controller_get (GstController * self, const gchar * property_name,
575     GstClockTime timestamp)
576 {
577   GstControlledProperty *prop;
578   GValue *val = NULL;
579
580   g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
581   g_return_val_if_fail (property_name, NULL);
582   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
583
584   g_mutex_lock (self->lock);
585   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
586     val = g_new0 (GValue, 1);
587     g_value_init (val, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
588     if (prop->csource) {
589       gboolean res;
590
591       /* get current value via control source */
592       res = gst_control_source_get_value (prop->csource, timestamp, val);
593       if (!res) {
594         g_free (val);
595         val = NULL;
596       }
597     } else {
598       g_object_get_property (self->object, prop->name, val);
599     }
600   }
601   g_mutex_unlock (self->lock);
602
603   return val;
604 }
605
606 /**
607  * gst_controller_suggest_next_sync:
608  * @self: the controller that handles the values
609  *
610  * Returns a suggestion for timestamps where buffers should be split
611  * to get best controller results.
612  *
613  * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
614  * if no control-rate was set.
615  */
616 GstClockTime
617 gst_controller_suggest_next_sync (GstController * self)
618 {
619   GstClockTime ret;
620
621   g_return_val_if_fail (GST_IS_CONTROLLER (self), GST_CLOCK_TIME_NONE);
622   g_return_val_if_fail (self->priv->control_rate != GST_CLOCK_TIME_NONE,
623       GST_CLOCK_TIME_NONE);
624
625   g_mutex_lock (self->lock);
626
627   /* TODO: Implement more logic, depending on interpolation mode
628    * and control points
629    * FIXME: we need playback direction
630    */
631   ret = self->priv->last_sync + self->priv->control_rate;
632
633   g_mutex_unlock (self->lock);
634
635   return ret;
636 }
637
638 /**
639  * gst_controller_sync_values:
640  * @self: the controller that handles the values
641  * @timestamp: the time that should be processed
642  *
643  * Sets the properties of the element, according to the controller that (maybe)
644  * handles them and for the given timestamp.
645  *
646  * If this function fails, it is most likely the application developers fault.
647  * Most probably the control sources are not setup correctly.
648  *
649  * Returns: %TRUE if the controller values could be applied to the object
650  * properties, %FALSE otherwise
651  */
652 gboolean
653 gst_controller_sync_values (GstController * self, GstClockTime timestamp)
654 {
655   GstControlledProperty *prop;
656   GList *node;
657   gboolean ret = TRUE, val_ret;
658   GValue value = { 0, };
659
660   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
661   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
662
663   GST_LOG ("sync_values");
664
665   g_mutex_lock (self->lock);
666   g_object_freeze_notify (self->object);
667   /* go over the controlled properties of the controller */
668   for (node = self->properties; node; node = g_list_next (node)) {
669     prop = node->data;
670
671     if (!prop->csource || prop->disabled)
672       continue;
673
674     GST_LOG ("property '%s' at ts=%" G_GUINT64_FORMAT, prop->name, timestamp);
675
676     /* we can make this faster
677      * http://bugzilla.gnome.org/show_bug.cgi?id=536939
678      */
679     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
680     val_ret = gst_control_source_get_value (prop->csource, timestamp, &value);
681     if (G_LIKELY (val_ret)) {
682       /* always set the value for first time, but then only if it changed
683        * this should limit g_object_notify invocations.
684        * FIXME: can we detect negative playback rates?
685        */
686       if ((timestamp < self->priv->last_sync) ||
687           gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
688         g_object_set_property (self->object, prop->name, &value);
689         g_value_copy (&value, &prop->last_value);
690       }
691     } else {
692       GST_DEBUG ("no control value for param %s", prop->name);
693     }
694     g_value_unset (&value);
695     ret &= val_ret;
696   }
697   self->priv->last_sync = timestamp;
698   g_object_thaw_notify (self->object);
699
700   g_mutex_unlock (self->lock);
701
702   return ret;
703 }
704
705 /**
706  * gst_controller_get_value_arrays:
707  * @self: the controller that handles the values
708  * @timestamp: the time that should be processed
709  * @value_arrays: list to return the control-values in
710  *
711  * Function to be able to get an array of values for one or more given element
712  * properties.
713  *
714  * All fields of the %GstValueArray in the list must be filled correctly.
715  * Especially the GstValueArray->values arrays must be big enough to keep
716  * the requested amount of values.
717  *
718  * The types of the values in the array are the same as the property's type.
719  *
720  * <note><para>This doesn't modify the controlled GObject properties!</para></note>
721  *
722  * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
723  */
724 gboolean
725 gst_controller_get_value_arrays (GstController * self,
726     GstClockTime timestamp, GSList * value_arrays)
727 {
728   gboolean res = TRUE;
729   GSList *node;
730
731   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
732   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
733   g_return_val_if_fail (value_arrays, FALSE);
734
735   for (node = value_arrays; (res && node); node = g_slist_next (node)) {
736     res = gst_controller_get_value_array (self, timestamp, node->data);
737   }
738
739   return (res);
740 }
741
742 /**
743  * gst_controller_get_value_array:
744  * @self: the controller that handles the values
745  * @timestamp: the time that should be processed
746  * @value_array: array to put control-values in
747  *
748  * Function to be able to get an array of values for one element property.
749  *
750  * All fields of @value_array must be filled correctly. Especially the
751  * @value_array->values array must be big enough to keep the requested amount
752  * of values (as indicated by the nbsamples field).
753  *
754  * The type of the values in the array is the same as the property's type.
755  *
756  * <note><para>This doesn't modify the controlled GObject property!</para></note>
757  *
758  * Returns: %TRUE if the given array could be filled, %FALSE otherwise
759  */
760 gboolean
761 gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
762     GstValueArray * value_array)
763 {
764   gboolean res = FALSE;
765   GstControlledProperty *prop;
766
767   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
768   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
769   g_return_val_if_fail (value_array, FALSE);
770   g_return_val_if_fail (value_array->property_name, FALSE);
771   g_return_val_if_fail (value_array->values, FALSE);
772
773   g_mutex_lock (self->lock);
774
775   if ((prop =
776           gst_controller_find_controlled_property (self,
777               value_array->property_name))) {
778     /* get current value_array via control source */
779
780     if (!prop->csource)
781       goto out;
782
783     res =
784         gst_control_source_get_value_array (prop->csource, timestamp,
785         value_array);
786   }
787
788 out:
789   g_mutex_unlock (self->lock);
790   return res;
791 }
792
793 /* gobject handling */
794
795 static void
796 _gst_controller_get_property (GObject * object, guint property_id,
797     GValue * value, GParamSpec * pspec)
798 {
799   GstController *self = GST_CONTROLLER (object);
800
801   switch (property_id) {
802     case PROP_CONTROL_RATE:{
803       /* FIXME: don't change if element is playing, controller works for GObject
804          so this wont work
805
806          GstState c_state, p_state;
807          GstStateChangeReturn ret;
808
809          ret = gst_element_get_state (self->object, &c_state, &p_state, 0);
810          if ((ret == GST_STATE_CHANGE_SUCCESS &&
811          (c_state == GST_STATE_NULL || c_state == GST_STATE_READY)) ||
812          (ret == GST_STATE_CHANGE_ASYNC &&
813          (p_state == GST_STATE_NULL || p_state == GST_STATE_READY))) {
814        */
815       g_value_set_uint64 (value, self->priv->control_rate);
816       /*
817          }
818          else {
819          GST_WARNING ("Changing the control rate is only allowed if the elemnt"
820          " is in NULL or READY");
821          }
822        */
823     }
824       break;
825     default:{
826       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
827     }
828       break;
829   }
830 }
831
832 /* sets the given properties for this object */
833 static void
834 _gst_controller_set_property (GObject * object, guint property_id,
835     const GValue * value, GParamSpec * pspec)
836 {
837   GstController *self = GST_CONTROLLER (object);
838
839   switch (property_id) {
840     case PROP_CONTROL_RATE:{
841       self->priv->control_rate = g_value_get_uint64 (value);
842     }
843       break;
844     default:{
845       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
846     }
847       break;
848   }
849 }
850
851 static void
852 _gst_controller_dispose (GObject * object)
853 {
854   GstController *self = GST_CONTROLLER (object);
855
856   if (self->object != NULL) {
857     g_mutex_lock (self->lock);
858     /* free list of properties */
859     if (self->properties) {
860       GList *node;
861
862       for (node = self->properties; node; node = g_list_next (node)) {
863         GstControlledProperty *prop = node->data;
864
865         gst_controlled_property_free (prop);
866       }
867       g_list_free (self->properties);
868       self->properties = NULL;
869     }
870
871     /* remove controller from object's qdata list */
872     g_object_set_qdata (self->object, priv_gst_controller_key, NULL);
873     g_object_unref (self->object);
874     self->object = NULL;
875     g_mutex_unlock (self->lock);
876   }
877
878   if (G_OBJECT_CLASS (parent_class)->dispose)
879     (G_OBJECT_CLASS (parent_class)->dispose) (object);
880 }
881
882 static void
883 _gst_controller_finalize (GObject * object)
884 {
885   GstController *self = GST_CONTROLLER (object);
886
887   g_mutex_free (self->lock);
888
889   if (G_OBJECT_CLASS (parent_class)->finalize)
890     (G_OBJECT_CLASS (parent_class)->finalize) (object);
891 }
892
893 static void
894 _gst_controller_init (GTypeInstance * instance, gpointer g_class)
895 {
896   GstController *self = GST_CONTROLLER (instance);
897
898   self->lock = g_mutex_new ();
899   self->priv =
900       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_CONTROLLER,
901       GstControllerPrivate);
902   self->priv->last_sync = GST_CLOCK_TIME_NONE;
903   self->priv->control_rate = 100 * GST_MSECOND;
904 }
905
906 static void
907 _gst_controller_class_init (GstControllerClass * klass)
908 {
909   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
910
911   parent_class = g_type_class_peek_parent (klass);
912   g_type_class_add_private (klass, sizeof (GstControllerPrivate));
913
914   gobject_class->set_property = _gst_controller_set_property;
915   gobject_class->get_property = _gst_controller_get_property;
916   gobject_class->dispose = _gst_controller_dispose;
917   gobject_class->finalize = _gst_controller_finalize;
918
919   priv_gst_controller_key = g_quark_from_static_string ("gst::controller");
920
921   /* register properties */
922   g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
923       g_param_spec_uint64 ("control-rate",
924           "control rate",
925           "Controlled properties will be updated at least every control-rate nanoseconds",
926           1, G_MAXUINT, 100 * GST_MSECOND,
927           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
928
929   /* register signals */
930   /* set defaults for overridable methods */
931 }
932
933 GType
934 gst_controller_get_type (void)
935 {
936   static volatile gsize type = 0;
937
938   if (g_once_init_enter (&type)) {
939     GType _type;
940     static const GTypeInfo info = {
941       sizeof (GstControllerClass),
942       NULL,                     /* base_init */
943       NULL,                     /* base_finalize */
944       (GClassInitFunc) _gst_controller_class_init,      /* class_init */
945       NULL,                     /* class_finalize */
946       NULL,                     /* class_data */
947       sizeof (GstController),
948       0,                        /* n_preallocs */
949       (GInstanceInitFunc) _gst_controller_init, /* instance_init */
950       NULL                      /* value_table */
951     };
952     _type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
953     g_once_init_leave (&type, _type);
954   }
955   return type;
956 }