Merge remote-tracking branch 'origin/master' into 0.11
[platform/upstream/gstreamer.git] / libs / gst / controller / gsttimedvaluecontrolsource.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *               2011 Stefan Sauer <ensonic@users.sf.net>
5  *
6  * gsttimedvaluecontrolsource.c: Base class for timeed value based control
7  *                               sources
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:gsttimedvaluecontrolsource
27  * @short_description: timed value control source base class
28  *
29  * Base class for #GstContrlSources that use time-stamped values.
30  *
31  * When overriding bind, chain up first to give this bind implementation a
32  * chance to setup things.
33  *
34  * All functions are MT-safe.
35  *
36  */
37
38 #include <glib-object.h>
39 #include <gst/gst.h>
40
41 #include "gstinterpolationcontrolsource.h"
42 #include "gstinterpolationcontrolsourceprivate.h"
43 #include "gst/glib-compat-private.h"
44
45 #define GST_CAT_DEFAULT controller_debug
46 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
47
48 #define _do_init \
49   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "timed value control source", 0, \
50     "timed value control source base class")
51
52 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
53     gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
54
55 /*
56  * gst_control_point_free:
57  * @prop: the object to free
58  *
59  * Private method which frees all data allocated by a #GstControlPoint
60  * instance.
61  */
62 static void
63 gst_control_point_free (GstControlPoint * cp)
64 {
65   g_return_if_fail (cp);
66
67   g_value_unset (&cp->value);
68   g_slice_free (GstControlPoint, cp);
69 }
70
71 static void
72 gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
73 {
74   GstControlSource *csource = (GstControlSource *) self;
75
76   csource->get_value = NULL;
77   csource->get_value_array = NULL;
78
79   self->type = self->base = G_TYPE_INVALID;
80
81   if (G_IS_VALUE (&self->default_value))
82     g_value_unset (&self->default_value);
83   if (G_IS_VALUE (&self->minimum_value))
84     g_value_unset (&self->minimum_value);
85   if (G_IS_VALUE (&self->maximum_value))
86     g_value_unset (&self->maximum_value);
87
88   if (self->values) {
89     g_sequence_free (self->values);
90     self->values = NULL;
91   }
92
93   self->nvalues = 0;
94   self->valid_cache = FALSE;
95 }
96
97 static gboolean
98 gst_timed_value_control_source_bind (GstControlSource * source,
99     GParamSpec * pspec)
100 {
101   GType type, base;
102   GstTimedValueControlSource *self = (GstTimedValueControlSource *) source;
103   gboolean ret = TRUE;
104
105   /* get the fundamental base type */
106   self->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
107   while ((type = g_type_parent (type)))
108     base = type;
109
110   self->base = base;
111   /* restore type */
112   type = self->type;
113
114   switch (base) {
115     case G_TYPE_INT:{
116       GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
117
118       g_value_init (&self->default_value, type);
119       g_value_set_int (&self->default_value, tpspec->default_value);
120       g_value_init (&self->minimum_value, type);
121       g_value_set_int (&self->minimum_value, tpspec->minimum);
122       g_value_init (&self->maximum_value, type);
123       g_value_set_int (&self->maximum_value, tpspec->maximum);
124       break;
125     }
126     case G_TYPE_UINT:{
127       GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
128
129       g_value_init (&self->default_value, type);
130       g_value_set_uint (&self->default_value, tpspec->default_value);
131       g_value_init (&self->minimum_value, type);
132       g_value_set_uint (&self->minimum_value, tpspec->minimum);
133       g_value_init (&self->maximum_value, type);
134       g_value_set_uint (&self->maximum_value, tpspec->maximum);
135       break;
136     }
137     case G_TYPE_LONG:{
138       GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
139
140       g_value_init (&self->default_value, type);
141       g_value_set_long (&self->default_value, tpspec->default_value);
142       g_value_init (&self->minimum_value, type);
143       g_value_set_long (&self->minimum_value, tpspec->minimum);
144       g_value_init (&self->maximum_value, type);
145       g_value_set_long (&self->maximum_value, tpspec->maximum);
146       break;
147     }
148     case G_TYPE_ULONG:{
149       GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
150
151       g_value_init (&self->default_value, type);
152       g_value_set_ulong (&self->default_value, tpspec->default_value);
153       g_value_init (&self->minimum_value, type);
154       g_value_set_ulong (&self->minimum_value, tpspec->minimum);
155       g_value_init (&self->maximum_value, type);
156       g_value_set_ulong (&self->maximum_value, tpspec->maximum);
157       break;
158     }
159     case G_TYPE_INT64:{
160       GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
161
162       g_value_init (&self->default_value, type);
163       g_value_set_int64 (&self->default_value, tpspec->default_value);
164       g_value_init (&self->minimum_value, type);
165       g_value_set_int64 (&self->minimum_value, tpspec->minimum);
166       g_value_init (&self->maximum_value, type);
167       g_value_set_int64 (&self->maximum_value, tpspec->maximum);
168       break;
169     }
170     case G_TYPE_UINT64:{
171       GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
172
173       g_value_init (&self->default_value, type);
174       g_value_set_uint64 (&self->default_value, tpspec->default_value);
175       g_value_init (&self->minimum_value, type);
176       g_value_set_uint64 (&self->minimum_value, tpspec->minimum);
177       g_value_init (&self->maximum_value, type);
178       g_value_set_uint64 (&self->maximum_value, tpspec->maximum);
179       break;
180     }
181     case G_TYPE_FLOAT:{
182       GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
183
184       g_value_init (&self->default_value, type);
185       g_value_set_float (&self->default_value, tpspec->default_value);
186       g_value_init (&self->minimum_value, type);
187       g_value_set_float (&self->minimum_value, tpspec->minimum);
188       g_value_init (&self->maximum_value, type);
189       g_value_set_float (&self->maximum_value, tpspec->maximum);
190       break;
191     }
192     case G_TYPE_DOUBLE:{
193       GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
194
195       g_value_init (&self->default_value, type);
196       g_value_set_double (&self->default_value, tpspec->default_value);
197       g_value_init (&self->minimum_value, type);
198       g_value_set_double (&self->minimum_value, tpspec->minimum);
199       g_value_init (&self->maximum_value, type);
200       g_value_set_double (&self->maximum_value, tpspec->maximum);
201       break;
202     }
203     case G_TYPE_BOOLEAN:{
204       GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
205
206       g_value_init (&self->default_value, type);
207       g_value_set_boolean (&self->default_value, tpspec->default_value);
208       break;
209     }
210     case G_TYPE_ENUM:{
211       GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
212
213       g_value_init (&self->default_value, type);
214       g_value_set_enum (&self->default_value, tpspec->default_value);
215       break;
216     }
217     case G_TYPE_STRING:{
218       GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
219
220       g_value_init (&self->default_value, type);
221       g_value_set_string (&self->default_value, tpspec->default_value);
222       break;
223     }
224     default:
225       GST_WARNING ("incomplete implementation for paramspec type '%s'",
226           G_PARAM_SPEC_TYPE_NAME (pspec));
227       ret = FALSE;
228       break;
229   }
230
231   if (ret) {
232     self->valid_cache = FALSE;
233     self->nvalues = 0;
234   } else {
235     gst_timed_value_control_source_reset (self);
236   }
237
238   return ret;
239 }
240
241 /*
242  * gst_control_point_compare:
243  * @p1: a pointer to a #GstControlPoint
244  * @p2: a pointer to a #GstControlPoint
245  *
246  * Compare function for g_list operations that operates on two #GstControlPoint
247  * parameters.
248  */
249 static gint
250 gst_control_point_compare (gconstpointer p1, gconstpointer p2)
251 {
252   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
253   GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
254
255   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
256 }
257
258 /*
259  * gst_control_point_find:
260  * @p1: a pointer to a #GstControlPoint
261  * @p2: a pointer to a #GstClockTime
262  *
263  * Compare function for g_list operations that operates on a #GstControlPoint and
264  * a #GstClockTime.
265  */
266 static gint
267 gst_control_point_find (gconstpointer p1, gconstpointer p2)
268 {
269   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
270   GstClockTime ct2 = *(GstClockTime *) p2;
271
272   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
273 }
274
275 static GstControlPoint *
276 _make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
277     const GValue * value)
278 {
279   GstControlPoint *cp;
280
281   /* create a new GstControlPoint */
282   cp = g_slice_new0 (GstControlPoint);
283   cp->timestamp = timestamp;
284   g_value_init (&cp->value, self->type);
285   g_value_copy (value, &cp->value);
286
287   return cp;
288 }
289
290 static void
291 gst_timed_value_control_source_set_internal (GstTimedValueControlSource *
292     self, GstClockTime timestamp, const GValue * value)
293 {
294   GSequenceIter *iter;
295
296   /* check if a control point for the timestamp already exists */
297
298   /* iter contains the iter right *after* timestamp */
299   if (G_LIKELY (self->values)) {
300     iter =
301         g_sequence_search (self->values, &timestamp,
302         (GCompareDataFunc) gst_control_point_find, NULL);
303     if (iter) {
304       GSequenceIter *prev = g_sequence_iter_prev (iter);
305       GstControlPoint *cp = g_sequence_get (prev);
306
307       /* If the timestamp is the same just update the control point value */
308       if (cp->timestamp == timestamp) {
309         /* update control point */
310         g_value_reset (&cp->value);
311         g_value_copy (value, &cp->value);
312         goto done;
313       }
314     }
315   } else {
316     self->values = g_sequence_new ((GDestroyNotify) gst_control_point_free);
317   }
318
319   /* sort new cp into the prop->values list */
320   g_sequence_insert_sorted (self->values, _make_new_cp (self, timestamp,
321           value), (GCompareDataFunc) gst_control_point_compare, NULL);
322   self->nvalues++;
323
324 done:
325   self->valid_cache = FALSE;
326 }
327
328 /**
329  * gst_timed_value_control_source_find_control_point_iter:
330  * @self: the control source to search in
331  * @timestamp: the search key
332  *
333  * Find last value before given timestamp in control point list.
334  * If all values in the control point list come after the given
335  * timestamp or no values exist, %NULL is returned.
336  *
337  * For use in control source implementations.
338  *
339  * Returns: the found #GSequenceIter or %NULL
340  */
341 GSequenceIter *gst_timed_value_control_source_find_control_point_iter
342     (GstTimedValueControlSource * self, GstClockTime timestamp)
343 {
344   GSequenceIter *iter;
345
346   if (!self->values)
347     return NULL;
348
349   iter =
350       g_sequence_search (self->values, &timestamp,
351       (GCompareDataFunc) gst_control_point_find, NULL);
352
353   /* g_sequence_search() returns the iter where timestamp
354    * would be inserted, i.e. the iter > timestamp, so
355    * we need to get the previous one. And of course, if
356    * there is no previous one, we return NULL. */
357   if (g_sequence_iter_is_begin (iter))
358     return NULL;
359
360   return g_sequence_iter_prev (iter);
361 }
362
363
364 /**
365  * gst_timed_value_control_source_set:
366  * @self: the #GstTimedValueControlSource object
367  * @timestamp: the time the control-change is scheduled for
368  * @value: the control-value
369  *
370  * Set the value of given controller-handled property at a certain time.
371  *
372  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
373  */
374 gboolean
375 gst_timed_value_control_source_set (GstTimedValueControlSource * self,
376     GstClockTime timestamp, const GValue * value)
377 {
378   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
379   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
380   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
381   g_return_val_if_fail (G_VALUE_TYPE (value) == self->type, FALSE);
382
383   g_mutex_lock (self->lock);
384   gst_timed_value_control_source_set_internal (self, timestamp, value);
385   g_mutex_unlock (self->lock);
386
387   return TRUE;
388 }
389
390 /**
391  * gst_timed_value_control_source_set_from_list:
392  * @self: the #GstTimedValueControlSource object
393  * @timedvalues: (transfer none) (element-type GstController.TimedValue): a list
394  * with #GstTimedValue items
395  *
396  * Sets multiple timed values at once.
397  *
398  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
399  */
400 gboolean
401 gst_timed_value_control_source_set_from_list (GstTimedValueControlSource *
402     self, const GSList * timedvalues)
403 {
404   const GSList *node;
405   GstTimedValue *tv;
406   gboolean res = FALSE;
407
408   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
409
410   for (node = timedvalues; node; node = g_slist_next (node)) {
411     tv = node->data;
412     if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
413       GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
414           GST_FUNCTION);
415     } else if (!G_IS_VALUE (&tv->value)) {
416       GST_WARNING ("GstTimedValued with invalid value passed to %s",
417           GST_FUNCTION);
418     } else if (G_VALUE_TYPE (&tv->value) != self->type) {
419       GST_WARNING ("incompatible value type for property");
420     } else {
421       g_mutex_lock (self->lock);
422       gst_timed_value_control_source_set_internal (self, tv->timestamp,
423           &tv->value);
424       g_mutex_unlock (self->lock);
425       res = TRUE;
426     }
427   }
428   return res;
429 }
430
431 /**
432  * gst_timed_value_control_source_unset:
433  * @self: the #GstTimedValueControlSource object
434  * @timestamp: the time the control-change should be removed from
435  *
436  * Used to remove the value of given controller-handled property at a certain
437  * time.
438  *
439  * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
440  */
441 gboolean
442 gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
443     GstClockTime timestamp)
444 {
445   GSequenceIter *iter;
446   gboolean res = FALSE;
447
448   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
449   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
450
451   g_mutex_lock (self->lock);
452   /* check if a control point for the timestamp exists */
453   if (G_LIKELY (self->values) && (iter =
454           g_sequence_search (self->values, &timestamp,
455               (GCompareDataFunc) gst_control_point_find, NULL))) {
456     GstControlPoint *cp;
457
458     /* Iter contains the iter right after timestamp, i.e.
459      * we need to get the previous one and check the timestamp
460      */
461     iter = g_sequence_iter_prev (iter);
462     cp = g_sequence_get (iter);
463     if (cp->timestamp == timestamp) {
464       g_sequence_remove (iter);
465       self->nvalues--;
466       self->valid_cache = FALSE;
467       res = TRUE;
468     }
469   }
470   g_mutex_unlock (self->lock);
471
472   return res;
473 }
474
475 /**
476  * gst_timed_value_control_source_unset_all:
477  * @self: the #GstTimedValueControlSource object
478  *
479  * Used to remove all time-stamped values of given controller-handled property
480  *
481  */
482 void
483 gst_timed_value_control_source_unset_all (GstTimedValueControlSource * self)
484 {
485   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
486
487   g_mutex_lock (self->lock);
488   /* free GstControlPoint structures */
489   if (self->values) {
490     g_sequence_free (self->values);
491     self->values = NULL;
492   }
493   self->nvalues = 0;
494   self->valid_cache = FALSE;
495
496   g_mutex_unlock (self->lock);
497 }
498
499 static void
500 _append_control_point (GstControlPoint * cp, GQueue * res)
501 {
502   g_queue_push_tail (res, cp);
503 }
504
505 /**
506  * gst_timed_value_control_source_get_all:
507  * @self: the #GstTimedValueControlSource to get the list from
508  *
509  * Returns a read-only copy of the list of #GstTimedValue for the given property.
510  * Free the list after done with it.
511  *
512  * Returns: (transfer container) (element-type GstController.TimedValue): a copy
513  * of the list, or %NULL if the property isn't handled by the controller
514  */
515 GList *
516 gst_timed_value_control_source_get_all (GstTimedValueControlSource * self)
517 {
518   GQueue res = G_QUEUE_INIT;
519
520   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), NULL);
521
522   g_mutex_lock (self->lock);
523   if (G_LIKELY (self->values))
524     g_sequence_foreach (self->values, (GFunc) _append_control_point, &res);
525   g_mutex_unlock (self->lock);
526
527   return res.head;
528 }
529
530 /**
531  * gst_timed_value_control_source_get_count:
532  * @self: the #GstTimedValueControlSource to get the number of values from
533  *
534  * Get the number of control points that are set.
535  *
536  * Returns: the number of control points that are set.
537  */
538 gint
539 gst_timed_value_control_source_get_count (GstTimedValueControlSource * self)
540 {
541   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), 0);
542   return self->nvalues;
543 }
544
545 /**
546  * gst_timed_value_control_source_get_base_value_type:
547  * @self: the #GstTimedValueControlSource
548  *
549  * Get the base #GType of the property value.
550  *
551  * Returns: the #GType, %G_TYPE_INVALID if not yet known.
552  */
553 GType
554 gst_timed_value_control_source_get_base_value_type (GstTimedValueControlSource *
555     self)
556 {
557   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self),
558       G_TYPE_INVALID);
559   return self->base;
560 }
561
562 /**
563  * gst_timed_value_control_invalidate_cache:
564  * @self: the #GstTimedValueControlSource
565  *
566  * Reset the controlled value cache.
567  */
568 void
569 gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self)
570 {
571   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
572   self->valid_cache = FALSE;
573 }
574
575 static void
576 gst_timed_value_control_source_init (GstTimedValueControlSource * self)
577 {
578   self->lock = g_mutex_new ();
579 }
580
581 static void
582 gst_timed_value_control_source_finalize (GObject * obj)
583 {
584   GstTimedValueControlSource *self = GST_TIMED_VALUE_CONTROL_SOURCE (obj);
585
586   g_mutex_lock (self->lock);
587   gst_timed_value_control_source_reset (self);
588   g_mutex_unlock (self->lock);
589   g_mutex_free (self->lock);
590
591   G_OBJECT_CLASS (gst_timed_value_control_source_parent_class)->finalize (obj);
592 }
593
594 static void
595 gst_timed_value_control_source_class_init (GstTimedValueControlSourceClass
596     * klass)
597 {
598   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
599   GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
600
601   gobject_class->finalize = gst_timed_value_control_source_finalize;
602   csource_class->bind = gst_timed_value_control_source_bind;
603 }