9b2a9cd9703cf0b00f43153a23038ea00e85184b
[platform/upstream/gstreamer.git] / libs / gst / controller / gstinterpolationcontrolsource.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
4  *
5  * gstinterpolationcontrolsource.c: Control source that provides several
6  *                                  interpolation methods
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:gstinterpolationcontrolsource
26  * @short_description: interpolation control source
27  *
28  * #GstInterpolationControlSource is a #GstControlSource, that interpolates values between user-given
29  * control points. It supports several interpolation modes and property types.
30  *
31  * To use #GstInterpolationControlSource get a new instance by calling
32  * gst_interpolation_control_source_new(), bind it to a #GParamSpec, select a interpolation mode with
33  * gst_interpolation_control_source_set_interpolation_mode() and set some control points by calling
34  * gst_interpolation_control_source_set().
35  *
36  * All functions are MT-safe.
37  *
38  */
39
40 #include <glib-object.h>
41 #include <gst/gst.h>
42
43 #include "gstcontrolsource.h"
44 #include "gstinterpolationcontrolsource.h"
45 #include "gstinterpolationcontrolsourceprivate.h"
46
47 static void gst_interpolation_control_source_init (GstInterpolationControlSource
48     * self);
49 static void
50 gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
51     * klass);
52
53 G_DEFINE_TYPE (GstInterpolationControlSource, gst_interpolation_control_source,
54     GST_TYPE_CONTROL_SOURCE);
55
56 static GObjectClass *parent_class = NULL;
57
58 /*
59  * gst_control_point_free:
60  * @prop: the object to free
61  *
62  * Private method which frees all data allocated by a #GstControlPoint
63  * instance.
64  */
65 static void
66 gst_control_point_free (GstControlPoint * cp)
67 {
68   g_return_if_fail (cp);
69
70   g_value_unset (&cp->value);
71   g_slice_free (GstControlPoint, cp);
72 }
73
74 static void
75 gst_interpolation_control_source_reset (GstInterpolationControlSource * self)
76 {
77   GstControlSource *csource = GST_CONTROL_SOURCE (self);
78
79   csource->get_value = NULL;
80   csource->get_value_array = NULL;
81
82   self->priv->type = self->priv->base = G_TYPE_INVALID;
83
84   if (G_IS_VALUE (&self->priv->default_value))
85     g_value_unset (&self->priv->default_value);
86   if (G_IS_VALUE (&self->priv->minimum_value))
87     g_value_unset (&self->priv->minimum_value);
88   if (G_IS_VALUE (&self->priv->maximum_value))
89     g_value_unset (&self->priv->maximum_value);
90
91   if (self->priv->values) {
92     g_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL);
93     g_list_free (self->priv->values);
94     self->priv->values = NULL;
95   }
96
97   self->priv->nvalues = 0;
98   self->priv->last_requested_value = NULL;
99   self->priv->valid_cache = FALSE;
100 }
101
102 /**
103  * gst_interpolation_control_source_new:
104  *
105  * This returns a new, unbound #GstInterpolationControlSource.
106  *
107  * Returns: a new, unbound #GstInterpolationControlSource.
108  */
109 GstInterpolationControlSource *
110 gst_interpolation_control_source_new (void)
111 {
112   return g_object_new (GST_TYPE_INTERPOLATION_CONTROL_SOURCE, NULL);
113 }
114
115 /**
116  * gst_interpolation_control_source_set_interpolation_mode:
117  * @self: the #GstInterpolationControlSource object
118  * @mode: interpolation mode
119  *
120  * Sets the given interpolation mode.
121  *
122  * <note><para>User interpolation is not yet available and quadratic interpolation
123  * is deprecated and maps to cubic interpolation.</para></note>
124  *
125  * Returns: %TRUE if the interpolation mode could be set, %FALSE otherwise
126  */
127 gboolean
128     gst_interpolation_control_source_set_interpolation_mode
129     (GstInterpolationControlSource * self, GstInterpolateMode mode) {
130   gboolean ret = TRUE;
131   GstControlSource *csource = GST_CONTROL_SOURCE (self);
132
133   if (mode >= priv_gst_num_interpolation_methods
134       || priv_gst_interpolation_methods[mode] == NULL) {
135     GST_WARNING ("interpolation mode %d invalid or not implemented yet", mode);
136     return FALSE;
137   }
138
139   if (mode == GST_INTERPOLATE_QUADRATIC) {
140     GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
141         "interpolation mode");
142   }
143
144   if (mode == GST_INTERPOLATE_USER) {
145     GST_WARNING ("User interpolation mode is not implemented yet");
146     return FALSE;
147   }
148
149   g_mutex_lock (self->lock);
150   switch (self->priv->base) {
151     case G_TYPE_INT:
152       csource->get_value = priv_gst_interpolation_methods[mode]->get_int;
153       csource->get_value_array =
154           priv_gst_interpolation_methods[mode]->get_int_value_array;
155       break;
156     case G_TYPE_UINT:{
157       csource->get_value = priv_gst_interpolation_methods[mode]->get_uint;
158       csource->get_value_array =
159           priv_gst_interpolation_methods[mode]->get_uint_value_array;
160       break;
161     }
162     case G_TYPE_LONG:{
163       csource->get_value = priv_gst_interpolation_methods[mode]->get_long;
164       csource->get_value_array =
165           priv_gst_interpolation_methods[mode]->get_long_value_array;
166       break;
167     }
168     case G_TYPE_ULONG:{
169       csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong;
170       csource->get_value_array =
171           priv_gst_interpolation_methods[mode]->get_ulong_value_array;
172       break;
173     }
174     case G_TYPE_INT64:{
175       csource->get_value = priv_gst_interpolation_methods[mode]->get_int64;
176       csource->get_value_array =
177           priv_gst_interpolation_methods[mode]->get_int64_value_array;
178       break;
179     }
180     case G_TYPE_UINT64:{
181       csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64;
182       csource->get_value_array =
183           priv_gst_interpolation_methods[mode]->get_uint64_value_array;
184       break;
185     }
186     case G_TYPE_FLOAT:{
187       csource->get_value = priv_gst_interpolation_methods[mode]->get_float;
188       csource->get_value_array =
189           priv_gst_interpolation_methods[mode]->get_float_value_array;
190       break;
191     }
192     case G_TYPE_DOUBLE:{
193       csource->get_value = priv_gst_interpolation_methods[mode]->get_double;
194       csource->get_value_array =
195           priv_gst_interpolation_methods[mode]->get_double_value_array;
196       break;
197     }
198     case G_TYPE_BOOLEAN:{
199       csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean;
200       csource->get_value_array =
201           priv_gst_interpolation_methods[mode]->get_boolean_value_array;
202       break;
203     }
204     case G_TYPE_ENUM:{
205       csource->get_value = priv_gst_interpolation_methods[mode]->get_enum;
206       csource->get_value_array =
207           priv_gst_interpolation_methods[mode]->get_enum_value_array;
208       break;
209     }
210     case G_TYPE_STRING:{
211       csource->get_value = priv_gst_interpolation_methods[mode]->get_string;
212       csource->get_value_array =
213           priv_gst_interpolation_methods[mode]->get_string_value_array;
214       break;
215     }
216     default:
217       ret = FALSE;
218       break;
219   }
220
221   /* Incomplete implementation */
222   if (!ret || !csource->get_value || !csource->get_value_array) {
223     gst_interpolation_control_source_reset (self);
224     ret = FALSE;
225   }
226
227   self->priv->valid_cache = FALSE;
228   self->priv->interpolation_mode = mode;
229
230   g_mutex_unlock (self->lock);
231
232   return ret;
233 }
234
235 static gboolean
236 gst_interpolation_control_source_bind (GstControlSource * source,
237     GParamSpec * pspec)
238 {
239   GType type, base;
240   GstInterpolationControlSource *self =
241       GST_INTERPOLATION_CONTROL_SOURCE (source);
242   gboolean ret = TRUE;
243
244   /* get the fundamental base type */
245   self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
246   while ((type = g_type_parent (type)))
247     base = type;
248
249   self->priv->base = base;
250   /* restore type */
251   type = self->priv->type;
252
253   if (!gst_interpolation_control_source_set_interpolation_mode (self,
254           self->priv->interpolation_mode))
255     return FALSE;
256
257   switch (base) {
258     case G_TYPE_INT:{
259       GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
260
261       g_value_init (&self->priv->default_value, type);
262       g_value_set_int (&self->priv->default_value, tpspec->default_value);
263       g_value_init (&self->priv->minimum_value, type);
264       g_value_set_int (&self->priv->minimum_value, tpspec->minimum);
265       g_value_init (&self->priv->maximum_value, type);
266       g_value_set_int (&self->priv->maximum_value, tpspec->maximum);
267       break;
268     }
269     case G_TYPE_UINT:{
270       GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
271
272       g_value_init (&self->priv->default_value, type);
273       g_value_set_uint (&self->priv->default_value, tpspec->default_value);
274       g_value_init (&self->priv->minimum_value, type);
275       g_value_set_uint (&self->priv->minimum_value, tpspec->minimum);
276       g_value_init (&self->priv->maximum_value, type);
277       g_value_set_uint (&self->priv->maximum_value, tpspec->maximum);
278       break;
279     }
280     case G_TYPE_LONG:{
281       GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
282
283       g_value_init (&self->priv->default_value, type);
284       g_value_set_long (&self->priv->default_value, tpspec->default_value);
285       g_value_init (&self->priv->minimum_value, type);
286       g_value_set_long (&self->priv->minimum_value, tpspec->minimum);
287       g_value_init (&self->priv->maximum_value, type);
288       g_value_set_long (&self->priv->maximum_value, tpspec->maximum);
289       break;
290     }
291     case G_TYPE_ULONG:{
292       GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
293
294       g_value_init (&self->priv->default_value, type);
295       g_value_set_ulong (&self->priv->default_value, tpspec->default_value);
296       g_value_init (&self->priv->minimum_value, type);
297       g_value_set_ulong (&self->priv->minimum_value, tpspec->minimum);
298       g_value_init (&self->priv->maximum_value, type);
299       g_value_set_ulong (&self->priv->maximum_value, tpspec->maximum);
300       break;
301     }
302     case G_TYPE_INT64:{
303       GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
304
305       g_value_init (&self->priv->default_value, type);
306       g_value_set_int64 (&self->priv->default_value, tpspec->default_value);
307       g_value_init (&self->priv->minimum_value, type);
308       g_value_set_int64 (&self->priv->minimum_value, tpspec->minimum);
309       g_value_init (&self->priv->maximum_value, type);
310       g_value_set_int64 (&self->priv->maximum_value, tpspec->maximum);
311       break;
312     }
313     case G_TYPE_UINT64:{
314       GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
315
316       g_value_init (&self->priv->default_value, type);
317       g_value_set_uint64 (&self->priv->default_value, tpspec->default_value);
318       g_value_init (&self->priv->minimum_value, type);
319       g_value_set_uint64 (&self->priv->minimum_value, tpspec->minimum);
320       g_value_init (&self->priv->maximum_value, type);
321       g_value_set_uint64 (&self->priv->maximum_value, tpspec->maximum);
322       break;
323     }
324     case G_TYPE_FLOAT:{
325       GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
326
327       g_value_init (&self->priv->default_value, type);
328       g_value_set_float (&self->priv->default_value, tpspec->default_value);
329       g_value_init (&self->priv->minimum_value, type);
330       g_value_set_float (&self->priv->minimum_value, tpspec->minimum);
331       g_value_init (&self->priv->maximum_value, type);
332       g_value_set_float (&self->priv->maximum_value, tpspec->maximum);
333       break;
334     }
335     case G_TYPE_DOUBLE:{
336       GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
337
338       g_value_init (&self->priv->default_value, type);
339       g_value_set_double (&self->priv->default_value, tpspec->default_value);
340       g_value_init (&self->priv->minimum_value, type);
341       g_value_set_double (&self->priv->minimum_value, tpspec->minimum);
342       g_value_init (&self->priv->maximum_value, type);
343       g_value_set_double (&self->priv->maximum_value, tpspec->maximum);
344       break;
345     }
346     case G_TYPE_BOOLEAN:{
347       GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
348
349       g_value_init (&self->priv->default_value, type);
350       g_value_set_boolean (&self->priv->default_value, tpspec->default_value);
351       break;
352     }
353     case G_TYPE_ENUM:{
354       GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
355
356       g_value_init (&self->priv->default_value, type);
357       g_value_set_enum (&self->priv->default_value, tpspec->default_value);
358       break;
359     }
360     case G_TYPE_STRING:{
361       GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
362
363       g_value_init (&self->priv->default_value, type);
364       g_value_set_string (&self->priv->default_value, tpspec->default_value);
365       break;
366     }
367     default:
368       GST_WARNING ("incomplete implementation for paramspec type '%s'",
369           G_PARAM_SPEC_TYPE_NAME (pspec));
370       ret = FALSE;
371       break;
372   }
373
374   if (ret) {
375     self->priv->valid_cache = FALSE;
376     self->priv->nvalues = 0;
377   } else {
378     gst_interpolation_control_source_reset (self);
379   }
380
381   return ret;
382 }
383
384 /*
385  * gst_control_point_compare:
386  * @p1: a pointer to a #GstControlPoint
387  * @p2: a pointer to a #GstControlPoint
388  *
389  * Compare function for g_list operations that operates on two #GstControlPoint
390  * parameters.
391  */
392 static gint
393 gst_control_point_compare (gconstpointer p1, gconstpointer p2)
394 {
395   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
396   GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
397
398   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
399 }
400
401 /*
402  * gst_control_point_find:
403  * @p1: a pointer to a #GstControlPoint
404  * @p2: a pointer to a #GstClockTime
405  *
406  * Compare function for g_list operations that operates on a #GstControlPoint and
407  * a #GstClockTime.
408  */
409 static gint
410 gst_control_point_find (gconstpointer p1, gconstpointer p2)
411 {
412   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
413   GstClockTime ct2 = *(GstClockTime *) p2;
414
415   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
416 }
417
418 /*
419  * _list_find_sorted_custom:
420  *
421  * This works like g_list_find_custom() with the difference that it expects the
422  * list to be sorted in ascending order (0->MAX), stops when it the list-values
423  * are bigger that what is searched for and optionaly delivers the last node
424  * back in the @prev_node argument. This can be used to quickly insert a new
425  * node at the correct position. 
426  */
427 static GList *
428 _list_find_sorted_custom (GList * list, gconstpointer data, GCompareFunc func,
429     GList ** prev_node)
430 {
431   GList *prev = list;
432   gint cmp;
433
434   g_return_val_if_fail (func != NULL, list);
435
436   while (list) {
437     cmp = func (list->data, data);
438     switch (cmp) {
439       case -1:
440         prev = list;
441         list = list->next;
442         break;
443       case 0:
444         return list;
445       case 1:
446         if (prev_node)
447           *prev_node = prev;
448         return NULL;
449     }
450   }
451   if (prev_node)
452     *prev_node = prev;
453   return NULL;
454 }
455
456 static GstControlPoint *
457 _make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp,
458     GValue * value)
459 {
460   GstControlPoint *cp;
461
462   /* create a new GstControlPoint */
463   cp = g_slice_new0 (GstControlPoint);
464   cp->timestamp = timestamp;
465   g_value_init (&cp->value, self->priv->type);
466   g_value_copy (value, &cp->value);
467
468   return cp;
469 }
470
471 static void
472 gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
473     self, GstClockTime timestamp, GValue * value)
474 {
475   GList *node, *prev = self->priv->values;
476
477   /* check if we can shortcut and append */
478   if ((node = g_list_last (self->priv->values))) {
479     GstControlPoint *last_cp = node->data;
480
481     if (timestamp > last_cp->timestamp) {
482       /* pass 'node' instead of list, and also deliberately ignore the result */
483       node = g_list_append (node, _make_new_cp (self, timestamp, value));
484       self->priv->nvalues++;
485       goto done;
486     }
487   }
488
489   /* check if a control point for the timestamp already exists */
490   if ((node = _list_find_sorted_custom (self->priv->values, &timestamp,
491               gst_control_point_find, &prev))) {
492     /* update control point */
493     GstControlPoint *cp = node->data;
494     g_value_reset (&cp->value);
495     g_value_copy (value, &cp->value);
496   } else {
497     /* sort new cp into the prop->values list */
498     if (self->priv->values) {
499       GList *new_list;
500
501       /* pass 'prev' instead of list */
502       new_list = g_list_insert_sorted (prev,
503           _make_new_cp (self, timestamp, value), gst_control_point_compare);
504       if (self->priv->values == prev)
505         self->priv->values = new_list;
506     } else {
507       self->priv->values = g_list_prepend (NULL,
508           _make_new_cp (self, timestamp, value));
509     }
510     self->priv->nvalues++;
511   }
512 done:
513   self->priv->valid_cache = FALSE;
514 }
515
516
517 /**
518  * gst_interpolation_control_source_set:
519  * @self: the #GstInterpolationControlSource object
520  * @timestamp: the time the control-change is scheduled for
521  * @value: the control-value
522  *
523  * Set the value of given controller-handled property at a certain time.
524  *
525  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
526  */
527 gboolean
528 gst_interpolation_control_source_set (GstInterpolationControlSource * self,
529     GstClockTime timestamp, GValue * value)
530 {
531   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
532   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
533   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
534   g_return_val_if_fail (G_VALUE_TYPE (value) == self->priv->type, FALSE);
535
536   g_mutex_lock (self->lock);
537   gst_interpolation_control_source_set_internal (self, timestamp, value);
538   g_mutex_unlock (self->lock);
539
540   return TRUE;
541 }
542
543 /**
544  * gst_interpolation_control_source_set_from_list:
545  * @self: the #GstInterpolationControlSource object
546  * @timedvalues: a list with #GstTimedValue items
547  *
548  * Sets multiple timed values at once.
549  *
550  * Returns: FALSE if the values couldn't be set, TRUE otherwise.
551  */
552 gboolean
553 gst_interpolation_control_source_set_from_list (GstInterpolationControlSource *
554     self, GSList * timedvalues)
555 {
556   GSList *node;
557   GstTimedValue *tv;
558   gboolean res = FALSE;
559
560   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
561
562   for (node = timedvalues; node; node = g_slist_next (node)) {
563     tv = node->data;
564     if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
565       GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
566           GST_FUNCTION);
567     } else if (!G_IS_VALUE (&tv->value)) {
568       GST_WARNING ("GstTimedValued with invalid value passed to %s",
569           GST_FUNCTION);
570     } else if (G_VALUE_TYPE (&tv->value) != self->priv->type) {
571       GST_WARNING ("incompatible value type for property");
572     } else {
573       g_mutex_lock (self->lock);
574       gst_interpolation_control_source_set_internal (self, tv->timestamp,
575           &tv->value);
576       g_mutex_unlock (self->lock);
577       res = TRUE;
578     }
579   }
580   return res;
581 }
582
583 /**
584  * gst_interpolation_control_source_unset:
585  * @self: the #GstInterpolationControlSource object
586  * @timestamp: the time the control-change should be removed from
587  *
588  * Used to remove the value of given controller-handled property at a certain
589  * time.
590  *
591  * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
592  */
593 gboolean
594 gst_interpolation_control_source_unset (GstInterpolationControlSource * self,
595     GstClockTime timestamp)
596 {
597   GList *node;
598   gboolean res = FALSE;
599
600   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
601   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
602
603   g_mutex_lock (self->lock);
604   /* check if a control point for the timestamp exists */
605   if ((node = g_list_find_custom (self->priv->values, &timestamp,
606               gst_control_point_find))) {
607     if (node == self->priv->last_requested_value)
608       self->priv->last_requested_value = NULL;
609     gst_control_point_free (node->data);        /* free GstControlPoint */
610     self->priv->values = g_list_delete_link (self->priv->values, node);
611     self->priv->nvalues--;
612     self->priv->valid_cache = FALSE;
613     res = TRUE;
614   }
615   g_mutex_unlock (self->lock);
616
617   return res;
618 }
619
620 /**
621  * gst_interpolation_control_source_unset_all:
622  * @self: the #GstInterpolationControlSource object
623  *
624  * Used to remove all time-stamped values of given controller-handled property
625  *
626  */
627 void
628 gst_interpolation_control_source_unset_all (GstInterpolationControlSource *
629     self)
630 {
631   g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self));
632
633   g_mutex_lock (self->lock);
634   /* free GstControlPoint structures */
635   g_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL);
636   g_list_free (self->priv->values);
637   self->priv->last_requested_value = NULL;
638   self->priv->values = NULL;
639   self->priv->nvalues = 0;
640   self->priv->valid_cache = FALSE;
641
642   g_mutex_unlock (self->lock);
643 }
644
645 /**
646  * gst_interpolation_control_source_get_all:
647  * @self: the #GstInterpolationControlSource to get the list from
648  *
649  * Returns a read-only copy of the list of #GstTimedValue for the given property.
650  * Free the list after done with it.
651  *
652  * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
653  */
654 GList *
655 gst_interpolation_control_source_get_all (GstInterpolationControlSource * self)
656 {
657   GList *res = NULL;
658
659   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL);
660
661   g_mutex_lock (self->lock);
662   if (self->priv->values)
663     res = g_list_copy (self->priv->values);
664   g_mutex_unlock (self->lock);
665
666   return res;
667 }
668
669 /**
670  * gst_interpolation_control_source_get_count:
671  * @self: the #GstInterpolationControlSource to get the number of values from
672  *
673  * Returns the number of control points that are set.
674  *
675  * Returns: the number of control points that are set.
676  *
677  */
678 gint
679 gst_interpolation_control_source_get_count (GstInterpolationControlSource *
680     self)
681 {
682   g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0);
683   return self->priv->nvalues;
684 }
685
686 static void
687 gst_interpolation_control_source_init (GstInterpolationControlSource * self)
688 {
689   self->lock = g_mutex_new ();
690   self->priv =
691       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE,
692       GstInterpolationControlSourcePrivate);
693   self->priv->interpolation_mode = GST_INTERPOLATE_NONE;
694 }
695
696 static void
697 gst_interpolation_control_source_finalize (GObject * obj)
698 {
699   GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj);
700
701   g_mutex_lock (self->lock);
702   gst_interpolation_control_source_reset (self);
703   g_mutex_unlock (self->lock);
704   g_mutex_free (self->lock);
705   G_OBJECT_CLASS (parent_class)->finalize (obj);
706 }
707
708 static void
709 gst_interpolation_control_source_dispose (GObject * obj)
710 {
711   G_OBJECT_CLASS (parent_class)->dispose (obj);
712 }
713
714 static void
715 gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
716     * klass)
717 {
718   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
719   GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
720
721   parent_class = g_type_class_peek_parent (klass);
722   g_type_class_add_private (klass,
723       sizeof (GstInterpolationControlSourcePrivate));
724
725   gobject_class->finalize = gst_interpolation_control_source_finalize;
726   gobject_class->dispose = gst_interpolation_control_source_dispose;
727   csource_class->bind = gst_interpolation_control_source_bind;
728 }