mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
libs/gst/controller/: Factor out the 'set' logic into gst_controller_set_unlocked for the gst_controller_set and gst_...
Original commit message from CVS: * 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.
This commit is contained in:
parent
ce5a853516
commit
c478fb4813
5 changed files with 409 additions and 82 deletions
28
ChangeLog
28
ChangeLog
|
@ -1,3 +1,31 @@
|
|||
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):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* 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
|
||||
*
|
||||
|
@ -240,21 +241,40 @@ gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
|
|||
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
|
||||
|
@ -374,13 +394,14 @@ gst_controlled_property_new (GObject * object, const gchar * name)
|
|||
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 =
|
||||
|
@ -718,6 +739,42 @@ gst_controller_remove_properties (GstController * self, ...)
|
|||
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
|
||||
|
@ -743,30 +800,7 @@ gst_controller_set (GstController * self, gchar * property_name,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -792,7 +826,6 @@ gst_controller_set_from_list (GstController * self, gchar * property_name,
|
|||
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);
|
||||
|
@ -801,22 +834,15 @@ gst_controller_set_from_list (GstController * self, gchar * property_name,
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -854,10 +880,20 @@ gst_controller_unset (GstController * self, gchar * property_name,
|
|||
/* 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;
|
||||
}
|
||||
}
|
||||
|
@ -893,6 +929,12 @@ gst_controller_unset_all (GstController * self, gchar * property_name)
|
|||
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);
|
||||
|
@ -1146,8 +1188,8 @@ gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
|
|||
*
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -81,6 +81,14 @@ typedef struct _GstControlPoint
|
|||
|
||||
/* internal fields */
|
||||
|
||||
/* Caches for the interpolators */
|
||||
union {
|
||||
struct {
|
||||
gdouble h;
|
||||
gdouble z;
|
||||
} cubic;
|
||||
} cache;
|
||||
|
||||
} GstControlPoint;
|
||||
|
||||
/**
|
||||
|
@ -106,10 +114,9 @@ typedef struct _GstControlledProperty
|
|||
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))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* 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
|
||||
*
|
||||
|
@ -284,17 +285,16 @@ _interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime times
|
|||
\
|
||||
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)); \
|
||||
|
@ -360,13 +360,205 @@ static GstInterpolateMethod interpolate_linear = {
|
|||
|
||||
/* 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);
|
||||
|
|
|
@ -524,7 +524,8 @@ GST_START_TEST (controller_interpolate_none)
|
|||
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);
|
||||
|
@ -567,8 +568,8 @@ GST_START_TEST (controller_interpolate_trigger)
|
|||
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);
|
||||
|
@ -612,7 +613,8 @@ GST_START_TEST (controller_interpolate_linear)
|
|||
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);
|
||||
|
@ -638,6 +640,63 @@ GST_START_TEST (controller_interpolate_linear)
|
|||
|
||||
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)
|
||||
|
@ -653,16 +712,9 @@ 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);
|
||||
|
@ -687,7 +739,8 @@ GST_START_TEST (controller_unset)
|
|||
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);
|
||||
|
@ -743,7 +796,8 @@ GST_START_TEST (controller_unset_all)
|
|||
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);
|
||||
|
@ -792,7 +846,8 @@ GST_START_TEST (controller_live)
|
|||
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);
|
||||
|
@ -866,7 +921,8 @@ GST_START_TEST (controller_misc)
|
|||
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);
|
||||
|
@ -876,7 +932,7 @@ GST_START_TEST (controller_misc)
|
|||
|
||||
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;
|
||||
|
@ -989,7 +1045,8 @@ GST_START_TEST (controller_interpolate_linear_value_array)
|
|||
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);
|
||||
|
@ -1041,6 +1098,7 @@ gst_controller_suite (void)
|
|||
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);
|
||||
|
|
Loading…
Reference in a new issue