3 * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
4 * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
6 * gstinterpolation.c: Interpolation methods for dynamic properties
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.
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.
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.
28 #include "gstinterpolationcontrolsource.h"
29 #include "gstinterpolationcontrolsourceprivate.h"
31 #define GST_CAT_DEFAULT controller_debug
32 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
39 gst_control_point_find (gconstpointer p1, gconstpointer p2)
41 GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
42 GstClockTime ct2 = *(GstClockTime *) p2;
44 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
48 * gst_interpolation_control_source_find_control_point_iter:
49 * @self: the interpolation control source to search in
50 * @timestamp: the search key
52 * Find last value before given timestamp in control point list.
54 * Returns: the found #GSequenceIter or %NULL
56 static GSequenceIter *gst_interpolation_control_source_find_control_point_iter
57 (GstInterpolationControlSource * self, GstClockTime timestamp)
62 if (!self->priv->values)
66 g_sequence_search (self->priv->values, ×tamp,
67 (GCompareDataFunc) gst_control_point_find, NULL);
69 /* g_sequence_search() returns the iter where timestamp
70 * would be inserted, i.e. the iter > timestamp, so
71 * we need to get the previous one */
72 iter = g_sequence_iter_prev (iter);
74 /* g_sequence_iter_prev () on the begin iter returns
75 * the begin iter. Check if the prev iter is still
76 * after our timestamp, in that case return NULL
78 cp = g_sequence_get (iter);
79 if (cp->timestamp > timestamp)
82 /* If the iter is the end iter return NULL as no
83 * data is linked to the end iter */
84 return G_UNLIKELY (g_sequence_iter_is_end (iter)) ? NULL : iter;
87 /* steps-like (no-)interpolation, default */
88 /* just returns the value for the most recent key-frame */
90 #define DEFINE_NONE_GET(type) \
91 static inline GValue * \
92 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
95 GSequenceIter *iter; \
98 gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \
99 GstControlPoint *cp = g_sequence_get (iter); \
100 g##type ret_val = g_value_get_##type (&cp->value); \
102 if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
103 ret = &self->priv->minimum_value; \
104 else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
105 ret = &self->priv->maximum_value; \
109 ret = &self->priv->default_value; \
115 interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
118 g_mutex_lock (self->lock); \
120 ret = _interpolate_none_get_##type (self, timestamp); \
122 g_mutex_unlock (self->lock); \
125 g_value_copy (ret, value); \
126 g_mutex_unlock (self->lock); \
131 interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \
132 GstClockTime timestamp, GstValueArray * value_array) \
135 GstClockTime ts = timestamp; \
136 g##type *values = (g##type *) value_array->values; \
139 g_mutex_lock (self->lock); \
140 for(i = 0; i < value_array->nbsamples; i++) { \
141 ret = _interpolate_none_get_##type (self, ts); \
143 g_mutex_unlock (self->lock); \
146 *values = g_value_get_##type (ret); \
147 ts += value_array->sample_interval; \
150 g_mutex_unlock (self->lock); \
155 DEFINE_NONE_GET (int);
156 DEFINE_NONE_GET (uint);
157 DEFINE_NONE_GET (long);
159 DEFINE_NONE_GET (ulong);
160 DEFINE_NONE_GET (int64);
161 DEFINE_NONE_GET (uint64);
162 DEFINE_NONE_GET (float);
163 DEFINE_NONE_GET (double);
165 static inline GValue *
166 _interpolate_none_get (GstInterpolationControlSource * self,
167 GstClockTime timestamp)
173 gst_interpolation_control_source_find_control_point_iter (self,
175 GstControlPoint *cp = g_sequence_get (iter);
179 ret = &self->priv->default_value;
185 interpolate_none_get (GstInterpolationControlSource * self,
186 GstClockTime timestamp, GValue * value)
190 g_mutex_lock (self->lock);
191 ret = _interpolate_none_get (self, timestamp);
194 g_mutex_unlock (self->lock);
198 g_value_copy (ret, value);
199 g_mutex_unlock (self->lock);
204 interpolate_none_get_boolean_value_array (GstInterpolationControlSource * self,
205 GstClockTime timestamp, GstValueArray * value_array)
208 GstClockTime ts = timestamp;
209 gboolean *values = (gboolean *) value_array->values;
212 g_mutex_lock (self->lock);
213 for (i = 0; i < value_array->nbsamples; i++) {
214 ret = _interpolate_none_get (self, ts);
216 g_mutex_unlock (self->lock);
219 *values = g_value_get_boolean (ret);
220 ts += value_array->sample_interval;
223 g_mutex_unlock (self->lock);
228 interpolate_none_get_enum_value_array (GstInterpolationControlSource * self,
229 GstClockTime timestamp, GstValueArray * value_array)
232 GstClockTime ts = timestamp;
233 gint *values = (gint *) value_array->values;
236 g_mutex_lock (self->lock);
237 for (i = 0; i < value_array->nbsamples; i++) {
238 ret = _interpolate_none_get (self, ts);
240 g_mutex_unlock (self->lock);
243 *values = g_value_get_enum (ret);
244 ts += value_array->sample_interval;
247 g_mutex_unlock (self->lock);
252 interpolate_none_get_string_value_array (GstInterpolationControlSource * self,
253 GstClockTime timestamp, GstValueArray * value_array)
256 GstClockTime ts = timestamp;
257 gchar **values = (gchar **) value_array->values;
260 g_mutex_lock (self->lock);
261 for (i = 0; i < value_array->nbsamples; i++) {
262 ret = _interpolate_none_get (self, ts);
264 g_mutex_unlock (self->lock);
267 *values = (gchar *) g_value_get_string (ret);
268 ts += value_array->sample_interval;
271 g_mutex_unlock (self->lock);
275 static GstInterpolateMethod interpolate_none = {
276 (GstControlSourceGetValue) interpolate_none_get_int,
277 (GstControlSourceGetValueArray) interpolate_none_get_int_value_array,
278 (GstControlSourceGetValue) interpolate_none_get_uint,
279 (GstControlSourceGetValueArray) interpolate_none_get_uint_value_array,
280 (GstControlSourceGetValue) interpolate_none_get_long,
281 (GstControlSourceGetValueArray) interpolate_none_get_long_value_array,
282 (GstControlSourceGetValue) interpolate_none_get_ulong,
283 (GstControlSourceGetValueArray) interpolate_none_get_ulong_value_array,
284 (GstControlSourceGetValue) interpolate_none_get_int64,
285 (GstControlSourceGetValueArray) interpolate_none_get_int64_value_array,
286 (GstControlSourceGetValue) interpolate_none_get_uint64,
287 (GstControlSourceGetValueArray) interpolate_none_get_uint64_value_array,
288 (GstControlSourceGetValue) interpolate_none_get_float,
289 (GstControlSourceGetValueArray) interpolate_none_get_float_value_array,
290 (GstControlSourceGetValue) interpolate_none_get_double,
291 (GstControlSourceGetValueArray) interpolate_none_get_double_value_array,
292 (GstControlSourceGetValue) interpolate_none_get,
293 (GstControlSourceGetValueArray) interpolate_none_get_boolean_value_array,
294 (GstControlSourceGetValue) interpolate_none_get,
295 (GstControlSourceGetValueArray) interpolate_none_get_enum_value_array,
296 (GstControlSourceGetValue) interpolate_none_get,
297 (GstControlSourceGetValueArray) interpolate_none_get_string_value_array
300 /* returns the default value of the property, except for times with specific values */
301 /* needed for one-shot events, such as notes and triggers */
303 #define DEFINE_TRIGGER_GET(type) \
304 static inline GValue * \
305 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
307 GSequenceIter *iter; \
308 GstControlPoint *cp; \
310 /* check if there is a value at the registered timestamp */ \
312 gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \
313 cp = g_sequence_get (iter); \
314 if (timestamp == cp->timestamp) { \
315 g##type ret = g_value_get_##type (&cp->value); \
316 if (g_value_get_##type (&self->priv->minimum_value) > ret) \
317 return &self->priv->minimum_value; \
318 else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
319 return &self->priv->maximum_value; \
325 if (self->priv->nvalues > 0) \
326 return &self->priv->default_value; \
332 interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
335 g_mutex_lock (self->lock); \
336 ret = _interpolate_trigger_get_##type (self, timestamp); \
338 g_mutex_unlock (self->lock); \
341 g_value_copy (ret, value); \
342 g_mutex_unlock (self->lock); \
347 interpolate_trigger_get_##type##_value_array (GstInterpolationControlSource *self, \
348 GstClockTime timestamp, GstValueArray * value_array) \
351 GstClockTime ts = timestamp; \
352 g##type *values = (g##type *) value_array->values; \
355 g_mutex_lock (self->lock); \
356 for(i = 0; i < value_array->nbsamples; i++) { \
357 ret = _interpolate_trigger_get_##type (self, ts); \
359 g_mutex_unlock (self->lock); \
362 *values = g_value_get_##type (ret); \
363 ts += value_array->sample_interval; \
366 g_mutex_unlock (self->lock); \
371 DEFINE_TRIGGER_GET (int);
373 DEFINE_TRIGGER_GET (uint);
374 DEFINE_TRIGGER_GET (long);
376 DEFINE_TRIGGER_GET (ulong);
377 DEFINE_TRIGGER_GET (int64);
378 DEFINE_TRIGGER_GET (uint64);
379 DEFINE_TRIGGER_GET (float);
380 DEFINE_TRIGGER_GET (double);
382 static inline GValue *
383 _interpolate_trigger_get (GstInterpolationControlSource * self,
384 GstClockTime timestamp)
389 /* check if there is a value at the registered timestamp */
391 gst_interpolation_control_source_find_control_point_iter (self,
393 cp = g_sequence_get (iter);
394 if (timestamp == cp->timestamp) {
398 if (self->priv->nvalues > 0)
399 return &self->priv->default_value;
405 interpolate_trigger_get (GstInterpolationControlSource * self,
406 GstClockTime timestamp, GValue * value)
410 g_mutex_lock (self->lock);
411 ret = _interpolate_trigger_get (self, timestamp);
413 g_mutex_unlock (self->lock);
416 g_value_copy (ret, value);
417 g_mutex_unlock (self->lock);
422 interpolate_trigger_get_boolean_value_array (GstInterpolationControlSource *
423 self, GstClockTime timestamp, GstValueArray * value_array)
426 GstClockTime ts = timestamp;
427 gint *values = (gint *) value_array->values;
430 g_mutex_lock (self->lock);
431 for (i = 0; i < value_array->nbsamples; i++) {
432 ret = _interpolate_trigger_get (self, ts);
434 g_mutex_unlock (self->lock);
437 *values = g_value_get_boolean (ret);
438 ts += value_array->sample_interval;
441 g_mutex_unlock (self->lock);
446 interpolate_trigger_get_enum_value_array (GstInterpolationControlSource * self,
447 GstClockTime timestamp, GstValueArray * value_array)
450 GstClockTime ts = timestamp;
451 gint *values = (gint *) value_array->values;
454 g_mutex_lock (self->lock);
455 for (i = 0; i < value_array->nbsamples; i++) {
456 ret = _interpolate_trigger_get (self, ts);
458 g_mutex_unlock (self->lock);
461 *values = g_value_get_enum (ret);
462 ts += value_array->sample_interval;
465 g_mutex_unlock (self->lock);
470 interpolate_trigger_get_string_value_array (GstInterpolationControlSource *
471 self, GstClockTime timestamp, GstValueArray * value_array)
474 GstClockTime ts = timestamp;
475 gchar **values = (gchar **) value_array->values;
478 g_mutex_lock (self->lock);
479 for (i = 0; i < value_array->nbsamples; i++) {
480 ret = _interpolate_trigger_get (self, ts);
482 g_mutex_unlock (self->lock);
485 *values = (gchar *) g_value_get_string (ret);
486 ts += value_array->sample_interval;
489 g_mutex_unlock (self->lock);
493 static GstInterpolateMethod interpolate_trigger = {
494 (GstControlSourceGetValue) interpolate_trigger_get_int,
495 (GstControlSourceGetValueArray) interpolate_trigger_get_int_value_array,
496 (GstControlSourceGetValue) interpolate_trigger_get_uint,
497 (GstControlSourceGetValueArray) interpolate_trigger_get_uint_value_array,
498 (GstControlSourceGetValue) interpolate_trigger_get_long,
499 (GstControlSourceGetValueArray) interpolate_trigger_get_long_value_array,
500 (GstControlSourceGetValue) interpolate_trigger_get_ulong,
501 (GstControlSourceGetValueArray) interpolate_trigger_get_ulong_value_array,
502 (GstControlSourceGetValue) interpolate_trigger_get_int64,
503 (GstControlSourceGetValueArray) interpolate_trigger_get_int64_value_array,
504 (GstControlSourceGetValue) interpolate_trigger_get_uint64,
505 (GstControlSourceGetValueArray) interpolate_trigger_get_uint64_value_array,
506 (GstControlSourceGetValue) interpolate_trigger_get_float,
507 (GstControlSourceGetValueArray) interpolate_trigger_get_float_value_array,
508 (GstControlSourceGetValue) interpolate_trigger_get_double,
509 (GstControlSourceGetValueArray) interpolate_trigger_get_double_value_array,
510 (GstControlSourceGetValue) interpolate_trigger_get,
511 (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array,
512 (GstControlSourceGetValue) interpolate_trigger_get,
513 (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array,
514 (GstControlSourceGetValue) interpolate_trigger_get,
515 (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array
518 /* linear interpolation */
519 /* smoothes inbetween values */
521 #define DEFINE_LINEAR_GET(vtype,round,convert) \
522 static inline gboolean \
523 _interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \
525 GSequenceIter *iter; \
526 GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \
528 iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
530 cp1 = g_sequence_get (iter); \
531 iter = g_sequence_iter_next (iter); \
532 iter = g_sequence_iter_is_end (iter) ? NULL : iter; \
534 cp.timestamp = G_GUINT64_CONSTANT(0); \
535 g_value_init (&cp.value, self->priv->type); \
536 g_value_copy (&self->priv->default_value, &cp.value); \
538 if (G_LIKELY (self->priv->values)) \
539 iter = g_sequence_get_begin_iter (self->priv->values); \
543 g##vtype value1,value2; \
545 cp2 = g_sequence_get (iter); \
547 value1 = g_value_get_##vtype (&cp1->value); \
548 value2 = g_value_get_##vtype (&cp2->value); \
549 slope = ((gdouble) convert (value2) - (gdouble) convert (value1)) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
552 *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \
554 *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \
557 *ret = g_value_get_##vtype (&cp1->value); \
559 *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \
564 interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
567 g_mutex_lock (self->lock); \
568 if (_interpolate_linear_get_##vtype (self, timestamp, &ret)) { \
569 g_value_set_##vtype (value, ret); \
570 g_mutex_unlock (self->lock); \
573 g_mutex_unlock (self->lock); \
578 interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \
579 GstClockTime timestamp, GstValueArray * value_array) \
582 GstClockTime ts = timestamp; \
583 g##vtype *values = (g##vtype *) value_array->values; \
585 g_mutex_lock (self->lock); \
586 for(i = 0; i < value_array->nbsamples; i++) { \
587 if (! _interpolate_linear_get_##vtype (self, ts, values)) { \
588 g_mutex_unlock (self->lock); \
591 ts += value_array->sample_interval; \
594 g_mutex_unlock (self->lock); \
598 DEFINE_LINEAR_GET (int, TRUE, EMPTY);
600 DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
601 DEFINE_LINEAR_GET (long, TRUE, EMPTY);
603 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
604 DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
605 DEFINE_LINEAR_GET (uint64, TRUE, gst_guint64_to_gdouble);
606 DEFINE_LINEAR_GET (float, FALSE, EMPTY);
607 DEFINE_LINEAR_GET (double, FALSE, EMPTY);
609 static GstInterpolateMethod interpolate_linear = {
610 (GstControlSourceGetValue) interpolate_linear_get_int,
611 (GstControlSourceGetValueArray) interpolate_linear_get_int_value_array,
612 (GstControlSourceGetValue) interpolate_linear_get_uint,
613 (GstControlSourceGetValueArray) interpolate_linear_get_uint_value_array,
614 (GstControlSourceGetValue) interpolate_linear_get_long,
615 (GstControlSourceGetValueArray) interpolate_linear_get_long_value_array,
616 (GstControlSourceGetValue) interpolate_linear_get_ulong,
617 (GstControlSourceGetValueArray) interpolate_linear_get_ulong_value_array,
618 (GstControlSourceGetValue) interpolate_linear_get_int64,
619 (GstControlSourceGetValueArray) interpolate_linear_get_int64_value_array,
620 (GstControlSourceGetValue) interpolate_linear_get_uint64,
621 (GstControlSourceGetValueArray) interpolate_linear_get_uint64_value_array,
622 (GstControlSourceGetValue) interpolate_linear_get_float,
623 (GstControlSourceGetValueArray) interpolate_linear_get_float_value_array,
624 (GstControlSourceGetValue) interpolate_linear_get_double,
625 (GstControlSourceGetValueArray) interpolate_linear_get_double_value_array,
626 (GstControlSourceGetValue) NULL,
627 (GstControlSourceGetValueArray) NULL,
628 (GstControlSourceGetValue) NULL,
629 (GstControlSourceGetValueArray) NULL,
630 (GstControlSourceGetValue) NULL,
631 (GstControlSourceGetValueArray) NULL
634 /* square interpolation */
636 /* cubic interpolation */
638 /* The following functions implement a natural cubic spline interpolator.
639 * For details look at http://en.wikipedia.org/wiki/Spline_interpolation
641 * Instead of using a real matrix with n^2 elements for the linear system
642 * of equations we use three arrays o, p, q to hold the tridiagonal matrix
643 * as following to save memory:
651 #define DEFINE_CUBIC_GET(vtype,round, convert) \
653 _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
655 gint i, n = self->priv->nvalues; \
656 gdouble *o = g_new0 (gdouble, n); \
657 gdouble *p = g_new0 (gdouble, n); \
658 gdouble *q = g_new0 (gdouble, n); \
660 gdouble *h = g_new0 (gdouble, n); \
661 gdouble *b = g_new0 (gdouble, n); \
662 gdouble *z = g_new0 (gdouble, n); \
664 GSequenceIter *iter; \
665 GstControlPoint *cp; \
666 GstClockTime x_prev, x, x_next; \
667 g##vtype y_prev, y, y_next; \
669 /* Fill linear system of equations */ \
670 iter = g_sequence_get_begin_iter (self->priv->values); \
671 cp = g_sequence_get (iter); \
673 y = g_value_get_##vtype (&cp->value); \
677 iter = g_sequence_iter_next (iter); \
678 cp = g_sequence_get (iter); \
679 x_next = cp->timestamp; \
680 y_next = g_value_get_##vtype (&cp->value); \
681 h[0] = gst_guint64_to_gdouble (x_next - x); \
683 for (i = 1; i < n-1; i++) { \
684 /* Shuffle x and y values */ \
689 iter = g_sequence_iter_next (iter); \
690 cp = g_sequence_get (iter); \
691 x_next = cp->timestamp; \
692 y_next = g_value_get_##vtype (&cp->value); \
694 h[i] = gst_guint64_to_gdouble (x_next - x); \
696 p[i] = 2.0 * (h[i-1] + h[i]); \
698 b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
702 /* Use Gauss elimination to set everything below the \
703 * diagonal to zero */ \
704 for (i = 1; i < n-1; i++) { \
705 gdouble a = o[i] / p[i-1]; \
706 p[i] -= a * q[i-1]; \
707 b[i] -= a * b[i-1]; \
710 /* Solve everything else from bottom to top */ \
711 for (i = n-2; i > 0; i--) \
712 z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
714 /* Save cache next in the GstControlPoint */ \
716 iter = g_sequence_get_begin_iter (self->priv->values); \
717 for (i = 0; i < n; i++) { \
718 cp = g_sequence_get (iter); \
719 cp->cache.cubic.h = h[i]; \
720 cp->cache.cubic.z = z[i]; \
721 iter = g_sequence_iter_next (iter); \
724 /* Free our temporary arrays */ \
733 static inline gboolean \
734 _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \
736 GSequenceIter *iter; \
737 GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \
739 if (self->priv->nvalues <= 2) \
740 return _interpolate_linear_get_##vtype (self, timestamp, ret); \
742 if (!self->priv->valid_cache) { \
743 _interpolate_cubic_update_cache_##vtype (self); \
744 self->priv->valid_cache = TRUE; \
747 iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
749 cp1 = g_sequence_get (iter); \
750 iter = g_sequence_iter_next (iter); \
751 iter = g_sequence_iter_is_end (iter) ? NULL : iter; \
753 cp.timestamp = G_GUINT64_CONSTANT(0); \
754 g_value_init (&cp.value, self->priv->type); \
755 g_value_copy (&self->priv->default_value, &cp.value); \
757 iter = g_sequence_get_begin_iter (self->priv->values); \
760 gdouble diff1, diff2; \
761 g##vtype value1,value2; \
764 cp2 = g_sequence_get (iter); \
766 value1 = g_value_get_##vtype (&cp1->value); \
767 value2 = g_value_get_##vtype (&cp2->value); \
769 diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \
770 diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \
772 out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
773 out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
774 out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
777 *ret = (g##vtype) (out + 0.5); \
779 *ret = (g##vtype) out; \
782 *ret = g_value_get_##vtype (&cp1->value); \
784 *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \
789 interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
792 g_mutex_lock (self->lock); \
793 if (_interpolate_cubic_get_##vtype (self, timestamp, &ret)) { \
794 g_value_set_##vtype (value, ret); \
795 g_mutex_unlock (self->lock); \
798 g_mutex_unlock (self->lock); \
803 interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \
804 GstClockTime timestamp, GstValueArray * value_array) \
807 GstClockTime ts = timestamp; \
808 g##vtype *values = (g##vtype *) value_array->values; \
810 g_mutex_lock (self->lock); \
811 for(i = 0; i < value_array->nbsamples; i++) { \
812 if (! _interpolate_cubic_get_##vtype (self, ts, values)) { \
813 g_mutex_unlock (self->lock); \
816 ts += value_array->sample_interval; \
819 g_mutex_unlock (self->lock); \
823 DEFINE_CUBIC_GET (int, TRUE, EMPTY);
825 DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
826 DEFINE_CUBIC_GET (long, TRUE, EMPTY);
828 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
829 DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
830 DEFINE_CUBIC_GET (uint64, TRUE, gst_guint64_to_gdouble);
831 DEFINE_CUBIC_GET (float, FALSE, EMPTY);
832 DEFINE_CUBIC_GET (double, FALSE, EMPTY);
834 static GstInterpolateMethod interpolate_cubic = {
835 (GstControlSourceGetValue) interpolate_cubic_get_int,
836 (GstControlSourceGetValueArray) interpolate_cubic_get_int_value_array,
837 (GstControlSourceGetValue) interpolate_cubic_get_uint,
838 (GstControlSourceGetValueArray) interpolate_cubic_get_uint_value_array,
839 (GstControlSourceGetValue) interpolate_cubic_get_long,
840 (GstControlSourceGetValueArray) interpolate_cubic_get_long_value_array,
841 (GstControlSourceGetValue) interpolate_cubic_get_ulong,
842 (GstControlSourceGetValueArray) interpolate_cubic_get_ulong_value_array,
843 (GstControlSourceGetValue) interpolate_cubic_get_int64,
844 (GstControlSourceGetValueArray) interpolate_cubic_get_int64_value_array,
845 (GstControlSourceGetValue) interpolate_cubic_get_uint64,
846 (GstControlSourceGetValueArray) interpolate_cubic_get_uint64_value_array,
847 (GstControlSourceGetValue) interpolate_cubic_get_float,
848 (GstControlSourceGetValueArray) interpolate_cubic_get_float_value_array,
849 (GstControlSourceGetValue) interpolate_cubic_get_double,
850 (GstControlSourceGetValueArray) interpolate_cubic_get_double_value_array,
851 (GstControlSourceGetValue) NULL,
852 (GstControlSourceGetValueArray) NULL,
853 (GstControlSourceGetValue) NULL,
854 (GstControlSourceGetValueArray) NULL,
855 (GstControlSourceGetValue) NULL,
856 (GstControlSourceGetValueArray) NULL
859 /* register all interpolation methods */
860 GstInterpolateMethod *priv_gst_interpolation_methods[] = {
862 &interpolate_trigger,
868 guint priv_gst_num_interpolation_methods =
869 G_N_ELEMENTS (priv_gst_interpolation_methods);