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