3 * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 * 2011 Stefan Sauer <ensonic@users.sf.net>
6 * gsttimedvaluecontrolsource.c: Base class for timeed value based control
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.
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.
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.
26 * SECTION:gsttimedvaluecontrolsource
27 * @short_description: timed value control source base class
29 * Base class for #GstContrlSources that use time-stamped values.
31 * When overriding bind, chain up first to give this bind implementation a
32 * chance to setup things.
34 * All functions are MT-safe.
38 #include <glib-object.h>
41 #include "gstinterpolationcontrolsource.h"
42 #include "gstinterpolationcontrolsourceprivate.h"
43 #include "gst/glib-compat-private.h"
45 #define GST_CAT_DEFAULT controller_debug
46 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
49 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "timed value control source", 0, \
50 "timed value control source base class")
52 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
53 gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
56 * gst_control_point_free:
57 * @prop: the object to free
59 * Private method which frees all data allocated by a #GstControlPoint
63 gst_control_point_free (GstControlPoint * cp)
65 g_return_if_fail (cp);
67 g_value_unset (&cp->value);
68 g_slice_free (GstControlPoint, cp);
72 gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
74 GstControlSource *csource = (GstControlSource *) self;
76 csource->get_value = NULL;
77 csource->get_value_array = NULL;
79 self->type = self->base = G_TYPE_INVALID;
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);
89 g_sequence_free (self->values);
94 self->valid_cache = FALSE;
98 gst_timed_value_control_source_bind (GstControlSource * source,
102 GstTimedValueControlSource *self = (GstTimedValueControlSource *) source;
105 /* get the fundamental base type */
106 self->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
107 while ((type = g_type_parent (type)))
116 GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
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);
127 GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
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);
138 GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
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);
149 GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
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);
160 GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
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);
171 GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
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);
182 GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
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);
193 GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
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);
203 case G_TYPE_BOOLEAN:{
204 GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
206 g_value_init (&self->default_value, type);
207 g_value_set_boolean (&self->default_value, tpspec->default_value);
211 GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
213 g_value_init (&self->default_value, type);
214 g_value_set_enum (&self->default_value, tpspec->default_value);
218 GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
220 g_value_init (&self->default_value, type);
221 g_value_set_string (&self->default_value, tpspec->default_value);
225 GST_WARNING ("incomplete implementation for paramspec type '%s'",
226 G_PARAM_SPEC_TYPE_NAME (pspec));
232 self->valid_cache = FALSE;
235 gst_timed_value_control_source_reset (self);
242 * gst_control_point_compare:
243 * @p1: a pointer to a #GstControlPoint
244 * @p2: a pointer to a #GstControlPoint
246 * Compare function for g_list operations that operates on two #GstControlPoint
250 gst_control_point_compare (gconstpointer p1, gconstpointer p2)
252 GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
253 GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
255 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
259 * gst_control_point_find:
260 * @p1: a pointer to a #GstControlPoint
261 * @p2: a pointer to a #GstClockTime
263 * Compare function for g_list operations that operates on a #GstControlPoint and
267 gst_control_point_find (gconstpointer p1, gconstpointer p2)
269 GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
270 GstClockTime ct2 = *(GstClockTime *) p2;
272 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
275 static GstControlPoint *
276 _make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
277 const GValue * value)
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);
291 gst_timed_value_control_source_set_internal (GstTimedValueControlSource *
292 self, GstClockTime timestamp, const GValue * value)
296 /* check if a control point for the timestamp already exists */
298 /* iter contains the iter right *after* timestamp */
299 if (G_LIKELY (self->values)) {
301 g_sequence_search (self->values, ×tamp,
302 (GCompareDataFunc) gst_control_point_find, NULL);
304 GSequenceIter *prev = g_sequence_iter_prev (iter);
305 GstControlPoint *cp = g_sequence_get (prev);
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);
316 self->values = g_sequence_new ((GDestroyNotify) gst_control_point_free);
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);
325 self->valid_cache = FALSE;
329 * gst_timed_value_control_source_find_control_point_iter:
330 * @self: the control source to search in
331 * @timestamp: the search key
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.
337 * For use in control source implementations.
339 * Returns: the found #GSequenceIter or %NULL
341 GSequenceIter *gst_timed_value_control_source_find_control_point_iter
342 (GstTimedValueControlSource * self, GstClockTime timestamp)
350 g_sequence_search (self->values, ×tamp,
351 (GCompareDataFunc) gst_control_point_find, NULL);
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))
360 return g_sequence_iter_prev (iter);
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
370 * Set the value of given controller-handled property at a certain time.
372 * Returns: FALSE if the values couldn't be set, TRUE otherwise.
375 gst_timed_value_control_source_set (GstTimedValueControlSource * self,
376 GstClockTime timestamp, const GValue * value)
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);
383 g_mutex_lock (self->lock);
384 gst_timed_value_control_source_set_internal (self, timestamp, value);
385 g_mutex_unlock (self->lock);
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
396 * Sets multiple timed values at once.
398 * Returns: FALSE if the values couldn't be set, TRUE otherwise.
401 gst_timed_value_control_source_set_from_list (GstTimedValueControlSource *
402 self, const GSList * timedvalues)
406 gboolean res = FALSE;
408 g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
410 for (node = timedvalues; node; node = g_slist_next (node)) {
412 if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
413 GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
415 } else if (!G_IS_VALUE (&tv->value)) {
416 GST_WARNING ("GstTimedValued with invalid value passed to %s",
418 } else if (G_VALUE_TYPE (&tv->value) != self->type) {
419 GST_WARNING ("incompatible value type for property");
421 g_mutex_lock (self->lock);
422 gst_timed_value_control_source_set_internal (self, tv->timestamp,
424 g_mutex_unlock (self->lock);
432 * gst_timed_value_control_source_unset:
433 * @self: the #GstTimedValueControlSource object
434 * @timestamp: the time the control-change should be removed from
436 * Used to remove the value of given controller-handled property at a certain
439 * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
442 gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
443 GstClockTime timestamp)
446 gboolean res = FALSE;
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);
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, ×tamp,
455 (GCompareDataFunc) gst_control_point_find, NULL))) {
458 /* Iter contains the iter right after timestamp, i.e.
459 * we need to get the previous one and check the timestamp
461 iter = g_sequence_iter_prev (iter);
462 cp = g_sequence_get (iter);
463 if (cp->timestamp == timestamp) {
464 g_sequence_remove (iter);
466 self->valid_cache = FALSE;
470 g_mutex_unlock (self->lock);
476 * gst_timed_value_control_source_unset_all:
477 * @self: the #GstTimedValueControlSource object
479 * Used to remove all time-stamped values of given controller-handled property
483 gst_timed_value_control_source_unset_all (GstTimedValueControlSource * self)
485 g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
487 g_mutex_lock (self->lock);
488 /* free GstControlPoint structures */
490 g_sequence_free (self->values);
494 self->valid_cache = FALSE;
496 g_mutex_unlock (self->lock);
500 _append_control_point (GstControlPoint * cp, GQueue * res)
502 g_queue_push_tail (res, cp);
506 * gst_timed_value_control_source_get_all:
507 * @self: the #GstTimedValueControlSource to get the list from
509 * Returns a read-only copy of the list of #GstTimedValue for the given property.
510 * Free the list after done with it.
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
516 gst_timed_value_control_source_get_all (GstTimedValueControlSource * self)
518 GQueue res = G_QUEUE_INIT;
520 g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), NULL);
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);
531 * gst_timed_value_control_source_get_count:
532 * @self: the #GstTimedValueControlSource to get the number of values from
534 * Get the number of control points that are set.
536 * Returns: the number of control points that are set.
539 gst_timed_value_control_source_get_count (GstTimedValueControlSource * self)
541 g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), 0);
542 return self->nvalues;
546 * gst_timed_value_control_source_get_base_value_type:
547 * @self: the #GstTimedValueControlSource
549 * Get the base #GType of the property value.
551 * Returns: the #GType, %G_TYPE_INVALID if not yet known.
554 gst_timed_value_control_source_get_base_value_type (GstTimedValueControlSource *
557 g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self),
563 * gst_timed_value_control_invalidate_cache:
564 * @self: the #GstTimedValueControlSource
566 * Reset the controlled value cache.
569 gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self)
571 g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
572 self->valid_cache = FALSE;
576 gst_timed_value_control_source_init (GstTimedValueControlSource * self)
578 self->lock = g_mutex_new ();
582 gst_timed_value_control_source_finalize (GObject * obj)
584 GstTimedValueControlSource *self = GST_TIMED_VALUE_CONTROL_SOURCE (obj);
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);
591 G_OBJECT_CLASS (gst_timed_value_control_source_parent_class)->finalize (obj);
595 gst_timed_value_control_source_class_init (GstTimedValueControlSourceClass
598 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
599 GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
601 gobject_class->finalize = gst_timed_value_control_source_finalize;
602 csource_class->bind = gst_timed_value_control_source_bind;