Merge remote-tracking branch 'upstream/master' into tizen
[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., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 /**
26  * SECTION:gsttimedvaluecontrolsource
27  * @title: GstTimedValueControlSource
28  * @short_description: timed value control source base class
29  *
30  * Base class for #GstControlSource that use time-stamped values.
31  *
32  * When overriding bind, chain up first to give this bind implementation a
33  * chance to setup things.
34  *
35  * All functions are MT-safe.
36  *
37  */
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <glib-object.h>
43 #include <gst/gst.h>
44
45 #include "gstinterpolationcontrolsource.h"
46 #include "gst/glib-compat-private.h"
47
48 #define GST_CAT_DEFAULT controller_debug
49 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
50
51 #define _do_init \
52   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "timed value control source", 0, \
53     "timed value control source base class")
54
55 #define gst_timed_value_control_source_parent_class parent_class
56 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
57     gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
58
59
60 enum
61 {
62   VALUE_CHANGED_SIGNAL,
63   VALUE_ADDED_SIGNAL,
64   VALUE_REMOVED_SIGNAL,
65   LAST_SIGNAL
66 };
67
68 static guint gst_timed_value_control_source_signals[LAST_SIGNAL] = { 0 };
69
70 /**
71  * gst_control_point_free:
72  * @cp: the object to free
73  *
74  * Frees all data allocated by a #GstControlPoint instance.
75  */
76 void
77 gst_control_point_free (GstControlPoint * cp)
78 {
79   g_return_if_fail (cp);
80
81   g_slice_free (GstControlPoint, cp);
82 }
83
84 /**
85  * gst_control_point_copy:
86  * @cp: The control point to copy
87  *
88  * Copies a #GstControlPoint
89  *
90  * Returns: A copy of @cp
91  */
92 GstControlPoint *
93 gst_control_point_copy (GstControlPoint * cp)
94 {
95   return g_slice_dup (GstControlPoint, cp);
96 }
97
98 GType
99 gst_control_point_get_type (void)
100 {
101   static gsize type_id = 0;
102
103   if (g_once_init_enter (&type_id)) {
104     GType tmp =
105         g_boxed_type_register_static (g_intern_static_string
106         ("GstControlPoint"),
107         (GBoxedCopyFunc) gst_control_point_copy,
108         (GBoxedFreeFunc) gst_control_point_free);
109     g_once_init_leave (&type_id, tmp);
110   }
111
112   return type_id;
113 }
114
115 static void
116 gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
117 {
118   GstControlSource *csource = (GstControlSource *) self;
119
120   csource->get_value = NULL;
121   csource->get_value_array = NULL;
122
123   if (self->values) {
124     g_sequence_free (self->values);
125     self->values = NULL;
126   }
127
128   self->nvalues = 0;
129   self->valid_cache = FALSE;
130 }
131
132 /*
133  * gst_control_point_compare:
134  * @p1: a pointer to a #GstControlPoint
135  * @p2: a pointer to a #GstControlPoint
136  *
137  * Compare function for g_list operations that operates on two #GstControlPoint
138  * parameters.
139  */
140 static gint
141 gst_control_point_compare (gconstpointer p1, gconstpointer p2)
142 {
143   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
144   GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
145
146   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
147 }
148
149 /*
150  * gst_control_point_find:
151  * @p1: a pointer to a #GstControlPoint
152  * @p2: a pointer to a #GstClockTime
153  * @user_data: supplied user data
154  *
155  * Compare function for g_sequence operations that operates on a #GstControlPoint and
156  * a #GstClockTime.
157  */
158 static gint
159 gst_control_point_find (gconstpointer p1, gconstpointer p2, gpointer user_data)
160 {
161   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
162   GstClockTime ct2 = *(GstClockTime *) p2;
163
164   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
165 }
166
167 static GstControlPoint *
168 _make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
169     const gdouble value)
170 {
171   GstControlPoint *cp;
172
173   /* create a new GstControlPoint */
174   cp = g_slice_new0 (GstControlPoint);
175   cp->timestamp = timestamp;
176   cp->value = value;
177
178   return cp;
179 }
180
181 static void
182 gst_timed_value_control_source_set_internal (GstTimedValueControlSource *
183     self, GstClockTime timestamp, const gdouble value)
184 {
185   GstControlPoint *cp;
186
187   g_mutex_lock (&self->lock);
188
189   /* check if a control point for the timestamp already exists */
190   if (G_LIKELY (self->values)) {
191     GSequenceIter *iter = g_sequence_lookup (self->values, &timestamp,
192         (GCompareDataFunc) gst_control_point_find, NULL);
193
194     if (iter) {
195       GstControlPoint *cp = g_sequence_get (iter);
196
197       /* update control point */
198       cp->value = value;
199       g_mutex_unlock (&self->lock);
200
201       g_signal_emit (self,
202           gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL], 0, cp);
203       goto done;
204     }
205   } else {
206     self->values = g_sequence_new ((GDestroyNotify) gst_control_point_free);
207     GST_INFO ("create new timed value sequence");
208   }
209
210   /* sort new cp into the prop->values list */
211   cp = _make_new_cp (self, timestamp, value);
212   g_sequence_insert_sorted (self->values, cp,
213       (GCompareDataFunc) gst_control_point_compare, NULL);
214   self->nvalues++;
215   g_mutex_unlock (&self->lock);
216
217   g_signal_emit (self,
218       gst_timed_value_control_source_signals[VALUE_ADDED_SIGNAL], 0, cp);
219
220 done:
221   self->valid_cache = FALSE;
222 }
223
224 /**
225  * gst_timed_value_control_source_find_control_point_iter:
226  * @self: the control source to search in
227  * @timestamp: the search key
228  *
229  * Find last value before given timestamp in control point list.
230  * If all values in the control point list come after the given
231  * timestamp or no values exist, %NULL is returned.
232  *
233  * For use in control source implementations.
234  *
235  * Returns: (transfer none): the found #GSequenceIter or %NULL
236  */
237 GSequenceIter *gst_timed_value_control_source_find_control_point_iter
238     (GstTimedValueControlSource * self, GstClockTime timestamp)
239 {
240   GSequenceIter *iter;
241
242   if (!self->values)
243     return NULL;
244
245   iter =
246       g_sequence_search (self->values, &timestamp,
247       (GCompareDataFunc) gst_control_point_find, NULL);
248
249   /* g_sequence_search() returns the iter where timestamp
250    * would be inserted, i.e. the iter > timestamp, so
251    * we need to get the previous one. And of course, if
252    * there is no previous one, we return NULL. */
253   if (g_sequence_iter_is_begin (iter))
254     return NULL;
255
256   return g_sequence_iter_prev (iter);
257 }
258
259
260 /**
261  * gst_timed_value_control_source_set:
262  * @self: the #GstTimedValueControlSource object
263  * @timestamp: the time the control-change is scheduled for
264  * @value: the control-value
265  *
266  * Set the value of given controller-handled property at a certain time.
267  *
268  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
269  */
270 gboolean
271 gst_timed_value_control_source_set (GstTimedValueControlSource * self,
272     GstClockTime timestamp, const gdouble value)
273 {
274   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
275   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
276
277   gst_timed_value_control_source_set_internal (self, timestamp, value);
278
279   return TRUE;
280 }
281
282 /**
283  * gst_timed_value_control_source_set_from_list:
284  * @self: the #GstTimedValueControlSource object
285  * @timedvalues: (transfer none) (element-type GstTimedValue): a list
286  * with #GstTimedValue items
287  *
288  * Sets multiple timed values at once.
289  *
290  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
291  */
292 gboolean
293 gst_timed_value_control_source_set_from_list (GstTimedValueControlSource *
294     self, const GSList * timedvalues)
295 {
296   const GSList *node;
297   GstTimedValue *tv;
298   gboolean res = FALSE;
299
300   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
301
302   for (node = timedvalues; node; node = g_slist_next (node)) {
303     tv = node->data;
304     if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
305       GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
306           GST_FUNCTION);
307     } else {
308       gst_timed_value_control_source_set_internal (self, tv->timestamp,
309           tv->value);
310       res = TRUE;
311     }
312   }
313   return res;
314 }
315
316 /**
317  * gst_timed_value_control_source_unset:
318  * @self: the #GstTimedValueControlSource object
319  * @timestamp: the time the control-change should be removed from
320  *
321  * Used to remove the value of given controller-handled property at a certain
322  * time.
323  *
324  * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
325  */
326 gboolean
327 gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
328     GstClockTime timestamp)
329 {
330   GSequenceIter *iter;
331   gboolean res = FALSE;
332   GstControlPoint *cp = NULL;
333
334   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
335   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
336
337   g_mutex_lock (&self->lock);
338   /* check if a control point for the timestamp exists */
339   if (G_LIKELY (self->values) && (iter =
340           g_sequence_lookup (self->values, &timestamp,
341               (GCompareDataFunc) gst_control_point_find, NULL))) {
342
343     /* Iter contains the iter right after timestamp, i.e.
344      * we need to get the previous one and check the timestamp
345      */
346     cp = g_slice_dup (GstControlPoint, g_sequence_get (iter));
347     g_sequence_remove (iter);
348     self->nvalues--;
349     self->valid_cache = FALSE;
350     res = TRUE;
351   }
352   g_mutex_unlock (&self->lock);
353
354   if (cp) {
355     g_signal_emit (self,
356         gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL], 0, cp);
357     g_slice_free (GstControlPoint, cp);
358   }
359
360   return res;
361 }
362
363 /**
364  * gst_timed_value_control_source_unset_all:
365  * @self: the #GstTimedValueControlSource object
366  *
367  * Used to remove all time-stamped values of given controller-handled property
368  *
369  */
370 void
371 gst_timed_value_control_source_unset_all (GstTimedValueControlSource * self)
372 {
373   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
374
375   g_mutex_lock (&self->lock);
376   /* free GstControlPoint structures */
377   if (self->values) {
378     g_sequence_free (self->values);
379     self->values = NULL;
380   }
381   self->nvalues = 0;
382   self->valid_cache = FALSE;
383
384   g_mutex_unlock (&self->lock);
385 }
386
387 static void
388 _append_control_point (GstControlPoint * cp, GQueue * res)
389 {
390   g_queue_push_tail (res, cp);
391 }
392
393 /**
394  * gst_timed_value_control_source_get_all:
395  * @self: the #GstTimedValueControlSource to get the list from
396  *
397  * Returns a read-only copy of the list of #GstTimedValue for the given property.
398  * Free the list after done with it.
399  *
400  * Returns: (transfer container) (element-type GstTimedValue): a copy
401  * of the list, or %NULL if the property isn't handled by the controller
402  */
403 GList *
404 gst_timed_value_control_source_get_all (GstTimedValueControlSource * self)
405 {
406   GQueue res = G_QUEUE_INIT;
407
408   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), NULL);
409
410   g_mutex_lock (&self->lock);
411   if (G_LIKELY (self->values))
412     g_sequence_foreach (self->values, (GFunc) _append_control_point, &res);
413   g_mutex_unlock (&self->lock);
414
415   return res.head;
416 }
417
418 /**
419  * gst_timed_value_control_source_get_count:
420  * @self: the #GstTimedValueControlSource to get the number of values from
421  *
422  * Get the number of control points that are set.
423  *
424  * Returns: the number of control points that are set.
425  */
426 gint
427 gst_timed_value_control_source_get_count (GstTimedValueControlSource * self)
428 {
429   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), 0);
430   return self->nvalues;
431 }
432
433 /**
434  * gst_timed_value_control_invalidate_cache:
435  * @self: the #GstTimedValueControlSource
436  *
437  * Reset the controlled value cache.
438  */
439 void
440 gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self)
441 {
442   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
443   self->valid_cache = FALSE;
444 }
445
446 static void
447 gst_timed_value_control_source_init (GstTimedValueControlSource * self)
448 {
449   g_mutex_init (&self->lock);
450 }
451
452 static void
453 gst_timed_value_control_source_finalize (GObject * obj)
454 {
455   GstTimedValueControlSource *self = GST_TIMED_VALUE_CONTROL_SOURCE (obj);
456
457   g_mutex_lock (&self->lock);
458   gst_timed_value_control_source_reset (self);
459   g_mutex_unlock (&self->lock);
460   g_mutex_clear (&self->lock);
461
462   G_OBJECT_CLASS (parent_class)->finalize (obj);
463 }
464
465 static void
466 gst_timed_value_control_source_class_init (GstTimedValueControlSourceClass
467     * klass)
468 {
469   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
470   //GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
471
472   /**
473    * GstTimedValueControlSource::value-changed
474    * @self: The #GstTimedValueControlSource on which a #GstTimedValue has changed
475    * @timed_value: The #GstTimedValue where the value changed
476    *
477    * Emitted right after the new value has been set on @timed_signals
478    *
479    * Since: 1.6
480    */
481   gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL] =
482       g_signal_new ("value-changed", G_TYPE_FROM_CLASS (klass),
483       G_SIGNAL_RUN_FIRST, 0, NULL,
484       NULL, NULL, G_TYPE_NONE, 1, gst_control_point_get_type ());
485
486   /**
487    * GstTimedValueControlSource::value-added
488    * @self: The #GstTimedValueControlSource into which a #GstTimedValue has been
489    *        added
490    * @timed_value: The newly added #GstTimedValue
491    *
492    * Emitted right after the new value has been added to @self
493    *
494    * Since: 1.6
495    */
496   gst_timed_value_control_source_signals[VALUE_ADDED_SIGNAL] =
497       g_signal_new ("value-added", G_TYPE_FROM_CLASS (klass),
498       G_SIGNAL_RUN_FIRST, 0, NULL,
499       NULL, NULL, G_TYPE_NONE, 1, gst_control_point_get_type ());
500
501   /**
502    * GstTimedValueControlSource::value-removed
503    * @self: The #GstTimedValueControlSource from which a #GstTimedValue has been
504    *        removed
505    * @timed_value: The removed #GstTimedValue
506    *
507    * Emitted when @timed_value is removed from @self
508    *
509    * Since: 1.6
510    */
511   gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL] =
512       g_signal_new ("value-removed", G_TYPE_FROM_CLASS (klass),
513       G_SIGNAL_RUN_FIRST, 0, NULL,
514       NULL, NULL, G_TYPE_NONE, 1, gst_control_point_get_type ());
515
516
517   gobject_class->finalize = gst_timed_value_control_source_finalize;
518 }