+2007-06-06 Sebastian Dröge <slomo@circular-chaos.org>
+
+ * libs/gst/controller/gstcontroller.c:
+ (gst_controlled_property_set_interpolation_mode),
+ (gst_controlled_property_prepend_default),
+ (gst_controlled_property_new), (gst_controller_set_unlocked),
+ (gst_controller_set), (gst_controller_set_from_list),
+ (gst_controller_unset), (gst_controller_unset_all):
+ * libs/gst/controller/gstcontrollerprivate.h:
+ * libs/gst/controller/gstinterpolation.c:
+ Factor out the 'set' logic into gst_controller_set_unlocked for the
+ gst_controller_set and gst_controller_set_from_list functions.
+
+ To make life of the interpolators easier always add a control point
+ at timestamp zero with the default value.
+
+ In the linear interpolator make things more obvious by better variable
+ naming (slope).
+
+ Implement cubic interpolation mode (by using a natural cubic spline)
+ and map the quadratic interpolation mode to this too (as quadratic
+ doesn't make much sense, see discussion on the list).
+
+ * tests/check/libs/controller.c: (GST_START_TEST),
+ (gst_controller_suite):
+ Add unit test for the cubic interpolation mode and check everywhere
+ if the interpolation mode could be set as expected.
+
2007-06-06 Tim-Philipp Müller <tim at centricular dot net>
* gst/gstparamspecs.c: (gst_param_spec_fraction_get_type):
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* gstcontroller.c: dynamic parameter control subsystem
*
self->get = NULL;
self->get_value_array = NULL;
}
- if (!self->get) { /* || !self->get_value_array) */
+ if (!self->get || !self->get_value_array) {
GST_WARNING ("incomplete implementation for type %lu/%lu:'%s'/'%s'",
self->type, self->base,
g_type_name (self->type), g_type_name (self->base));
res = FALSE;
}
+ if (mode == GST_INTERPOLATE_QUADRATIC) {
+ GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
+ "interpolation mode");
+ }
} else {
/* TODO shouldn't this also get a GstInterpolateMethod *user_method
for the case mode==GST_INTERPOLATE_USER
*/
res = FALSE;
}
+
+ self->valid_cache = FALSE;
+
return (res);
}
+static void
+gst_controlled_property_prepend_default (GstControlledProperty * prop)
+{
+ GstControlPoint *cp = g_new0 (GstControlPoint, 1);
+
+ cp->timestamp = 0;
+ g_value_init (&cp->value, prop->type);
+ g_value_copy (&prop->default_value, &cp->value);
+ prop->values = g_list_prepend (prop->values, cp);
+ prop->nvalues++;
+}
+
/*
* gst_controlled_property_new:
* @object: for which object the controlled property should be set up
GST_WARNING ("incomplete implementation for paramspec type '%s'",
G_PARAM_SPEC_TYPE_NAME (pspec));
}
- /* TODO what about adding a control point with timestamp=0 and value=default
- * a bit easier for interpolators, example:
- * first timestamp is at 5
- * requested value if for timestamp=3
- * LINEAR and Co. would need to interpolate from default value to value
- * at timestamp 5
- */
+
+ prop->valid_cache = FALSE;
+ prop->nvalues = 0;
+
+ /* Add a control point at timestamp 0 with the default value
+ * to make the life of interpolators easier. */
+ gst_controlled_property_prepend_default (prop);
+
signal_name = g_alloca (8 + 1 + strlen (name));
g_sprintf (signal_name, "notify::%s", name);
prop->notify_handler_id =
return (res);
}
+static gboolean
+gst_controller_set_unlocked (GstController * self, GstControlledProperty * prop,
+ GstClockTime timestamp, GValue * value)
+{
+ gboolean res = FALSE;
+
+ if (G_VALUE_TYPE (value) == prop->type) {
+ GstControlPoint *cp;
+ GList *node;
+
+ /* check if a control point for the timestamp already exists */
+ if ((node = g_list_find_custom (prop->values, ×tamp,
+ gst_control_point_find))) {
+ cp = node->data;
+ g_value_reset (&cp->value);
+ g_value_copy (value, &cp->value);
+ } else {
+ /* create a new GstControlPoint */
+ cp = g_new0 (GstControlPoint, 1);
+ cp->timestamp = timestamp;
+ g_value_init (&cp->value, prop->type);
+ g_value_copy (value, &cp->value);
+ /* and sort it into the prop->values list */
+ prop->values =
+ g_list_insert_sorted (prop->values, cp, gst_control_point_compare);
+ prop->nvalues++;
+ }
+ prop->valid_cache = FALSE;
+ res = TRUE;
+ } else {
+ GST_WARNING ("incompatible value type for property '%s'", prop->name);
+ }
+
+ return res;
+}
+
/**
* gst_controller_set:
* @self: the controller object which handles the properties
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
- if (G_VALUE_TYPE (value) == prop->type) {
- GstControlPoint *cp;
- GList *node;
-
- /* check if a control point for the timestamp already exists */
- if ((node = g_list_find_custom (prop->values, ×tamp,
- gst_control_point_find))) {
- cp = node->data;
- g_value_reset (&cp->value);
- g_value_copy (value, &cp->value);
- } else {
- /* create a new GstControlPoint */
- cp = g_new0 (GstControlPoint, 1);
- cp->timestamp = timestamp;
- g_value_init (&cp->value, prop->type);
- g_value_copy (value, &cp->value);
- /* and sort it into the prop->values list */
- prop->values =
- g_list_insert_sorted (prop->values, cp, gst_control_point_compare);
- }
- res = TRUE;
- } else {
- GST_WARNING ("incompatible value type for property '%s'", prop->name);
- }
+ res = gst_controller_set_unlocked (self, prop, timestamp, value);
}
g_mutex_unlock (self->lock);
GstControlledProperty *prop;
GSList *node;
GstTimedValue *tv;
- GstControlPoint *cp;
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
g_return_val_if_fail (property_name, FALSE);
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
for (node = timedvalues; node; node = g_slist_next (node)) {
tv = node->data;
- if (G_VALUE_TYPE (&tv->value) == prop->type) {
- if (GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
- cp = g_new0 (GstControlPoint, 1);
- cp->timestamp = tv->timestamp;
- g_value_init (&cp->value, prop->type);
- g_value_copy (&tv->value, &cp->value);
- prop->values =
- g_list_insert_sorted (prop->values, cp,
- gst_control_point_compare);
- res = TRUE;
- } else {
- g_warning ("GstTimedValued with invalid timestamp passed to %s "
- "for property '%s'", GST_FUNCTION, property_name);
- }
+ if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
+ GST_WARNING ("GstTimedValued with invalid timestamp passed to %s "
+ "for property '%s'", GST_FUNCTION, property_name);
+ } else if (!G_IS_VALUE (&tv->value)) {
+ GST_WARNING ("GstTimedValued with invalid value passed to %s "
+ "for property '%s'", GST_FUNCTION, property_name);
} else {
- GST_WARNING ("incompatible value type for property '%s'", prop->name);
+ res =
+ gst_controller_set_unlocked (self, prop, tv->timestamp, &tv->value);
}
}
}
/* check if a control point for the timestamp exists */
if ((node = g_list_find_custom (prop->values, ×tamp,
gst_control_point_find))) {
- if (node == prop->last_requested_value)
- prop->last_requested_value = NULL;
- gst_control_point_free (node->data); /* free GstControlPoint */
- prop->values = g_list_delete_link (prop->values, node);
+ GstControlPoint *cp = node->data;
+
+ if (cp->timestamp == 0) {
+ /* Restore the default node */
+ g_value_reset (&cp->value);
+ g_value_copy (&prop->default_value, &cp->value);
+ } else {
+ if (node == prop->last_requested_value)
+ prop->last_requested_value = NULL;
+ gst_control_point_free (node->data); /* free GstControlPoint */
+ prop->values = g_list_delete_link (prop->values, node);
+ prop->nvalues--;
+ }
+ prop->valid_cache = FALSE;
res = TRUE;
}
}
g_list_free (prop->values);
prop->last_requested_value = NULL;
prop->values = NULL;
+ prop->nvalues = 0;
+ prop->valid_cache = FALSE;
+
+ /* Insert the default control point again */
+ gst_controlled_property_prepend_default (prop);
+
res = TRUE;
}
g_mutex_unlock (self->lock);
*
* Sets the given interpolation mode on the given property.
*
- * <note><para>Quadratic, cubic and user interpolation is not yet available.
- * </para></note>
+ * <note><para>User interpolation is not yet available and quadratic interpolation
+ * is deprecated and maps to cubic interpolation.</para></note>
*
* Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
*/
/* internal fields */
+ /* Caches for the interpolators */
+ union {
+ struct {
+ gdouble h;
+ gdouble z;
+ } cubic;
+ } cache;
+
} GstControlPoint;
/**
InterpolateGetValueArray get_value_array;
GList *values; /* List of GstControlPoint */
+ gint nvalues; /* Number of control points */
GList *last_requested_value; /* last search result, can be used for incremental searches */
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
+ gboolean valid_cache;
} GstControlledProperty;
#define GST_CONTROLLED_PROPERTY(obj) ((GstControlledProperty *)(obj))
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* gstinterpolation.c: Interpolation methods for dynamic properties
*
\
cp1 = node->data; \
if ((node = g_list_next (node))) { \
- gdouble timediff,valuediff; \
+ gdouble slope; \
g##type value1,value2; \
\
cp2 = node->data; \
\
- timediff = gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
value1 = g_value_get_##type (&cp1->value); \
value2 = g_value_get_##type (&cp2->value); \
- valuediff = (gdouble) (value2 - value1); \
+ slope = (gdouble) (value2 - value1) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
\
- return ((g##type) (value1 + valuediff * (gst_guint64_to_gdouble (timestamp - cp1->timestamp) / timediff))); \
+ return ((g##type) (value1 + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope)); \
} \
else { \
return (g_value_get_##type (&cp1->value)); \
/* 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) \
+static void \
+_interpolate_cubic_update_cache_##type (GstControlledProperty *prop) \
+{ \
+ gint i, n = prop->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 = prop->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] = 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] = x_next - x; \
+ o[i] = h[i-1]; \
+ p[i] = 2.0 * (h[i-1] + h[i]); \
+ q[i] = h[i]; \
+ b[i] = (y_next - y) / h[i] - (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 = prop->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 g##type \
+_interpolate_cubic_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+{ \
+ GList *node; \
+ \
+ if (prop->nvalues <= 2) \
+ return _interpolate_linear_get_##type (prop, timestamp); \
+ \
+ if (!prop->valid_cache) { \
+ _interpolate_cubic_update_cache_##type (prop); \
+ prop->valid_cache = TRUE; \
+ } \
+ \
+ if ((node = gst_controlled_property_find_control_point_node (prop, timestamp))) { \
+ GstControlPoint *cp1, *cp2; \
+ \
+ cp1 = node->data; \
+ if ((node = g_list_next (node))) { \
+ gdouble diff1, diff2; \
+ g##type value1,value2; \
+ gdouble ret; \
+ \
+ 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); \
+ \
+ ret = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
+ ret += (value2 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
+ ret += (value1 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
+ \
+ return (g##type) ret; \
+ } \
+ else { \
+ return (g_value_get_##type (&cp1->value)); \
+ } \
+ } \
+ return (g_value_get_##type (&prop->default_value)); \
+} \
+\
+static GValue * \
+interpolate_cubic_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+{ \
+ g_value_set_##type (&prop->result_value,_interpolate_cubic_get_##type (prop,timestamp)); \
+ return (&prop->result_value); \
+} \
+\
+static gboolean \
+interpolate_cubic_get_##type##_value_array (GstControlledProperty * prop, \
+ GstClockTime timestamp, GstValueArray * value_array) \
+{ \
+ gint i; \
+ GstClockTime ts = timestamp; \
+ g##type *values = (g##type *) value_array->values; \
+ \
+ for(i = 0; i < value_array->nbsamples; i++) { \
+ *values = _interpolate_cubic_get_##type (prop, ts); \
+ ts += value_array->sample_interval; \
+ values++; \
+ } \
+ return (TRUE); \
+}
+
+DEFINE_CUBIC_GET (int);
+
+DEFINE_CUBIC_GET (uint);
+DEFINE_CUBIC_GET (long);
+
+DEFINE_CUBIC_GET (ulong);
+DEFINE_CUBIC_GET (float);
+DEFINE_CUBIC_GET (double);
+
+static GstInterpolateMethod interpolate_cubic = {
+ interpolate_cubic_get_int,
+ interpolate_cubic_get_int_value_array,
+ interpolate_cubic_get_uint,
+ interpolate_cubic_get_uint_value_array,
+ interpolate_cubic_get_long,
+ interpolate_cubic_get_long_value_array,
+ interpolate_cubic_get_ulong,
+ interpolate_cubic_get_ulong_value_array,
+ interpolate_cubic_get_float,
+ interpolate_cubic_get_float_value_array,
+ interpolate_cubic_get_double,
+ interpolate_cubic_get_double_value_array,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
/* register all interpolation methods */
GstInterpolateMethod *interpolation_methods[] = {
&interpolate_none,
&interpolate_trigger,
&interpolate_linear,
- NULL,
- NULL
+ &interpolate_cubic,
+ &interpolate_cubic
};
guint num_interpolation_methods = G_N_ELEMENTS (interpolation_methods);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_NONE);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_NONE));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong",
- GST_INTERPOLATE_TRIGGER);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_TRIGGER));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_LINEAR);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_LINEAR));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
GST_END_TEST;
+/* test timed value handling with cubic interpolation */
+GST_START_TEST (controller_interpolate_cubic)
+{
+ GstController *ctrl;
+ GstElement *elem;
+ gboolean res;
+ GValue val_double = { 0, };
+
+ gst_controller_init (NULL, NULL);
+
+ elem = gst_element_factory_make ("testmonosource", "test_source");
+
+ /* that property should exist and should be controllable */
+ ctrl = gst_controller_new (G_OBJECT (elem), "double", NULL);
+ fail_unless (ctrl != NULL, NULL);
+
+ /* set interpolation mode */
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "double",
+ GST_INTERPOLATE_CUBIC));
+
+ /* set control values */
+ g_value_init (&val_double, G_TYPE_DOUBLE);
+ g_value_set_double (&val_double, 0.0);
+ res = gst_controller_set (ctrl, "double", 0 * GST_SECOND, &val_double);
+ fail_unless (res, NULL);
+ g_value_set_double (&val_double, 5.0);
+ res = gst_controller_set (ctrl, "double", 1 * GST_SECOND, &val_double);
+ fail_unless (res, NULL);
+ g_value_set_double (&val_double, 2.0);
+ res = gst_controller_set (ctrl, "double", 2 * GST_SECOND, &val_double);
+ fail_unless (res, NULL);
+ g_value_set_double (&val_double, 8.0);
+ res = gst_controller_set (ctrl, "double", 4 * GST_SECOND, &val_double);
+ fail_unless (res, NULL);
+
+ /* now pull in values for some timestamps */
+ gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+ gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 5.0, NULL);
+ gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 2.0, NULL);
+ gst_controller_sync_values (ctrl, 3 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double > 2.0 &&
+ GST_TEST_MONO_SOURCE (elem)->val_double < 8.0, NULL);
+ gst_controller_sync_values (ctrl, 4 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 8.0, NULL);
+ gst_controller_sync_values (ctrl, 5 * GST_SECOND);
+ fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 8.0, NULL);
+
+ GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
+ g_object_unref (ctrl);
+ gst_object_unref (elem);
+}
+
+GST_END_TEST;
+
/* make sure we don't crash when someone sets an unsupported interpolation
* mode */
GST_START_TEST (controller_interpolate_unimplemented)
ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
fail_unless (ctrl != NULL, NULL);
- /* set unsupported interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_CUBIC);
-
- /* set another unsupported interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong",
- GST_INTERPOLATE_QUADRATIC);
-
/* set completely bogus interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong",
- (GstInterpolateMode) 93871);
+ fail_if (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ (GstInterpolateMode) 93871));
g_object_unref (ctrl);
gst_object_unref (elem);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_NONE);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_NONE));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_NONE);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_NONE));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_LINEAR);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_LINEAR));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_LINEAR);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_LINEAR));
/* set control value */
tval = g_new0 (GstTimedValue, 1);
list = g_slist_append (list, tval);
- ASSERT_WARNING (fail_if (gst_controller_set_from_list (ctrl, "ulong", list)));
+ fail_if (gst_controller_set_from_list (ctrl, "ulong", list));
/* try again with a valid stamp, should work now */
tval->timestamp = 0;
fail_unless (ctrl != NULL, NULL);
/* set interpolation mode */
- gst_controller_set_interpolation_mode (ctrl, "ulong", GST_INTERPOLATE_LINEAR);
+ fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+ GST_INTERPOLATE_LINEAR));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
tcase_add_test (tc, controller_interpolate_none);
tcase_add_test (tc, controller_interpolate_trigger);
tcase_add_test (tc, controller_interpolate_linear);
+ tcase_add_test (tc, controller_interpolate_cubic);
tcase_add_test (tc, controller_interpolate_unimplemented);
tcase_add_test (tc, controller_unset);
tcase_add_test (tc, controller_unset_all);