8f7d1d86f6fe1f67ee4cde96cb139ea5cf24965a
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 */
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 */
40 #include <glib-object.h>
41 #include <gst/gst.h>
43 #include "gstcontrolsource.h"
44 #include "gstinterpolationcontrolsource.h"
45 #include "gstinterpolationcontrolsourceprivate.h"
47 #define GST_CAT_DEFAULT controller_debug
48 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
50 G_DEFINE_TYPE (GstInterpolationControlSource, gst_interpolation_control_source,
51 GST_TYPE_CONTROL_SOURCE);
53 static GObjectClass *parent_class = NULL;
55 /*
56 * gst_control_point_free:
57 * @prop: the object to free
58 *
59 * Private method which frees all data allocated by a #GstControlPoint
60 * instance.
61 */
62 static void
63 gst_control_point_free (GstControlPoint * cp)
64 {
65 g_return_if_fail (cp);
67 g_value_unset (&cp->value);
68 g_slice_free (GstControlPoint, cp);
69 }
71 static void
72 gst_interpolation_control_source_reset (GstInterpolationControlSource * self)
73 {
74 GstControlSource *csource = (GstControlSource *) self;
76 csource->get_value = NULL;
77 csource->get_value_array = NULL;
79 self->priv->type = self->priv->base = G_TYPE_INVALID;
81 if (G_IS_VALUE (&self->priv->default_value))
82 g_value_unset (&self->priv->default_value);
83 if (G_IS_VALUE (&self->priv->minimum_value))
84 g_value_unset (&self->priv->minimum_value);
85 if (G_IS_VALUE (&self->priv->maximum_value))
86 g_value_unset (&self->priv->maximum_value);
88 if (self->priv->values) {
89 g_sequence_free (self->priv->values);
90 self->priv->values = NULL;
91 }
93 self->priv->nvalues = 0;
94 self->priv->valid_cache = FALSE;
95 }
97 /**
98 * gst_interpolation_control_source_new:
99 *
100 * This returns a new, unbound #GstInterpolationControlSource.
101 *
102 * Returns: a new, unbound #GstInterpolationControlSource.
103 */
104 GstInterpolationControlSource *
105 gst_interpolation_control_source_new (void)
106 {
107 return g_object_newv (GST_TYPE_INTERPOLATION_CONTROL_SOURCE, 0, NULL);
108 }
110 /**
111 * gst_interpolation_control_source_set_interpolation_mode:
112 * @self: the #GstInterpolationControlSource object
113 * @mode: interpolation mode
114 *
115 * Sets the given interpolation mode.
116 *
117 * <note><para>User interpolation is not yet available and quadratic interpolation
118 * is deprecated and maps to cubic interpolation.</para></note>
119 *
120 * Returns: %TRUE if the interpolation mode could be set, %FALSE otherwise
121 */
122 /* *INDENT-OFF* */
123 gboolean
124 gst_interpolation_control_source_set_interpolation_mode (
125 GstInterpolationControlSource * self, GstInterpolateMode mode)
126 /* *INDENT-ON* */
127 {
128 gboolean ret = TRUE;
129 GstControlSource *csource = GST_CONTROL_SOURCE (self);
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 }
137 if (mode == GST_INTERPOLATE_QUADRATIC) {
138 GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
139 "interpolation mode");
140 }
142 if (mode == GST_INTERPOLATE_USER) {
143 GST_WARNING ("User interpolation mode is not implemented yet");
144 return FALSE;
145 }
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 }
219 /* Incomplete implementation */
220 if (!ret || !csource->get_value || !csource->get_value_array) {
221 gst_interpolation_control_source_reset (self);
222 ret = FALSE;
223 }
225 self->priv->valid_cache = FALSE;
226 self->priv->interpolation_mode = mode;
228 g_mutex_unlock (self->lock);
230 return ret;
231 }
233 static gboolean
234 gst_interpolation_control_source_bind (GstControlSource * source,
235 GParamSpec * pspec)
236 {
237 GType type, base;
238 GstInterpolationControlSource *self =
239 (GstInterpolationControlSource *) source;
240 gboolean ret = TRUE;
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;
247 self->priv->base = base;
248 /* restore type */
249 type = self->priv->type;
251 if (!gst_interpolation_control_source_set_interpolation_mode (self,
252 self->priv->interpolation_mode))
253 return FALSE;
255 switch (base) {
256 case G_TYPE_INT:{
257 GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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 }
372 if (ret) {
373 self->priv->valid_cache = FALSE;
374 self->priv->nvalues = 0;
375 } else {
376 gst_interpolation_control_source_reset (self);
377 }
379 return ret;
380 }
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;
396 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
397 }
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;
413 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
414 }
416 static GstControlPoint *
417 _make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp,
418 const GValue * value)
419 {
420 GstControlPoint *cp;
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);
428 return cp;
429 }
431 static void
432 gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
433 self, GstClockTime timestamp, const GValue * value)
434 {
435 GSequenceIter *iter;
437 /* check if a control point for the timestamp already exists */
439 /* iter contains the iter right *after* timestamp */
440 if (G_LIKELY (self->priv->values)) {
441 iter =
442 g_sequence_search (self->priv->values, ×tamp,
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);
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 } else {
457 self->priv->values =
458 g_sequence_new ((GDestroyNotify) gst_control_point_free);
459 }
461 /* sort new cp into the prop->values list */
462 g_sequence_insert_sorted (self->priv->values, _make_new_cp (self, timestamp,
463 value), (GCompareDataFunc) gst_control_point_compare, NULL);
464 self->priv->nvalues++;
466 done:
467 self->priv->valid_cache = FALSE;
468 }
471 /**
472 * gst_interpolation_control_source_set:
473 * @self: the #GstInterpolationControlSource object
474 * @timestamp: the time the control-change is scheduled for
475 * @value: the control-value
476 *
477 * Set the value of given controller-handled property at a certain time.
478 *
479 * Returns: FALSE if the values couldn't be set, TRUE otherwise.
480 */
481 gboolean
482 gst_interpolation_control_source_set (GstInterpolationControlSource * self,
483 GstClockTime timestamp, const GValue * value)
484 {
485 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
486 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
487 g_return_val_if_fail (G_IS_VALUE (value), FALSE);
488 g_return_val_if_fail (G_VALUE_TYPE (value) == self->priv->type, FALSE);
490 g_mutex_lock (self->lock);
491 gst_interpolation_control_source_set_internal (self, timestamp, value);
492 g_mutex_unlock (self->lock);
494 return TRUE;
495 }
497 /**
498 * gst_interpolation_control_source_set_from_list:
499 * @self: the #GstInterpolationControlSource object
500 * @timedvalues: a list with #GstTimedValue items
501 *
502 * Sets multiple timed values at once.
503 *
504 * Returns: FALSE if the values couldn't be set, TRUE otherwise.
505 */
506 gboolean
507 gst_interpolation_control_source_set_from_list (GstInterpolationControlSource *
508 self, const GSList * timedvalues)
509 {
510 const GSList *node;
511 GstTimedValue *tv;
512 gboolean res = FALSE;
514 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
516 for (node = timedvalues; node; node = g_slist_next (node)) {
517 tv = node->data;
518 if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
519 GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
520 GST_FUNCTION);
521 } else if (!G_IS_VALUE (&tv->value)) {
522 GST_WARNING ("GstTimedValued with invalid value passed to %s",
523 GST_FUNCTION);
524 } else if (G_VALUE_TYPE (&tv->value) != self->priv->type) {
525 GST_WARNING ("incompatible value type for property");
526 } else {
527 g_mutex_lock (self->lock);
528 gst_interpolation_control_source_set_internal (self, tv->timestamp,
529 &tv->value);
530 g_mutex_unlock (self->lock);
531 res = TRUE;
532 }
533 }
534 return res;
535 }
537 /**
538 * gst_interpolation_control_source_unset:
539 * @self: the #GstInterpolationControlSource object
540 * @timestamp: the time the control-change should be removed from
541 *
542 * Used to remove the value of given controller-handled property at a certain
543 * time.
544 *
545 * Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
546 */
547 gboolean
548 gst_interpolation_control_source_unset (GstInterpolationControlSource * self,
549 GstClockTime timestamp)
550 {
551 GSequenceIter *iter;
552 gboolean res = FALSE;
554 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
555 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
557 g_mutex_lock (self->lock);
558 /* check if a control point for the timestamp exists */
559 if (G_LIKELY (self->priv->values) && (iter =
560 g_sequence_search (self->priv->values, ×tamp,
561 (GCompareDataFunc) gst_control_point_find, NULL))) {
562 GstControlPoint *cp;
564 /* Iter contains the iter right after timestamp, i.e.
565 * we need to get the previous one and check the timestamp
566 */
567 iter = g_sequence_iter_prev (iter);
568 cp = g_sequence_get (iter);
569 if (cp->timestamp == timestamp) {
570 g_sequence_remove (iter);
571 self->priv->nvalues--;
572 self->priv->valid_cache = FALSE;
573 res = TRUE;
574 }
575 }
576 g_mutex_unlock (self->lock);
578 return res;
579 }
581 /**
582 * gst_interpolation_control_source_unset_all:
583 * @self: the #GstInterpolationControlSource object
584 *
585 * Used to remove all time-stamped values of given controller-handled property
586 *
587 */
588 void
589 gst_interpolation_control_source_unset_all (GstInterpolationControlSource *
590 self)
591 {
592 g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self));
594 g_mutex_lock (self->lock);
595 /* free GstControlPoint structures */
596 if (self->priv->values) {
597 g_sequence_free (self->priv->values);
598 self->priv->values = NULL;
599 }
600 self->priv->nvalues = 0;
601 self->priv->valid_cache = FALSE;
603 g_mutex_unlock (self->lock);
604 }
606 static void
607 _append_control_point (GstControlPoint * cp, GList ** l)
608 {
609 *l = g_list_prepend (*l, cp);
610 }
612 /**
613 * gst_interpolation_control_source_get_all:
614 * @self: the #GstInterpolationControlSource to get the list from
615 *
616 * Returns a read-only copy of the list of #GstTimedValue for the given property.
617 * Free the list after done with it.
618 *
619 * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
620 */
621 GList *
622 gst_interpolation_control_source_get_all (GstInterpolationControlSource * self)
623 {
624 GList *res = NULL;
626 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL);
628 g_mutex_lock (self->lock);
629 if (G_LIKELY (self->priv->values))
630 g_sequence_foreach (self->priv->values, (GFunc) _append_control_point,
631 &res);
632 g_mutex_unlock (self->lock);
634 return g_list_reverse (res);
635 }
637 /**
638 * gst_interpolation_control_source_get_count:
639 * @self: the #GstInterpolationControlSource to get the number of values from
640 *
641 * Returns the number of control points that are set.
642 *
643 * Returns: the number of control points that are set.
644 *
645 */
646 gint
647 gst_interpolation_control_source_get_count (GstInterpolationControlSource *
648 self)
649 {
650 g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0);
651 return self->priv->nvalues;
652 }
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 }
665 static void
666 gst_interpolation_control_source_finalize (GObject * obj)
667 {
668 GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj);
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 }
677 static void
678 gst_interpolation_control_source_dispose (GObject * obj)
679 {
680 G_OBJECT_CLASS (parent_class)->dispose (obj);
681 }
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);
690 parent_class = g_type_class_peek_parent (klass);
691 g_type_class_add_private (klass,
692 sizeof (GstInterpolationControlSourcePrivate));
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 }