4c8dca97359a4bfe1a89b8ae3cafff21c4b2f78d
[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  * @short_description: timed value control source base class
28  *
29  * Base class for #GstControlSource 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 "gst/glib-compat-private.h"
43
44 #define GST_CAT_DEFAULT controller_debug
45 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
46
47 #define _do_init \
48   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "timed value control source", 0, \
49     "timed value control source base class")
50
51 #define gst_timed_value_control_source_parent_class parent_class
52 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
53     gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
54
55
56 enum
57 {
58   VALUE_CHANGED_SIGNAL,
59   VALUE_ADDED_SIGNAL,
60   VALUE_REMOVED_SIGNAL,
61   LAST_SIGNAL
62 };
63
64 static guint gst_timed_value_control_source_signals[LAST_SIGNAL] = { 0 };
65
66 /*
67  * gst_control_point_free:
68  * @prop: the object to free
69  *
70  * Private method which frees all data allocated by a #GstControlPoint
71  * instance.
72  */
73 static void
74 gst_control_point_free (GstControlPoint * cp)
75 {
76   g_return_if_fail (cp);
77
78   g_slice_free (GstControlPoint, cp);
79 }
80
81 static gpointer
82 gst_control_point_copy (GstControlPoint * boxed)
83 {
84   return g_slice_dup (GstControlPoint, boxed);
85 }
86
87 GType
88 gst_control_point_get_type (void)
89 {
90   static volatile gsize type_id = 0;
91
92   if (g_once_init_enter (&type_id)) {
93     GType tmp =
94         g_boxed_type_register_static (g_intern_static_string
95         ("GstControlPoint"),
96         (GBoxedCopyFunc) gst_control_point_copy,
97         (GBoxedFreeFunc) gst_control_point_free);
98     g_once_init_leave (&type_id, tmp);
99   }
100
101   return type_id;
102 }
103
104 static void
105 gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
106 {
107   GstControlSource *csource = (GstControlSource *) self;
108
109   csource->get_value = NULL;
110   csource->get_value_array = NULL;
111
112   if (self->values) {
113     g_sequence_free (self->values);
114     self->values = NULL;
115   }
116
117   self->nvalues = 0;
118   self->valid_cache = FALSE;
119 }
120
121 /*
122  * gst_control_point_compare:
123  * @p1: a pointer to a #GstControlPoint
124  * @p2: a pointer to a #GstControlPoint
125  *
126  * Compare function for g_list operations that operates on two #GstControlPoint
127  * parameters.
128  */
129 static gint
130 gst_control_point_compare (gconstpointer p1, gconstpointer p2)
131 {
132   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
133   GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
134
135   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
136 }
137
138 /*
139  * gst_control_point_find:
140  * @p1: a pointer to a #GstControlPoint
141  * @p2: a pointer to a #GstClockTime
142  * @user_data: supplied user data
143  *
144  * Compare function for g_sequence operations that operates on a #GstControlPoint and
145  * a #GstClockTime.
146  */
147 static gint
148 gst_control_point_find (gconstpointer p1, gconstpointer p2, gpointer user_data)
149 {
150   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
151   GstClockTime ct2 = *(GstClockTime *) p2;
152
153   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
154 }
155
156 static GstControlPoint *
157 _make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
158     const gdouble value)
159 {
160   GstControlPoint *cp;
161
162   /* create a new GstControlPoint */
163   cp = g_slice_new0 (GstControlPoint);
164   cp->timestamp = timestamp;
165   cp->value = value;
166
167   return cp;
168 }
169
170 static void
171 gst_timed_value_control_source_set_internal (GstTimedValueControlSource *
172     self, GstClockTime timestamp, const gdouble value)
173 {
174   GSequenceIter *iter;
175   GstControlPoint *cp;
176
177   g_mutex_lock (&self->lock);
178
179   /* check if a control point for the timestamp already exists */
180   /* iter contains the iter right *after* timestamp */
181   if (G_LIKELY (self->values)) {
182     iter =
183         g_sequence_search (self->values, &timestamp,
184         (GCompareDataFunc) gst_control_point_find, NULL);
185     if (iter) {
186       GSequenceIter *prev = g_sequence_iter_prev (iter);
187
188       if (!g_sequence_iter_is_end (prev)) {
189         GstControlPoint *cp = g_sequence_get (prev);
190
191         /* If the timestamp is the same just update the control point value */
192         if (cp->timestamp == timestamp) {
193
194           /* update control point */
195           cp->value = value;
196           g_mutex_unlock (&self->lock);
197
198           g_signal_emit (self,
199               gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL], 0,
200               cp);
201           goto done;
202         }
203       }
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_search (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     iter = g_sequence_iter_prev (iter);
347     cp = g_sequence_get (iter);
348     if (cp->timestamp == timestamp) {
349       cp = g_slice_dup (GstControlPoint, cp);
350       g_sequence_remove (iter);
351       self->nvalues--;
352       self->valid_cache = FALSE;
353       res = TRUE;
354     } else {
355       cp = NULL;
356     }
357
358   }
359   g_mutex_unlock (&self->lock);
360
361   if (cp) {
362     g_signal_emit (self,
363         gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL], 0, cp);
364     g_slice_free (GstControlPoint, cp);
365   }
366
367   return res;
368 }
369
370 /**
371  * gst_timed_value_control_source_unset_all:
372  * @self: the #GstTimedValueControlSource object
373  *
374  * Used to remove all time-stamped values of given controller-handled property
375  *
376  */
377 void
378 gst_timed_value_control_source_unset_all (GstTimedValueControlSource * self)
379 {
380   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
381
382   g_mutex_lock (&self->lock);
383   /* free GstControlPoint structures */
384   if (self->values) {
385     g_sequence_free (self->values);
386     self->values = NULL;
387   }
388   self->nvalues = 0;
389   self->valid_cache = FALSE;
390
391   g_mutex_unlock (&self->lock);
392 }
393
394 static void
395 _append_control_point (GstControlPoint * cp, GQueue * res)
396 {
397   g_queue_push_tail (res, cp);
398 }
399
400 /**
401  * gst_timed_value_control_source_get_all:
402  * @self: the #GstTimedValueControlSource to get the list from
403  *
404  * Returns a read-only copy of the list of #GstTimedValue for the given property.
405  * Free the list after done with it.
406  *
407  * Returns: (transfer container) (element-type GstTimedValue): a copy
408  * of the list, or %NULL if the property isn't handled by the controller
409  */
410 GList *
411 gst_timed_value_control_source_get_all (GstTimedValueControlSource * self)
412 {
413   GQueue res = G_QUEUE_INIT;
414
415   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), NULL);
416
417   g_mutex_lock (&self->lock);
418   if (G_LIKELY (self->values))
419     g_sequence_foreach (self->values, (GFunc) _append_control_point, &res);
420   g_mutex_unlock (&self->lock);
421
422   return res.head;
423 }
424
425 /**
426  * gst_timed_value_control_source_get_count:
427  * @self: the #GstTimedValueControlSource to get the number of values from
428  *
429  * Get the number of control points that are set.
430  *
431  * Returns: the number of control points that are set.
432  */
433 gint
434 gst_timed_value_control_source_get_count (GstTimedValueControlSource * self)
435 {
436   g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), 0);
437   return self->nvalues;
438 }
439
440 /**
441  * gst_timed_value_control_invalidate_cache:
442  * @self: the #GstTimedValueControlSource
443  *
444  * Reset the controlled value cache.
445  */
446 void
447 gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self)
448 {
449   g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
450   self->valid_cache = FALSE;
451 }
452
453 static void
454 gst_timed_value_control_source_init (GstTimedValueControlSource * self)
455 {
456   g_mutex_init (&self->lock);
457 }
458
459 static void
460 gst_timed_value_control_source_finalize (GObject * obj)
461 {
462   GstTimedValueControlSource *self = GST_TIMED_VALUE_CONTROL_SOURCE (obj);
463
464   g_mutex_lock (&self->lock);
465   gst_timed_value_control_source_reset (self);
466   g_mutex_unlock (&self->lock);
467   g_mutex_clear (&self->lock);
468
469   G_OBJECT_CLASS (parent_class)->finalize (obj);
470 }
471
472 static void
473 gst_timed_value_control_source_class_init (GstTimedValueControlSourceClass
474     * klass)
475 {
476   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
477   //GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
478
479   /**
480    * GstTimedValueControlSource::value-changed
481    * @self: The #GstTimedValueControlSource on which a #GstTimedValue has changed
482    * @timed_value: The #GstTimedValue where the value changed
483    *
484    * Emited right after the new value has been set on @timed_signals
485    *
486    * Since: 1.6
487    */
488   gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL] =
489       g_signal_new ("value-changed", G_TYPE_FROM_CLASS (klass),
490       G_SIGNAL_RUN_FIRST, 0, NULL,
491       NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
492       gst_control_point_get_type ());
493
494   /**
495    * GstTimedValueControlSource::value-added
496    * @self: The #GstTimedValueControlSource into which a #GstTimedValue has been
497    *        added
498    * @timed_value: The newly added #GstTimedValue
499    *
500    * Emited right after the new value has been added to @self
501    *
502    * Since: 1.6
503    */
504   gst_timed_value_control_source_signals[VALUE_ADDED_SIGNAL] =
505       g_signal_new ("value-added", G_TYPE_FROM_CLASS (klass),
506       G_SIGNAL_RUN_FIRST, 0, NULL,
507       NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
508       gst_control_point_get_type ());
509
510   /**
511    * GstTimedValueControlSource::value-removed
512    * @self: The #GstTimedValueControlSource from which a #GstTimedValue has been
513    *        removed
514    * @timed_value: The removed #GstTimedValue
515    *
516    * Emited when @timed_value is removed from @self
517    *
518    * Since: 1.6
519    */
520   gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL] =
521       g_signal_new ("value-removed", G_TYPE_FROM_CLASS (klass),
522       G_SIGNAL_RUN_FIRST, 0, NULL,
523       NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
524       gst_control_point_get_type ());
525
526
527   gobject_class->finalize = gst_timed_value_control_source_finalize;
528 }