aboutsummaryrefslogtreecommitdiff
path: root/libs/gst/controller/gstinterpolation.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gst/controller/gstinterpolation.c')
-rw-r--r--libs/gst/controller/gstinterpolation.c811
1 files changed, 0 insertions, 811 deletions
diff --git a/libs/gst/controller/gstinterpolation.c b/libs/gst/controller/gstinterpolation.c
deleted file mode 100644
index 54ff60e..0000000
--- a/libs/gst/controller/gstinterpolation.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
- * Copyright (C) 2007-2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * gstinterpolation.c: Interpolation methods for dynamic properties
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstinterpolationcontrolsource.h"
-#include "gstinterpolationcontrolsourceprivate.h"
-
-#define GST_CAT_DEFAULT controller_debug
-GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
-
-#define EMPTY(x) (x)
-
-/* common helper */
-
-static gint
-gst_control_point_find (gconstpointer p1, gconstpointer p2)
-{
- GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
- GstClockTime ct2 = *(GstClockTime *) p2;
-
- return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
-}
-
-/*
- * gst_interpolation_control_source_find_control_point_iter:
- * @self: the interpolation control source to search in
- * @timestamp: the search key
- *
- * Find last value before given timestamp in control point list.
- * If all values in the control point list come after the given
- * timestamp or no values exist, %NULL is returned.
- *
- * Returns: the found #GSequenceIter or %NULL
- */
-static GSequenceIter *gst_interpolation_control_source_find_control_point_iter
- (GstInterpolationControlSource * self, GstClockTime timestamp)
-{
- GSequenceIter *iter;
-
- if (!self->priv->values)
- return NULL;
-
- iter =
- g_sequence_search (self->priv->values, &timestamp,
- (GCompareDataFunc) gst_control_point_find, NULL);
-
- /* g_sequence_search() returns the iter where timestamp
- * would be inserted, i.e. the iter > timestamp, so
- * we need to get the previous one. And of course, if
- * there is no previous one, we return NULL. */
- if (g_sequence_iter_is_begin (iter))
- return NULL;
-
- return g_sequence_iter_prev (iter);
-}
-
-/* steps-like (no-)interpolation, default */
-/* just returns the value for the most recent key-frame */
-static inline const GValue *
-_interpolate_none_get (GstInterpolationControlSource * self,
- GSequenceIter * iter)
-{
- const GValue *ret;
-
- if (iter) {
- GstControlPoint *cp = g_sequence_get (iter);
-
- ret = &cp->value;
- } else {
- ret = &self->priv->default_value;
- }
- return ret;
-}
-
-#define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \
-static inline const GValue * \
-_interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter) \
-{ \
- const GValue *ret; \
- \
- if (iter) { \
- GstControlPoint *cp = g_sequence_get (iter); \
- g##type ret_val = g_value_get_##type (&cp->value); \
- \
- if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
- ret = &self->priv->minimum_value; \
- else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
- ret = &self->priv->maximum_value; \
- else \
- ret = &cp->value; \
- } else { \
- ret = &self->priv->default_value; \
- } \
- return ret; \
-}
-
-#define DEFINE_NONE_GET(type,ctype,get_func) \
-static gboolean \
-interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
-{ \
- const GValue *ret; \
- GSequenceIter *iter; \
- \
- g_mutex_lock (self->lock); \
- \
- iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
- ret = get_func (self, iter); \
- g_value_copy (ret, value); \
- g_mutex_unlock (self->lock); \
- return TRUE; \
-} \
-\
-static gboolean \
-interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts = timestamp; \
- GstClockTime next_ts = 0; \
- ctype *values = (ctype *) value_array->values; \
- const GValue *ret_val = NULL; \
- ctype ret = 0; \
- GSequenceIter *iter1 = NULL, *iter2 = NULL; \
- \
- g_mutex_lock (self->lock); \
- for(i = 0; i < value_array->nbsamples; i++) { \
- if (!ret_val || ts >= next_ts) { \
- iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
- if (!iter1) { \
- if (G_LIKELY (self->priv->values)) \
- iter2 = g_sequence_get_begin_iter (self->priv->values); \
- else \
- iter2 = NULL; \
- } else { \
- iter2 = g_sequence_iter_next (iter1); \
- } \
- \
- if (iter2 && !g_sequence_iter_is_end (iter2)) { \
- GstControlPoint *cp; \
- \
- cp = g_sequence_get (iter2); \
- next_ts = cp->timestamp; \
- } else { \
- next_ts = GST_CLOCK_TIME_NONE; \
- } \
- \
- ret_val = get_func (self, iter1); \
- ret = g_value_get_##type (ret_val); \
- } \
- *values = ret; \
- ts += value_array->sample_interval; \
- values++; \
- } \
- g_mutex_unlock (self->lock); \
- return TRUE; \
-}
-
-DEFINE_NONE_GET_FUNC_COMPARABLE (int);
-DEFINE_NONE_GET (int, gint, _interpolate_none_get_int);
-DEFINE_NONE_GET_FUNC_COMPARABLE (uint);
-DEFINE_NONE_GET (uint, guint, _interpolate_none_get_uint);
-DEFINE_NONE_GET_FUNC_COMPARABLE (long);
-DEFINE_NONE_GET (long, glong, _interpolate_none_get_long);
-DEFINE_NONE_GET_FUNC_COMPARABLE (ulong);
-DEFINE_NONE_GET (ulong, gulong, _interpolate_none_get_ulong);
-DEFINE_NONE_GET_FUNC_COMPARABLE (int64);
-DEFINE_NONE_GET (int64, gint64, _interpolate_none_get_int64);
-DEFINE_NONE_GET_FUNC_COMPARABLE (uint64);
-DEFINE_NONE_GET (uint64, guint64, _interpolate_none_get_uint64);
-DEFINE_NONE_GET_FUNC_COMPARABLE (float);
-DEFINE_NONE_GET (float, gfloat, _interpolate_none_get_float);
-DEFINE_NONE_GET_FUNC_COMPARABLE (double);
-DEFINE_NONE_GET (double, gdouble, _interpolate_none_get_double);
-
-DEFINE_NONE_GET (boolean, gboolean, _interpolate_none_get);
-DEFINE_NONE_GET (enum, gint, _interpolate_none_get);
-DEFINE_NONE_GET (string, const gchar *, _interpolate_none_get);
-
-static GstInterpolateMethod interpolate_none = {
- (GstControlSourceGetValue) interpolate_none_get_int,
- (GstControlSourceGetValueArray) interpolate_none_get_int_value_array,
- (GstControlSourceGetValue) interpolate_none_get_uint,
- (GstControlSourceGetValueArray) interpolate_none_get_uint_value_array,
- (GstControlSourceGetValue) interpolate_none_get_long,
- (GstControlSourceGetValueArray) interpolate_none_get_long_value_array,
- (GstControlSourceGetValue) interpolate_none_get_ulong,
- (GstControlSourceGetValueArray) interpolate_none_get_ulong_value_array,
- (GstControlSourceGetValue) interpolate_none_get_int64,
- (GstControlSourceGetValueArray) interpolate_none_get_int64_value_array,
- (GstControlSourceGetValue) interpolate_none_get_uint64,
- (GstControlSourceGetValueArray) interpolate_none_get_uint64_value_array,
- (GstControlSourceGetValue) interpolate_none_get_float,
- (GstControlSourceGetValueArray) interpolate_none_get_float_value_array,
- (GstControlSourceGetValue) interpolate_none_get_double,
- (GstControlSourceGetValueArray) interpolate_none_get_double_value_array,
- (GstControlSourceGetValue) interpolate_none_get_boolean,
- (GstControlSourceGetValueArray) interpolate_none_get_boolean_value_array,
- (GstControlSourceGetValue) interpolate_none_get_enum,
- (GstControlSourceGetValueArray) interpolate_none_get_enum_value_array,
- (GstControlSourceGetValue) interpolate_none_get_string,
- (GstControlSourceGetValueArray) interpolate_none_get_string_value_array
-};
-
-/* returns the default value of the property, except for times with specific values */
-/* needed for one-shot events, such as notes and triggers */
-static inline const GValue *
-_interpolate_trigger_get (GstInterpolationControlSource * self,
- GSequenceIter * iter, GstClockTime timestamp)
-{
- GstControlPoint *cp;
-
- /* check if there is a value at the registered timestamp */
- if (iter) {
- cp = g_sequence_get (iter);
- if (timestamp == cp->timestamp) {
- return &cp->value;
- }
- }
- if (self->priv->nvalues > 0)
- return &self->priv->default_value;
- else
- return NULL;
-}
-
-#define DEFINE_TRIGGER_GET_FUNC_COMPARABLE(type) \
-static inline const GValue * \
-_interpolate_trigger_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter, GstClockTime timestamp) \
-{ \
- GstControlPoint *cp; \
- \
- /* check if there is a value at the registered timestamp */ \
- if (iter) { \
- cp = g_sequence_get (iter); \
- if (timestamp == cp->timestamp) { \
- g##type ret = g_value_get_##type (&cp->value); \
- if (g_value_get_##type (&self->priv->minimum_value) > ret) \
- return &self->priv->minimum_value; \
- else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
- return &self->priv->maximum_value; \
- else \
- return &cp->value; \
- } \
- } \
- \
- if (self->priv->nvalues > 0) \
- return &self->priv->default_value; \
- else \
- return NULL; \
-}
-
-#define DEFINE_TRIGGER_GET(type, ctype, get_func) \
-static gboolean \
-interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
-{ \
- const GValue *ret; \
- GSequenceIter *iter; \
- \
- g_mutex_lock (self->lock); \
- \
- iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
- ret = get_func (self, iter, timestamp); \
- if (!ret) { \
- g_mutex_unlock (self->lock); \
- return FALSE; \
- } \
- \
- g_value_copy (ret, value); \
- g_mutex_unlock (self->lock); \
- return TRUE; \
-} \
-\
-static gboolean \
-interpolate_trigger_get_##type##_value_array (GstInterpolationControlSource *self, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts = timestamp; \
- GstClockTime next_ts = 0; \
- ctype *values = (ctype *) value_array->values; \
- const GValue *ret_val = NULL; \
- ctype ret = 0; \
- GSequenceIter *iter1 = NULL, *iter2 = NULL; \
- gboolean triggered = FALSE; \
- \
- g_mutex_lock (self->lock); \
- for(i = 0; i < value_array->nbsamples; i++) { \
- if (!ret_val || ts >= next_ts) { \
- iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
- if (!iter1) { \
- if (G_LIKELY (self->priv->values)) \
- iter2 = g_sequence_get_begin_iter (self->priv->values); \
- else \
- iter2 = NULL; \
- } else { \
- iter2 = g_sequence_iter_next (iter1); \
- } \
- \
- if (iter2 && !g_sequence_iter_is_end (iter2)) { \
- GstControlPoint *cp; \
- \
- cp = g_sequence_get (iter2); \
- next_ts = cp->timestamp; \
- } else { \
- next_ts = GST_CLOCK_TIME_NONE; \
- } \
- \
- ret_val = get_func (self, iter1, ts); \
- if (!ret_val) { \
- g_mutex_unlock (self->lock); \
- return FALSE; \
- } \
- ret = g_value_get_##type (ret_val); \
- triggered = TRUE; \
- } else if (triggered) { \
- ret_val = get_func (self, iter1, ts); \
- if (!ret_val) { \
- g_mutex_unlock (self->lock); \
- return FALSE; \
- } \
- ret = g_value_get_##type (ret_val); \
- triggered = FALSE; \
- } \
- *values = ret; \
- ts += value_array->sample_interval; \
- values++; \
- } \
- g_mutex_unlock (self->lock); \
- return TRUE; \
-}
-
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int);
-DEFINE_TRIGGER_GET (int, gint, _interpolate_trigger_get_int);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint);
-DEFINE_TRIGGER_GET (uint, guint, _interpolate_trigger_get_uint);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (long);
-DEFINE_TRIGGER_GET (long, glong, _interpolate_trigger_get_long);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (ulong);
-DEFINE_TRIGGER_GET (ulong, gulong, _interpolate_trigger_get_ulong);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int64);
-DEFINE_TRIGGER_GET (int64, gint64, _interpolate_trigger_get_int64);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint64);
-DEFINE_TRIGGER_GET (uint64, guint64, _interpolate_trigger_get_uint64);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (float);
-DEFINE_TRIGGER_GET (float, gfloat, _interpolate_trigger_get_float);
-DEFINE_TRIGGER_GET_FUNC_COMPARABLE (double);
-DEFINE_TRIGGER_GET (double, gdouble, _interpolate_trigger_get_double);
-
-DEFINE_TRIGGER_GET (boolean, gboolean, _interpolate_trigger_get);
-DEFINE_TRIGGER_GET (enum, gint, _interpolate_trigger_get);
-DEFINE_TRIGGER_GET (string, const gchar *, _interpolate_trigger_get);
-
-static GstInterpolateMethod interpolate_trigger = {
- (GstControlSourceGetValue) interpolate_trigger_get_int,
- (GstControlSourceGetValueArray) interpolate_trigger_get_int_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_uint,
- (GstControlSourceGetValueArray) interpolate_trigger_get_uint_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_long,
- (GstControlSourceGetValueArray) interpolate_trigger_get_long_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_ulong,
- (GstControlSourceGetValueArray) interpolate_trigger_get_ulong_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_int64,
- (GstControlSourceGetValueArray) interpolate_trigger_get_int64_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_uint64,
- (GstControlSourceGetValueArray) interpolate_trigger_get_uint64_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_float,
- (GstControlSourceGetValueArray) interpolate_trigger_get_float_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_double,
- (GstControlSourceGetValueArray) interpolate_trigger_get_double_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_boolean,
- (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_enum,
- (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array,
- (GstControlSourceGetValue) interpolate_trigger_get_string,
- (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array
-};
-
-/* linear interpolation */
-/* smoothes inbetween values */
-#define DEFINE_LINEAR_GET(vtype, round, convert) \
-static inline void \
-_interpolate_linear_internal_##vtype (GstClockTime timestamp1, g##vtype value1, GstClockTime timestamp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \
-{ \
- if (GST_CLOCK_TIME_IS_VALID (timestamp2)) { \
- gdouble slope; \
- \
- slope = ((gdouble) convert (value2) - (gdouble) convert (value1)) / gst_guint64_to_gdouble (timestamp2 - timestamp1); \
- \
- if (round) \
- *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - timestamp1) * slope + 0.5); \
- else \
- *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - timestamp1) * slope); \
- } else { \
- *ret = value1; \
- } \
- *ret = CLAMP (*ret, min, max); \
-} \
-\
-static gboolean \
-interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
-{ \
- g##vtype ret, min, max; \
- GSequenceIter *iter; \
- GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
- \
- g_mutex_lock (self->lock); \
- \
- min = g_value_get_##vtype (&self->priv->minimum_value); \
- max = g_value_get_##vtype (&self->priv->maximum_value); \
- \
- iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
- if (iter) { \
- cp1 = g_sequence_get (iter); \
- iter = g_sequence_iter_next (iter); \
- } else { \
- cp.timestamp = G_GUINT64_CONSTANT(0); \
- g_value_init (&cp.value, self->priv->type); \
- g_value_copy (&self->priv->default_value, &cp.value); \
- cp1 = &cp; \
- if (G_LIKELY (self->priv->values)) \
- iter = g_sequence_get_begin_iter (self->priv->values); \
- } \
- if (iter && !g_sequence_iter_is_end (iter)) \
- cp2 = g_sequence_get (iter); \
- \
- _interpolate_linear_internal_##vtype (cp1->timestamp, g_value_get_##vtype (&cp1->value), (cp2 ? cp2->timestamp : GST_CLOCK_TIME_NONE), (cp2 ? g_value_get_##vtype (&cp2->value) : 0), timestamp, min, max, &ret); \
- g_value_set_##vtype (value, ret); \
- g_mutex_unlock (self->lock); \
- if (cp1 == &cp) \
- g_value_unset (&cp.value); \
- return TRUE; \
-} \
-\
-static gboolean \
-interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts = timestamp; \
- GstClockTime next_ts = 0; \
- g##vtype *values = (g##vtype *) value_array->values; \
- GSequenceIter *iter1, *iter2 = NULL; \
- GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
- g##vtype val1 = 0, val2 = 0, min, max; \
- \
- g_mutex_lock (self->lock); \
- \
- cp.timestamp = G_GUINT64_CONSTANT(0); \
- g_value_init (&cp.value, self->priv->type); \
- g_value_copy (&self->priv->default_value, &cp.value); \
- \
- min = g_value_get_##vtype (&self->priv->minimum_value); \
- max = g_value_get_##vtype (&self->priv->maximum_value); \
- \
- for(i = 0; i < value_array->nbsamples; i++) { \
- if (timestamp >= next_ts) { \
- iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
- if (!iter1) { \
- cp1 = &cp; \
- if (G_LIKELY (self->priv->values)) \
- iter2 = g_sequence_get_begin_iter (self->priv->values); \
- else \
- iter2 = NULL; \
- } else { \
- cp1 = g_sequence_get (iter1); \
- iter2 = g_sequence_iter_next (iter1); \
- } \
- \
- if (iter2 && !g_sequence_iter_is_end (iter2)) { \
- cp2 = g_sequence_get (iter2); \
- next_ts = cp2->timestamp; \
- } else { \
- next_ts = GST_CLOCK_TIME_NONE; \
- } \
- val1 = g_value_get_##vtype (&cp1->value); \
- if (cp2) \
- val2 = g_value_get_##vtype (&cp2->value); \
- } \
- _interpolate_linear_internal_##vtype (cp1->timestamp, val1, (cp2 ? cp2->timestamp : GST_CLOCK_TIME_NONE), (cp2 ? val2 : 0), ts, min, max, values); \
- ts += value_array->sample_interval; \
- values++; \
- } \
- g_mutex_unlock (self->lock); \
- g_value_unset (&cp.value); \
- return TRUE; \
-}
-
-DEFINE_LINEAR_GET (int, TRUE, EMPTY);
-DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
-DEFINE_LINEAR_GET (long, TRUE, EMPTY);
-DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
-DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
-DEFINE_LINEAR_GET (uint64, TRUE, gst_guint64_to_gdouble);
-DEFINE_LINEAR_GET (float, FALSE, EMPTY);
-DEFINE_LINEAR_GET (double, FALSE, EMPTY);
-
-static GstInterpolateMethod interpolate_linear = {
- (GstControlSourceGetValue) interpolate_linear_get_int,
- (GstControlSourceGetValueArray) interpolate_linear_get_int_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_uint,
- (GstControlSourceGetValueArray) interpolate_linear_get_uint_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_long,
- (GstControlSourceGetValueArray) interpolate_linear_get_long_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_ulong,
- (GstControlSourceGetValueArray) interpolate_linear_get_ulong_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_int64,
- (GstControlSourceGetValueArray) interpolate_linear_get_int64_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_uint64,
- (GstControlSourceGetValueArray) interpolate_linear_get_uint64_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_float,
- (GstControlSourceGetValueArray) interpolate_linear_get_float_value_array,
- (GstControlSourceGetValue) interpolate_linear_get_double,
- (GstControlSourceGetValueArray) interpolate_linear_get_double_value_array,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL
-};
-
-/* square interpolation */
-
-/* cubic interpolation */
-
-/* The following functions implement a natural cubic spline interpolator.
- * For details look at http://en.wikipedia.org/wiki/Spline_interpolation
- *
- * Instead of using a real matrix with n^2 elements for the linear system
- * of equations we use three arrays o, p, q to hold the tridiagonal matrix
- * as following to save memory:
- *
- * p[0] q[0] 0 0 0
- * o[1] p[1] q[1] 0 0
- * 0 o[2] p[2] q[2] .
- * . . . . .
- */
-
-#define DEFINE_CUBIC_GET(vtype,round, convert) \
-static void \
-_interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
-{ \
- gint i, n = self->priv->nvalues; \
- gdouble *o = g_new0 (gdouble, n); \
- gdouble *p = g_new0 (gdouble, n); \
- gdouble *q = g_new0 (gdouble, n); \
- \
- gdouble *h = g_new0 (gdouble, n); \
- gdouble *b = g_new0 (gdouble, n); \
- gdouble *z = g_new0 (gdouble, n); \
- \
- GSequenceIter *iter; \
- GstControlPoint *cp; \
- GstClockTime x, x_next; \
- g##vtype y_prev, y, y_next; \
- \
- /* Fill linear system of equations */ \
- iter = g_sequence_get_begin_iter (self->priv->values); \
- cp = g_sequence_get (iter); \
- x = cp->timestamp; \
- y = g_value_get_##vtype (&cp->value); \
- \
- p[0] = 1.0; \
- \
- iter = g_sequence_iter_next (iter); \
- cp = g_sequence_get (iter); \
- x_next = cp->timestamp; \
- y_next = g_value_get_##vtype (&cp->value); \
- h[0] = gst_guint64_to_gdouble (x_next - x); \
- \
- for (i = 1; i < n-1; i++) { \
- /* Shuffle x and y values */ \
- y_prev = y; \
- x = x_next; \
- y = y_next; \
- iter = g_sequence_iter_next (iter); \
- cp = g_sequence_get (iter); \
- x_next = cp->timestamp; \
- y_next = g_value_get_##vtype (&cp->value); \
- \
- h[i] = gst_guint64_to_gdouble (x_next - x); \
- o[i] = h[i-1]; \
- p[i] = 2.0 * (h[i-1] + h[i]); \
- q[i] = h[i]; \
- b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
- } \
- p[n-1] = 1.0; \
- \
- /* Use Gauss elimination to set everything below the \
- * diagonal to zero */ \
- for (i = 1; i < n-1; i++) { \
- gdouble a = o[i] / p[i-1]; \
- p[i] -= a * q[i-1]; \
- b[i] -= a * b[i-1]; \
- } \
- \
- /* Solve everything else from bottom to top */ \
- for (i = n-2; i > 0; i--) \
- z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
- \
- /* Save cache next in the GstControlPoint */ \
- \
- iter = g_sequence_get_begin_iter (self->priv->values); \
- for (i = 0; i < n; i++) { \
- cp = g_sequence_get (iter); \
- cp->cache.cubic.h = h[i]; \
- cp->cache.cubic.z = z[i]; \
- iter = g_sequence_iter_next (iter); \
- } \
- \
- /* Free our temporary arrays */ \
- g_free (o); \
- g_free (p); \
- g_free (q); \
- g_free (h); \
- g_free (b); \
- g_free (z); \
-} \
-\
-static inline void \
-_interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlPoint *cp1, g##vtype value1, GstControlPoint *cp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \
-{ \
- if (!self->priv->valid_cache) { \
- _interpolate_cubic_update_cache_##vtype (self); \
- self->priv->valid_cache = TRUE; \
- } \
- \
- if (cp2) { \
- gdouble diff1, diff2; \
- gdouble out; \
- \
- diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \
- diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \
- \
- out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
- out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
- out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
- \
- if (round) \
- *ret = (g##vtype) (out + 0.5); \
- else \
- *ret = (g##vtype) out; \
- } \
- else { \
- *ret = value1; \
- } \
- *ret = CLAMP (*ret, min, max); \
-} \
-\
-static gboolean \
-interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
-{ \
- g##vtype ret, min, max; \
- GSequenceIter *iter; \
- GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
- \
- if (self->priv->nvalues <= 2) \
- return interpolate_linear_get_##vtype (self, timestamp, value); \
- \
- g_mutex_lock (self->lock); \
- \
- min = g_value_get_##vtype (&self->priv->minimum_value); \
- max = g_value_get_##vtype (&self->priv->maximum_value); \
- \
- iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
- if (iter) { \
- cp1 = g_sequence_get (iter); \
- iter = g_sequence_iter_next (iter); \
- } else { \
- cp.timestamp = G_GUINT64_CONSTANT(0); \
- g_value_init (&cp.value, self->priv->type); \
- g_value_copy (&self->priv->default_value, &cp.value); \
- cp1 = &cp; \
- if (G_LIKELY (self->priv->values)) \
- iter = g_sequence_get_begin_iter (self->priv->values); \
- } \
- if (iter && !g_sequence_iter_is_end (iter)) \
- cp2 = g_sequence_get (iter); \
- \
- _interpolate_cubic_get_##vtype (self, cp1, g_value_get_##vtype (&cp1->value), cp2, (cp2 ? g_value_get_##vtype (&cp2->value) : 0), timestamp, min, max, &ret); \
- g_value_set_##vtype (value, ret); \
- g_mutex_unlock (self->lock); \
- if (cp1 == &cp) \
- g_value_unset (&cp.value); \
- return TRUE; \
-} \
-\
-static gboolean \
-interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts = timestamp; \
- GstClockTime next_ts = 0; \
- g##vtype *values = (g##vtype *) value_array->values; \
- GSequenceIter *iter1, *iter2 = NULL; \
- GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
- g##vtype val1 = 0, val2 = 0, min, max; \
- \
- if (self->priv->nvalues <= 2) \
- return interpolate_linear_get_##vtype##_value_array (self, timestamp, value_array); \
- \
- g_mutex_lock (self->lock); \
- \
- cp.timestamp = G_GUINT64_CONSTANT(0); \
- g_value_init (&cp.value, self->priv->type); \
- g_value_copy (&self->priv->default_value, &cp.value); \
- \
- min = g_value_get_##vtype (&self->priv->minimum_value); \
- max = g_value_get_##vtype (&self->priv->maximum_value); \
- \
- for(i = 0; i < value_array->nbsamples; i++) { \
- if (timestamp >= next_ts) { \
- iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
- if (!iter1) { \
- cp1 = &cp; \
- if (G_LIKELY (self->priv->values)) \
- iter2 = g_sequence_get_begin_iter (self->priv->values); \
- else \
- iter2 = NULL; \
- } else { \
- cp1 = g_sequence_get (iter1); \
- iter2 = g_sequence_iter_next (iter1); \
- } \
- \
- if (iter2 && !g_sequence_iter_is_end (iter2)) { \
- cp2 = g_sequence_get (iter2); \
- next_ts = cp2->timestamp; \
- } else { \
- next_ts = GST_CLOCK_TIME_NONE; \
- } \
- val1 = g_value_get_##vtype (&cp1->value); \
- if (cp2) \
- val2 = g_value_get_##vtype (&cp2->value); \
- } \
- _interpolate_cubic_get_##vtype (self, cp1, val1, cp2, val2, timestamp, min, max, values); \
- ts += value_array->sample_interval; \
- values++; \
- } \
- g_mutex_unlock (self->lock); \
- g_value_unset (&cp.value); \
- return TRUE; \
-}
-
-DEFINE_CUBIC_GET (int, TRUE, EMPTY);
-DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
-DEFINE_CUBIC_GET (long, TRUE, EMPTY);
-DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
-DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
-DEFINE_CUBIC_GET (uint64, TRUE, gst_guint64_to_gdouble);
-DEFINE_CUBIC_GET (float, FALSE, EMPTY);
-DEFINE_CUBIC_GET (double, FALSE, EMPTY);
-
-static GstInterpolateMethod interpolate_cubic = {
- (GstControlSourceGetValue) interpolate_cubic_get_int,
- (GstControlSourceGetValueArray) interpolate_cubic_get_int_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_uint,
- (GstControlSourceGetValueArray) interpolate_cubic_get_uint_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_long,
- (GstControlSourceGetValueArray) interpolate_cubic_get_long_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_ulong,
- (GstControlSourceGetValueArray) interpolate_cubic_get_ulong_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_int64,
- (GstControlSourceGetValueArray) interpolate_cubic_get_int64_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_uint64,
- (GstControlSourceGetValueArray) interpolate_cubic_get_uint64_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_float,
- (GstControlSourceGetValueArray) interpolate_cubic_get_float_value_array,
- (GstControlSourceGetValue) interpolate_cubic_get_double,
- (GstControlSourceGetValueArray) interpolate_cubic_get_double_value_array,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL,
- (GstControlSourceGetValue) NULL,
- (GstControlSourceGetValueArray) NULL
-};
-
-/* register all interpolation methods */
-GstInterpolateMethod *priv_gst_interpolation_methods[] = {
- &interpolate_none,
- &interpolate_trigger,
- &interpolate_linear,
- &interpolate_cubic,
- &interpolate_cubic
-};
-
-guint priv_gst_num_interpolation_methods =
-G_N_ELEMENTS (priv_gst_interpolation_methods);