📄 gstinterpolation.c
字号:
{ gint i; GstClockTime ts = timestamp; gint *values = (gint *) value_array->values; GValue *ret; g_mutex_lock (self->lock); for (i = 0; i < value_array->nbsamples; i++) { ret = _interpolate_trigger_get (self, timestamp); if (!ret) { g_mutex_unlock (self->lock); return FALSE; } *values = g_value_get_boolean (ret); ts += value_array->sample_interval; values++; } g_mutex_unlock (self->lock); return TRUE;}static gbooleaninterpolate_trigger_get_enum_value_array (GstInterpolationControlSource * self, GstClockTime timestamp, GstValueArray * value_array){ gint i; GstClockTime ts = timestamp; gint *values = (gint *) value_array->values; GValue *ret; g_mutex_lock (self->lock); for (i = 0; i < value_array->nbsamples; i++) { ret = _interpolate_trigger_get (self, timestamp); if (!ret) { g_mutex_unlock (self->lock); return FALSE; } *values = g_value_get_enum (ret); ts += value_array->sample_interval; values++; } g_mutex_unlock (self->lock); return TRUE;}static gbooleaninterpolate_trigger_get_string_value_array (GstInterpolationControlSource * self, GstClockTime timestamp, GstValueArray * value_array){ gint i; GstClockTime ts = timestamp; gchar **values = (gchar **) value_array->values; GValue *ret; g_mutex_lock (self->lock); for (i = 0; i < value_array->nbsamples; i++) { ret = _interpolate_trigger_get (self, timestamp); if (!ret) { g_mutex_unlock (self->lock); return FALSE; } *values = (gchar *) g_value_get_string (ret); ts += value_array->sample_interval; values++; } g_mutex_unlock (self->lock); return TRUE;}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, (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array, (GstControlSourceGetValue) interpolate_trigger_get, (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array, (GstControlSourceGetValue) interpolate_trigger_get, (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array};/* linear interpolation *//* smoothes inbetween values */#define DEFINE_LINEAR_GET(type,round,convert) \static inline gboolean \_interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \{ \ GList *node; \ \ if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ GstControlPoint *cp1, *cp2; \ \ cp1 = node->data; \ if ((node = g_list_next (node))) { \ gdouble slope; \ g##type value1,value2; \ \ cp2 = node->data; \ \ value1 = g_value_get_##type (&cp1->value); \ value2 = g_value_get_##type (&cp2->value); \ slope = (gdouble) convert (value2 - value1) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \ \ if (round) \ *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \ else \ *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \ } \ else { \ *ret = g_value_get_##type (&cp1->value); \ } \ } else { \ GValue *first = gst_interpolation_control_source_get_first_value (self); \ if (!first) \ return FALSE; \ *ret = g_value_get_##type (first); \ } \ *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \ return TRUE; \} \\static gboolean \interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \{ \ g##type ret; \ g_mutex_lock (self->lock); \ if (_interpolate_linear_get_##type (self, timestamp, &ret)) { \ g_value_set_##type (value, ret); \ g_mutex_unlock (self->lock); \ return TRUE; \ } \ g_mutex_unlock (self->lock); \ return FALSE; \} \\static gboolean \interpolate_linear_get_##type##_value_array (GstInterpolationControlSource *self, \ GstClockTime timestamp, GstValueArray * value_array) \{ \ gint i; \ GstClockTime ts = timestamp; \ g##type *values = (g##type *) value_array->values; \ \ g_mutex_lock (self->lock); \ for(i = 0; i < value_array->nbsamples; i++) { \ if (! _interpolate_linear_get_##type (self, ts, values)) { \ g_mutex_unlock (self->lock); \ return FALSE; \ } \ ts += value_array->sample_interval; \ values++; \ } \ g_mutex_unlock (self->lock); \ 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_util_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(type,round, convert) \static void \_interpolate_cubic_update_cache_##type (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); \ \ GList *node; \ GstControlPoint *cp; \ GstClockTime x_prev, x, x_next; \ g##type y_prev, y, y_next; \ \ /* Fill linear system of equations */ \ node = self->priv->values; \ cp = node->data; \ x = cp->timestamp; \ y = g_value_get_##type (&cp->value); \ \ p[0] = 1.0; \ \ node = node->next; \ cp = node->data; \ x_next = cp->timestamp; \ y_next = g_value_get_##type (&cp->value); \ h[0] = gst_util_guint64_to_gdouble (x_next - x); \ \ for (i = 1; i < n-1; i++) { \ /* Shuffle x and y values */ \ x_prev = x; \ y_prev = y; \ x = x_next; \ y = y_next; \ node = node->next; \ cp = node->data; \ x_next = cp->timestamp; \ y_next = g_value_get_##type (&cp->value); \ \ h[i] = gst_util_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 */ \ \ node = self->priv->values; \ for (i = 0; i < n; i++) { \ cp = node->data; \ cp->cache.cubic.h = h[i]; \ cp->cache.cubic.z = z[i]; \ node = node->next; \ } \ \ /* Free our temporary arrays */ \ g_free (o); \ g_free (p); \ g_free (q); \ g_free (h); \ g_free (b); \ g_free (z); \} \\static inline gboolean \_interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \{ \ GList *node; \ \ if (self->priv->nvalues <= 2) \ return _interpolate_linear_get_##type (self, timestamp, ret); \ \ if (!self->priv->valid_cache) { \ _interpolate_cubic_update_cache_##type (self); \ self->priv->valid_cache = TRUE; \ } \ \ if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ GstControlPoint *cp1, *cp2; \ \ cp1 = node->data; \ if ((node = g_list_next (node))) { \ gdouble diff1, diff2; \ g##type value1,value2; \ gdouble out; \ \ cp2 = node->data; \ \ value1 = g_value_get_##type (&cp1->value); \ value2 = g_value_get_##type (&cp2->value); \ \ 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##type) (out + 0.5); \ else \ *ret = (g##type) out; \ } \ else { \ *ret = g_value_get_##type (&cp1->value); \ } \ } else { \ GValue *first = gst_interpolation_control_source_get_first_value (self); \ if (!first) \ return FALSE; \ *ret = g_value_get_##type (first); \ } \ *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \ return TRUE; \} \\static gboolean \interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \{ \ g##type ret; \ g_mutex_lock (self->lock); \ if (_interpolate_cubic_get_##type (self, timestamp, &ret)) { \ g_value_set_##type (value, ret); \ g_mutex_unlock (self->lock); \ return TRUE; \ } \ g_mutex_unlock (self->lock); \ return FALSE; \} \\static gboolean \interpolate_cubic_get_##type##_value_array (GstInterpolationControlSource *self, \ GstClockTime timestamp, GstValueArray * value_array) \{ \ gint i; \ GstClockTime ts = timestamp; \ g##type *values = (g##type *) value_array->values; \ \ g_mutex_lock (self->lock); \ for(i = 0; i < value_array->nbsamples; i++) { \ if (! _interpolate_cubic_get_##type (self, ts, values)) { \ g_mutex_unlock (self->lock); \ return FALSE; \ } \ ts += value_array->sample_interval; \ values++; \ } \ g_mutex_unlock (self->lock); \ 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_util_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 *interpolation_methods[] = { &interpolate_none, &interpolate_trigger, &interpolate_linear, &interpolate_cubic, &interpolate_cubic};guint num_interpolation_methods = G_N_ELEMENTS (interpolation_methods);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -