controlsources: refactor interpolation control source

Move most of the code to a GstTimedValueControlSource. Split out the trigger
'interpolation mode' to a new control source class. Move tests and examples to
new api. Update docs.

Fixes #610338
This commit is contained in:
Stefan Sauer 2011-12-19 11:13:45 +01:00
parent 9c3c0fb251
commit 2c7a8b924a
17 changed files with 1653 additions and 1084 deletions

View file

@ -55,8 +55,10 @@
element properties over time.
</para>
<xi:include href="xml/gsttimedvaluecontrolsource.xml" />
<xi:include href="xml/gstinterpolationcontrolsource.xml" />
<xi:include href="xml/gstlfocontrolsource.xml" />
<xi:include href="xml/gsttriggercontrolsource.xml" />
</chapter>
<chapter id="gstreamer-dataprotocol">

View file

@ -53,22 +53,22 @@ gst_dp_version_get_type
# control source classes
<SECTION>
<FILE>gstinterpolationcontrolsource</FILE>
<TITLE>GstInterpolationControlSource</TITLE>
<INCLUDE>libs/controller/gstinterpolationcontrolsource.h</INCLUDE>
GstInterpolationControlSource
GstInterpolateMode
gst_interpolation_control_source_new
gst_interpolation_control_source_set
gst_interpolation_control_source_set_from_list
gst_interpolation_control_source_set_interpolation_mode
gst_interpolation_control_source_get_all
gst_interpolation_control_source_unset
gst_interpolation_control_source_unset_all
gst_interpolation_control_source_get_count
<FILE>gsttimedvaluecontrolsource</FILE>
<TITLE>GstTimedValueControlSource</TITLE>
<INCLUDE>libs/controller/gsttimedvaluecontrolsource.h</INCLUDE>
GstTimedValueControlSource
gst_timed_value_control_source_find_control_point_iter
gst_timed_value_control_source_set
gst_timed_value_control_source_set_from_list
gst_timed_value_control_source_get_all
gst_timed_value_control_source_unset
gst_timed_value_control_source_unset_all
gst_timed_value_control_source_get_count
gst_timed_value_control_source_get_base_value_type
gst_timed_value_control_invalidate_cache
<SUBSECTION Standard>
GstInterpolationControlSourceClass
GstInterpolationControlSourcePrivate
GstTimedValueControlSourceClass
GstTimedValueControlSourcePrivate
GST_INTERPOLATION_CONTROL_SOURCE
GST_IS_INTERPOLATION_CONTROL_SOURCE
GST_INTERPOLATION_CONTROL_SOURCE_CLASS
@ -76,6 +76,27 @@ GST_IS_INTERPOLATION_CONTROL_SOURCE_CLASS
GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS
GST_TYPE_INTERPOLATION_CONTROL_SOURCE
<SUBSECTION Private>
gst_timed_value_control_source_get_type
</SECTION>
<SECTION>
<FILE>gstinterpolationcontrolsource</FILE>
<TITLE>GstInterpolationControlSource</TITLE>
<INCLUDE>libs/controller/gstinterpolationcontrolsource.h</INCLUDE>
GstInterpolationControlSource
GstInterpolateMode
gst_interpolation_control_source_new
gst_interpolation_control_source_set_interpolation_mode
<SUBSECTION Standard>
GstInterpolationControlSourceClass
GstInterpolationControlSourcePrivate
GST_TIMED_VALUE_CONTROL_SOURCE
GST_IS_TIMED_VALUE_CONTROL_SOURCE
GST_TIMED_VALUE_CONTROL_SOURCE_CLASS
GST_IS_TIMED_VALUE_CONTROL_SOURCE_CLASS
GST_TIMED_VALUE_CONTROL_SOURCE_GET_CLASS
GST_TYPE_TIMED_VALUE_CONTROL_SOURCE
<SUBSECTION Private>
gst_interpolation_control_source_get_type
</SECTION>
@ -101,6 +122,25 @@ gst_lfo_control_source_get_type
gst_lfo_waveform_get_type
</SECTION>
<SECTION>
<FILE>gsttriggercontrolsource</FILE>
<TITLE>GstTriggerControlSource</TITLE>
<INCLUDE>libs/controller/gsttriggercontrolsource.h</INCLUDE>
GstTriggerControlSource
gst_trigger_control_source_new
<SUBSECTION Standard>
GstTriggerControlSourceClass
GstTriggerControlSourcePrivate
GST_TRIGGER_CONTROL_SOURCE
GST_IS_TRIGGER_CONTROL_SOURCE
GST_TRIGGER_CONTROL_SOURCE_CLASS
GST_IS_TRIGGER_CONTROL_SOURCE_CLASS
GST_TRIGGER_CONTROL_SOURCE_GET_CLASS
GST_TYPE_TRIGGER_CONTROL_SOURCE
<SUBSECTION Private>
gst_trigger_control_source_get_type
</SECTION>
# base classes
<SECTION>

View file

@ -18,11 +18,15 @@ gst_push_src_get_type
% controller
#include <gst/controller/gsttimedvaluecontrolsource.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstlfocontrolsource.h>
#include <gst/controller/gsttriggercontrolsource.h>
gst_timed_value_control_source_get_type
gst_interpolation_control_source_get_type
gst_lfo_control_source_get_type
gst_trigger_control_source_get_type
% net

View file

@ -447,4 +447,8 @@ The 0.11 porting guide
properties fetch the value array. Also GstValueArray is gone. The fields of
GstValueArray are now passed directly to gst_object_get_value_array as
arguments.
GstInterpolationControlSource has been split. There is a new
GstTimedValueControlSource baseclass and 2 sub classes:
GstInterpolationControlSource and GstTriggerControlSource. The API for setting
and getting the timestamps is in GstTimedValueControlSource.

View file

@ -121,8 +121,8 @@
* </para></listitem>
* <listitem><para>
* Set the control values
* gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
* gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
* gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,0 * GST_SECOND, value1);
* gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,1 * GST_SECOND, value2);
* </para></listitem>
* <listitem><para>
* start your pipeline

View file

@ -2,7 +2,9 @@ lib_LTLIBRARIES = libgstcontroller-@GST_MAJORMINOR@.la
libgstcontroller_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller
libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \
gsttimedvaluecontrolsource.h \
gstinterpolationcontrolsource.h \
gsttriggercontrolsource.h \
gstlfocontrolsource.h
noinst_HEADERS = \
@ -10,8 +12,10 @@ noinst_HEADERS = \
gstlfocontrolsourceprivate.h
libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \
gsttimedvaluecontrolsource.c \
gstinterpolation.c \
gstinterpolationcontrolsource.c \
gsttriggercontrolsource.c \
gstlfocontrolsource.c
libgstcontroller_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)

View file

@ -33,55 +33,10 @@ 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)
_interpolate_none_get (GstTimedValueControlSource * self, GSequenceIter * iter)
{
const GValue *ret;
@ -90,14 +45,14 @@ _interpolate_none_get (GstInterpolationControlSource * self,
ret = &cp->value;
} else {
ret = &self->priv->default_value;
ret = &self->default_value;
}
return ret;
}
#define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \
static inline const GValue * \
_interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter) \
_interpolate_none_get_##type (GstTimedValueControlSource *self, GSequenceIter *iter) \
{ \
const GValue *ret; \
\
@ -105,28 +60,28 @@ _interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter
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; \
if (g_value_get_##type (&self->minimum_value) > ret_val) \
ret = &self->minimum_value; \
else if (g_value_get_##type (&self->maximum_value) < ret_val) \
ret = &self->maximum_value; \
else \
ret = &cp->value; \
} else { \
ret = &self->priv->default_value; \
ret = &self->default_value; \
} \
return ret; \
}
#define DEFINE_NONE_GET(type,ctype,get_func) \
static gboolean \
interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
interpolate_none_get_##type (GstTimedValueControlSource *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); \
iter = gst_timed_value_control_source_find_control_point_iter (self, timestamp); \
ret = get_func (self, iter); \
g_value_copy (ret, value); \
g_mutex_unlock (self->lock); \
@ -134,7 +89,7 @@ interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime t
} \
\
static gboolean \
interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \
interpolate_none_get_##type##_value_array (GstTimedValueControlSource *self, \
GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \
guint i; \
@ -148,10 +103,10 @@ interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self,
g_mutex_lock (self->lock); \
for(i = 0; i < n_values; i++) { \
if (!ret_val || ts >= next_ts) { \
iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
iter1 = gst_timed_value_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); \
if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->values); \
else \
iter2 = NULL; \
} else { \
@ -224,178 +179,6 @@ static GstInterpolateMethod interpolate_none = {
(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, GstClockTime interval, guint n_values, gpointer _values) \
{ \
guint i; \
GstClockTime ts = timestamp; \
GstClockTime next_ts = 0; \
ctype *values = (ctype *) _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 < n_values; 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 += 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 */
@ -419,7 +202,7 @@ _interpolate_linear_internal_##vtype (GstClockTime timestamp1, g##vtype value1,
} \
\
static gboolean \
interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
interpolate_linear_get_##vtype (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \
{ \
g##vtype ret, min, max; \
GSequenceIter *iter; \
@ -427,20 +210,20 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim
\
g_mutex_lock (self->lock); \
\
min = g_value_get_##vtype (&self->priv->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_value); \
min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->maximum_value); \
\
iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
iter = gst_timed_value_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); \
g_value_init (&cp.value, self->type); \
g_value_copy (&self->default_value, &cp.value); \
cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \
iter = g_sequence_get_begin_iter (self->priv->values); \
if (G_LIKELY (self->values)) \
iter = g_sequence_get_begin_iter (self->values); \
} \
if (iter && !g_sequence_iter_is_end (iter)) \
cp2 = g_sequence_get (iter); \
@ -454,7 +237,7 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim
} \
\
static gboolean \
interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \
interpolate_linear_get_##vtype##_value_array (GstTimedValueControlSource *self, \
GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \
guint i; \
@ -468,19 +251,19 @@ interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *sel
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); \
g_value_init (&cp.value, self->type); \
g_value_copy (&self->default_value, &cp.value); \
\
min = g_value_get_##vtype (&self->priv->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_value); \
min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->maximum_value); \
\
for(i = 0; i < n_values; i++) { \
if (timestamp >= next_ts) { \
iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
iter1 = gst_timed_value_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); \
if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->values); \
else \
iter2 = NULL; \
} else { \
@ -560,9 +343,9 @@ static GstInterpolateMethod interpolate_linear = {
#define DEFINE_CUBIC_GET(vtype,round, convert) \
static void \
_interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
_interpolate_cubic_update_cache_##vtype (GstTimedValueControlSource *self) \
{ \
gint i, n = self->priv->nvalues; \
gint i, n = self->nvalues; \
gdouble *o = g_new0 (gdouble, n); \
gdouble *p = g_new0 (gdouble, n); \
gdouble *q = g_new0 (gdouble, n); \
@ -577,7 +360,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
g##vtype y_prev, y, y_next; \
\
/* Fill linear system of equations */ \
iter = g_sequence_get_begin_iter (self->priv->values); \
iter = g_sequence_get_begin_iter (self->values); \
cp = g_sequence_get (iter); \
x = cp->timestamp; \
y = g_value_get_##vtype (&cp->value); \
@ -622,7 +405,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
\
/* Save cache next in the GstControlPoint */ \
\
iter = g_sequence_get_begin_iter (self->priv->values); \
iter = g_sequence_get_begin_iter (self->values); \
for (i = 0; i < n; i++) { \
cp = g_sequence_get (iter); \
cp->cache.cubic.h = h[i]; \
@ -640,11 +423,11 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
} \
\
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) \
_interpolate_cubic_get_##vtype (GstTimedValueControlSource *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) { \
if (!self->valid_cache) { \
_interpolate_cubic_update_cache_##vtype (self); \
self->priv->valid_cache = TRUE; \
self->valid_cache = TRUE; \
} \
\
if (cp2) { \
@ -670,31 +453,31 @@ _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlP
} \
\
static gboolean \
interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
interpolate_cubic_get_##vtype (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \
{ \
g##vtype ret, min, max; \
GSequenceIter *iter; \
GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
\
if (self->priv->nvalues <= 2) \
if (self->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); \
min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->maximum_value); \
\
iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
iter = gst_timed_value_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); \
g_value_init (&cp.value, self->type); \
g_value_copy (&self->default_value, &cp.value); \
cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \
iter = g_sequence_get_begin_iter (self->priv->values); \
if (G_LIKELY (self->values)) \
iter = g_sequence_get_begin_iter (self->values); \
} \
if (iter && !g_sequence_iter_is_end (iter)) \
cp2 = g_sequence_get (iter); \
@ -708,7 +491,7 @@ interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime
} \
\
static gboolean \
interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \
interpolate_cubic_get_##vtype##_value_array (GstTimedValueControlSource *self, \
GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \
guint i; \
@ -719,25 +502,25 @@ interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self
GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
g##vtype val1 = 0, val2 = 0, min, max; \
\
if (self->priv->nvalues <= 2) \
if (self->nvalues <= 2) \
return interpolate_linear_get_##vtype##_value_array (self, timestamp, interval, n_values, values); \
\
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); \
g_value_init (&cp.value, self->type); \
g_value_copy (&self->default_value, &cp.value); \
\
min = g_value_get_##vtype (&self->priv->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_value); \
min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->maximum_value); \
\
for(i = 0; i < n_values; i++) { \
if (timestamp >= next_ts) { \
iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
iter1 = gst_timed_value_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); \
if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->values); \
else \
iter2 = NULL; \
} else { \
@ -801,7 +584,6 @@ static GstInterpolateMethod interpolate_cubic = {
/* register all interpolation methods */
GstInterpolateMethod *priv_gst_interpolation_methods[] = {
&interpolate_none,
&interpolate_trigger,
&interpolate_linear,
&interpolate_cubic,
&interpolate_cubic

View file

@ -31,7 +31,7 @@
* To use #GstInterpolationControlSource get a new instance by calling
* gst_interpolation_control_source_new(), bind it to a #GParamSpec, select a interpolation mode with
* gst_interpolation_control_source_set_interpolation_mode() and set some control points by calling
* gst_interpolation_control_source_set().
* gst_timed_value_control_source_set().
*
* All functions are MT-safe.
*
@ -48,54 +48,17 @@
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define _do_init \
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "interpolation control source", 0, "timeline value interpolating control source")
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "interpolation control source", 0, \
"timeline value interpolating control source")
G_DEFINE_TYPE_WITH_CODE (GstInterpolationControlSource,
gst_interpolation_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
gst_interpolation_control_source, GST_TYPE_TIMED_VALUE_CONTROL_SOURCE,
_do_init);
static GObjectClass *parent_class = NULL;
/*
* gst_control_point_free:
* @prop: the object to free
*
* Private method which frees all data allocated by a #GstControlPoint
* instance.
*/
static void
gst_control_point_free (GstControlPoint * cp)
struct _GstInterpolationControlSourcePrivate
{
g_return_if_fail (cp);
g_value_unset (&cp->value);
g_slice_free (GstControlPoint, cp);
}
static void
gst_interpolation_control_source_reset (GstInterpolationControlSource * self)
{
GstControlSource *csource = (GstControlSource *) self;
csource->get_value = NULL;
csource->get_value_array = NULL;
self->priv->type = self->priv->base = G_TYPE_INVALID;
if (G_IS_VALUE (&self->priv->default_value))
g_value_unset (&self->priv->default_value);
if (G_IS_VALUE (&self->priv->minimum_value))
g_value_unset (&self->priv->minimum_value);
if (G_IS_VALUE (&self->priv->maximum_value))
g_value_unset (&self->priv->maximum_value);
if (self->priv->values) {
g_sequence_free (self->priv->values);
self->priv->values = NULL;
}
self->priv->nvalues = 0;
self->priv->valid_cache = FALSE;
}
GstInterpolateMode interpolation_mode;
};
/**
* gst_interpolation_control_source_new:
@ -142,561 +105,115 @@ gst_interpolation_control_source_set_interpolation_mode (
"interpolation mode");
}
if (mode == GST_INTERPOLATE_USER) {
GST_WARNING ("User interpolation mode is not implemented yet");
return FALSE;
}
g_mutex_lock (self->lock);
switch (self->priv->base) {
GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (self);
switch (gst_timed_value_control_source_get_base_value_type (
(GstTimedValueControlSource *) self)) {
case G_TYPE_INT:
csource->get_value = priv_gst_interpolation_methods[mode]->get_int;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_int_value_array;
break;
case G_TYPE_UINT:{
case G_TYPE_UINT:
csource->get_value = priv_gst_interpolation_methods[mode]->get_uint;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_uint_value_array;
break;
}
case G_TYPE_LONG:{
case G_TYPE_LONG:
csource->get_value = priv_gst_interpolation_methods[mode]->get_long;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_long_value_array;
break;
}
case G_TYPE_ULONG:{
case G_TYPE_ULONG:
csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_ulong_value_array;
break;
}
case G_TYPE_INT64:{
case G_TYPE_INT64:
csource->get_value = priv_gst_interpolation_methods[mode]->get_int64;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_int64_value_array;
break;
}
case G_TYPE_UINT64:{
case G_TYPE_UINT64:
csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_uint64_value_array;
break;
}
case G_TYPE_FLOAT:{
case G_TYPE_FLOAT:
csource->get_value = priv_gst_interpolation_methods[mode]->get_float;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_float_value_array;
break;
}
case G_TYPE_DOUBLE:{
case G_TYPE_DOUBLE:
csource->get_value = priv_gst_interpolation_methods[mode]->get_double;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_double_value_array;
break;
}
case G_TYPE_BOOLEAN:{
case G_TYPE_BOOLEAN:
csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_boolean_value_array;
break;
}
case G_TYPE_ENUM:{
case G_TYPE_ENUM:
csource->get_value = priv_gst_interpolation_methods[mode]->get_enum;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_enum_value_array;
break;
}
case G_TYPE_STRING:{
case G_TYPE_STRING:
csource->get_value = priv_gst_interpolation_methods[mode]->get_string;
csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_string_value_array;
break;
}
default:
ret = FALSE;
break;
}
/* Incomplete implementation */
if (!ret || !csource->get_value || !csource->get_value_array) {
gst_interpolation_control_source_reset (self);
if (!csource->get_value || !csource->get_value_array) {
ret = FALSE;
}
self->priv->valid_cache = FALSE;
gst_timed_value_control_invalidate_cache ((GstTimedValueControlSource *)
csource);
self->priv->interpolation_mode = mode;
g_mutex_unlock (self->lock);
GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (self);
return ret;
}
static gboolean
gst_interpolation_control_source_bind (GstControlSource * source,
gst_interpolation_control_source_bind (GstControlSource * csource,
GParamSpec * pspec)
{
GType type, base;
GstInterpolationControlSource *self =
(GstInterpolationControlSource *) source;
gboolean ret = TRUE;
if (GST_CONTROL_SOURCE_CLASS
(gst_interpolation_control_source_parent_class)->bind (csource, pspec)) {
GstInterpolationControlSource *self =
GST_INTERPOLATION_CONTROL_SOURCE (csource);
/* get the fundamental base type */
self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
while ((type = g_type_parent (type)))
base = type;
self->priv->base = base;
/* restore type */
type = self->priv->type;
if (!gst_interpolation_control_source_set_interpolation_mode (self,
self->priv->interpolation_mode))
return FALSE;
switch (base) {
case G_TYPE_INT:{
GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_int (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_int (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_int (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_UINT:{
GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_uint (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_uint (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_uint (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_LONG:{
GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_long (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_long (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_long (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_ULONG:{
GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_ulong (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_ulong (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_ulong (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_INT64:{
GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_int64 (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_int64 (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_int64 (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_UINT64:{
GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_uint64 (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_uint64 (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_uint64 (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_FLOAT:{
GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_float (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_float (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_float (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_DOUBLE:{
GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_double (&self->priv->default_value, tpspec->default_value);
g_value_init (&self->priv->minimum_value, type);
g_value_set_double (&self->priv->minimum_value, tpspec->minimum);
g_value_init (&self->priv->maximum_value, type);
g_value_set_double (&self->priv->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_BOOLEAN:{
GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_boolean (&self->priv->default_value, tpspec->default_value);
break;
}
case G_TYPE_ENUM:{
GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_enum (&self->priv->default_value, tpspec->default_value);
break;
}
case G_TYPE_STRING:{
GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
g_value_init (&self->priv->default_value, type);
g_value_set_string (&self->priv->default_value, tpspec->default_value);
break;
}
default:
GST_WARNING ("incomplete implementation for paramspec type '%s'",
G_PARAM_SPEC_TYPE_NAME (pspec));
ret = FALSE;
break;
if (gst_interpolation_control_source_set_interpolation_mode (self,
self->priv->interpolation_mode))
return TRUE;
}
if (ret) {
self->priv->valid_cache = FALSE;
self->priv->nvalues = 0;
} else {
gst_interpolation_control_source_reset (self);
}
return ret;
return FALSE;
}
/*
* gst_control_point_compare:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstControlPoint
*
* Compare function for g_list operations that operates on two #GstControlPoint
* parameters.
*/
static gint
gst_control_point_compare (gconstpointer p1, gconstpointer p2)
{
GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
}
/*
* gst_control_point_find:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstClockTime
*
* Compare function for g_list operations that operates on a #GstControlPoint and
* a #GstClockTime.
*/
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));
}
static GstControlPoint *
_make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp,
const GValue * value)
{
GstControlPoint *cp;
/* create a new GstControlPoint */
cp = g_slice_new0 (GstControlPoint);
cp->timestamp = timestamp;
g_value_init (&cp->value, self->priv->type);
g_value_copy (value, &cp->value);
return cp;
}
static void
gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
self, GstClockTime timestamp, const GValue * value)
{
GSequenceIter *iter;
/* check if a control point for the timestamp already exists */
/* iter contains the iter right *after* timestamp */
if (G_LIKELY (self->priv->values)) {
iter =
g_sequence_search (self->priv->values, &timestamp,
(GCompareDataFunc) gst_control_point_find, NULL);
if (iter) {
GSequenceIter *prev = g_sequence_iter_prev (iter);
GstControlPoint *cp = g_sequence_get (prev);
/* If the timestamp is the same just update the control point value */
if (cp->timestamp == timestamp) {
/* update control point */
g_value_reset (&cp->value);
g_value_copy (value, &cp->value);
goto done;
}
}
} else {
self->priv->values =
g_sequence_new ((GDestroyNotify) gst_control_point_free);
}
/* sort new cp into the prop->values list */
g_sequence_insert_sorted (self->priv->values, _make_new_cp (self, timestamp,
value), (GCompareDataFunc) gst_control_point_compare, NULL);
self->priv->nvalues++;
done:
self->priv->valid_cache = FALSE;
}
/**
* gst_interpolation_control_source_set:
* @self: the #GstInterpolationControlSource object
* @timestamp: the time the control-change is scheduled for
* @value: the control-value
*
* Set the value of given controller-handled property at a certain time.
*
* Returns: FALSE if the values couldn't be set, TRUE otherwise.
*/
gboolean
gst_interpolation_control_source_set (GstInterpolationControlSource * self,
GstClockTime timestamp, const GValue * value)
{
g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_return_val_if_fail (G_IS_VALUE (value), FALSE);
g_return_val_if_fail (G_VALUE_TYPE (value) == self->priv->type, FALSE);
g_mutex_lock (self->lock);
gst_interpolation_control_source_set_internal (self, timestamp, value);
g_mutex_unlock (self->lock);
return TRUE;
}
/**
* gst_interpolation_control_source_set_from_list:
* @self: the #GstInterpolationControlSource object
* @timedvalues: (transfer none) (element-type GstController.TimedValue): a list
* with #GstTimedValue items
*
* Sets multiple timed values at once.
*
* Returns: FALSE if the values couldn't be set, TRUE otherwise.
*/
gboolean
gst_interpolation_control_source_set_from_list (GstInterpolationControlSource *
self, const GSList * timedvalues)
{
const GSList *node;
GstTimedValue *tv;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
for (node = timedvalues; node; node = g_slist_next (node)) {
tv = node->data;
if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
GST_FUNCTION);
} else if (!G_IS_VALUE (&tv->value)) {
GST_WARNING ("GstTimedValued with invalid value passed to %s",
GST_FUNCTION);
} else if (G_VALUE_TYPE (&tv->value) != self->priv->type) {
GST_WARNING ("incompatible value type for property");
} else {
g_mutex_lock (self->lock);
gst_interpolation_control_source_set_internal (self, tv->timestamp,
&tv->value);
g_mutex_unlock (self->lock);
res = TRUE;
}
}
return res;
}
/**
* gst_interpolation_control_source_unset:
* @self: the #GstInterpolationControlSource object
* @timestamp: the time the control-change should be removed from
*
* Used to remove the value of given controller-handled property at a certain
* time.
*
* Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
*/
gboolean
gst_interpolation_control_source_unset (GstInterpolationControlSource * self,
GstClockTime timestamp)
{
GSequenceIter *iter;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_mutex_lock (self->lock);
/* check if a control point for the timestamp exists */
if (G_LIKELY (self->priv->values) && (iter =
g_sequence_search (self->priv->values, &timestamp,
(GCompareDataFunc) gst_control_point_find, NULL))) {
GstControlPoint *cp;
/* Iter contains the iter right after timestamp, i.e.
* we need to get the previous one and check the timestamp
*/
iter = g_sequence_iter_prev (iter);
cp = g_sequence_get (iter);
if (cp->timestamp == timestamp) {
g_sequence_remove (iter);
self->priv->nvalues--;
self->priv->valid_cache = FALSE;
res = TRUE;
}
}
g_mutex_unlock (self->lock);
return res;
}
/**
* gst_interpolation_control_source_unset_all:
* @self: the #GstInterpolationControlSource object
*
* Used to remove all time-stamped values of given controller-handled property
*
*/
void
gst_interpolation_control_source_unset_all (GstInterpolationControlSource *
self)
{
g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self));
g_mutex_lock (self->lock);
/* free GstControlPoint structures */
if (self->priv->values) {
g_sequence_free (self->priv->values);
self->priv->values = NULL;
}
self->priv->nvalues = 0;
self->priv->valid_cache = FALSE;
g_mutex_unlock (self->lock);
}
static void
_append_control_point (GstControlPoint * cp, GQueue * res)
{
g_queue_push_tail (res, cp);
}
/**
* gst_interpolation_control_source_get_all:
* @self: the #GstInterpolationControlSource to get the list from
*
* Returns a read-only copy of the list of #GstTimedValue for the given property.
* Free the list after done with it.
*
* Returns: (transfer container) (element-type GstController.TimedValue): a copy
* of the list, or %NULL if the property isn't handled by the controller
*/
GList *
gst_interpolation_control_source_get_all (GstInterpolationControlSource * self)
{
GQueue res = G_QUEUE_INIT;
g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL);
g_mutex_lock (self->lock);
if (G_LIKELY (self->priv->values))
g_sequence_foreach (self->priv->values, (GFunc) _append_control_point,
&res);
g_mutex_unlock (self->lock);
return res.head;
}
/**
* gst_interpolation_control_source_get_count:
* @self: the #GstInterpolationControlSource to get the number of values from
*
* Returns the number of control points that are set.
*
* Returns: the number of control points that are set.
*
*/
gint
gst_interpolation_control_source_get_count (GstInterpolationControlSource *
self)
{
g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0);
return self->priv->nvalues;
}
static void
gst_interpolation_control_source_init (GstInterpolationControlSource * self)
{
self->lock = g_mutex_new ();
self->priv =
G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE,
GstInterpolationControlSourcePrivate);
self->priv->interpolation_mode = GST_INTERPOLATE_NONE;
}
static void
gst_interpolation_control_source_finalize (GObject * obj)
{
GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj);
g_mutex_lock (self->lock);
gst_interpolation_control_source_reset (self);
g_mutex_unlock (self->lock);
g_mutex_free (self->lock);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
gst_interpolation_control_source_dispose (GObject * obj)
{
G_OBJECT_CLASS (parent_class)->dispose (obj);
}
static void
gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
* klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass,
sizeof (GstInterpolationControlSourcePrivate));
gobject_class->finalize = gst_interpolation_control_source_finalize;
gobject_class->dispose = gst_interpolation_control_source_dispose;
csource_class->bind = gst_interpolation_control_source_bind;
}

View file

@ -27,7 +27,7 @@
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/gstcontrolsource.h>
#include <gst/controller/gsttimedvaluecontrolsource.h>
G_BEGIN_DECLS
@ -51,23 +51,18 @@ typedef struct _GstInterpolationControlSourcePrivate GstInterpolationControlSour
/**
* GstInterpolateMode:
* @GST_INTERPOLATE_NONE: steps-like interpolation, default
* @GST_INTERPOLATE_TRIGGER: returns the default value of the property,
* except for times with specific values
* @GST_INTERPOLATE_LINEAR: linear interpolation
* @GST_INTERPOLATE_QUADRATIC: square interpolation (deprecated, maps to cubic)
* @GST_INTERPOLATE_CUBIC: cubic interpolation
* @GST_INTERPOLATE_USER: user-provided interpolation (not yet available)
*
* The various interpolation modes available.
*/
typedef enum
{
GST_INTERPOLATE_NONE,
GST_INTERPOLATE_TRIGGER,
GST_INTERPOLATE_LINEAR,
GST_INTERPOLATE_QUADRATIC,
GST_INTERPOLATE_CUBIC,
GST_INTERPOLATE_USER
GST_INTERPOLATE_CUBIC
} GstInterpolateMode;
/**
@ -76,17 +71,15 @@ typedef enum
* The instance structure of #GstControlSource.
*/
struct _GstInterpolationControlSource {
GstControlSource parent;
GstTimedValueControlSource parent;
/* <private> */
GMutex *lock;
/*< private >*/
GstInterpolationControlSourcePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstInterpolationControlSourceClass {
GstControlSourceClass parent_class;
GstTimedValueControlSourceClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
@ -101,16 +94,6 @@ GstInterpolationControlSource *
gboolean gst_interpolation_control_source_set_interpolation_mode
(GstInterpolationControlSource *self,
GstInterpolateMode mode);
gboolean gst_interpolation_control_source_set (GstInterpolationControlSource * self,
GstClockTime timestamp,
const GValue * value);
gboolean gst_interpolation_control_source_set_from_list (GstInterpolationControlSource * self,
const GSList * timedvalues);
gboolean gst_interpolation_control_source_unset (GstInterpolationControlSource * self,
GstClockTime timestamp);
void gst_interpolation_control_source_unset_all (GstInterpolationControlSource *self);
GList * gst_interpolation_control_source_get_all (GstInterpolationControlSource * self);
gint gst_interpolation_control_source_get_count (GstInterpolationControlSource * self);
G_END_DECLS

View file

@ -80,21 +80,6 @@ typedef struct _GstControlPoint
} GstControlPoint;
struct _GstInterpolationControlSourcePrivate
{
GType type; /* type of the handled property */
GType base; /* base-type of the handled property */
GValue default_value; /* default value for the handled property */
GValue minimum_value; /* min value for the handled property */
GValue maximum_value; /* max value for the handled property */
GstInterpolateMode interpolation_mode;
GSequence *values; /* List of GstControlPoint */
gint nvalues; /* Number of control points */
gboolean valid_cache;
};
extern GstInterpolateMethod *priv_gst_interpolation_methods[];
extern guint priv_gst_num_interpolation_methods;

View file

@ -0,0 +1,603 @@
/* GStreamer
*
* Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* 2011 Stefan Sauer <ensonic@users.sf.net>
*
* gsttimedvaluecontrolsource.c: Base class for timeed value based control
* sources
*
* 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.
*/
/**
* SECTION:gsttimedvaluecontrolsource
* @short_description: timed value control source base class
*
* Base class for #GstContrlSources that use time-stamped values.
*
* When overriding bind, chain up first to give this bind implementation a
* chance to setup things.
*
* All functions are MT-safe.
*
*/
#include <glib-object.h>
#include <gst/gst.h>
#include "gstinterpolationcontrolsource.h"
#include "gstinterpolationcontrolsourceprivate.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define _do_init \
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "timed value control source", 0, \
"timed value control source base class")
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
/*
* gst_control_point_free:
* @prop: the object to free
*
* Private method which frees all data allocated by a #GstControlPoint
* instance.
*/
static void
gst_control_point_free (GstControlPoint * cp)
{
g_return_if_fail (cp);
g_value_unset (&cp->value);
g_slice_free (GstControlPoint, cp);
}
static void
gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
{
GstControlSource *csource = (GstControlSource *) self;
csource->get_value = NULL;
csource->get_value_array = NULL;
self->type = self->base = G_TYPE_INVALID;
if (G_IS_VALUE (&self->default_value))
g_value_unset (&self->default_value);
if (G_IS_VALUE (&self->minimum_value))
g_value_unset (&self->minimum_value);
if (G_IS_VALUE (&self->maximum_value))
g_value_unset (&self->maximum_value);
if (self->values) {
g_sequence_free (self->values);
self->values = NULL;
}
self->nvalues = 0;
self->valid_cache = FALSE;
}
static gboolean
gst_timed_value_control_source_bind (GstControlSource * source,
GParamSpec * pspec)
{
GType type, base;
GstTimedValueControlSource *self = (GstTimedValueControlSource *) source;
gboolean ret = TRUE;
/* get the fundamental base type */
self->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
while ((type = g_type_parent (type)))
base = type;
self->base = base;
/* restore type */
type = self->type;
switch (base) {
case G_TYPE_INT:{
GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
g_value_init (&self->default_value, type);
g_value_set_int (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_int (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_int (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_UINT:{
GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
g_value_init (&self->default_value, type);
g_value_set_uint (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_uint (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_uint (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_LONG:{
GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
g_value_init (&self->default_value, type);
g_value_set_long (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_long (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_long (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_ULONG:{
GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
g_value_init (&self->default_value, type);
g_value_set_ulong (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_ulong (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_ulong (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_INT64:{
GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
g_value_init (&self->default_value, type);
g_value_set_int64 (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_int64 (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_int64 (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_UINT64:{
GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
g_value_init (&self->default_value, type);
g_value_set_uint64 (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_uint64 (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_uint64 (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_FLOAT:{
GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
g_value_init (&self->default_value, type);
g_value_set_float (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_float (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_float (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_DOUBLE:{
GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
g_value_init (&self->default_value, type);
g_value_set_double (&self->default_value, tpspec->default_value);
g_value_init (&self->minimum_value, type);
g_value_set_double (&self->minimum_value, tpspec->minimum);
g_value_init (&self->maximum_value, type);
g_value_set_double (&self->maximum_value, tpspec->maximum);
break;
}
case G_TYPE_BOOLEAN:{
GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
g_value_init (&self->default_value, type);
g_value_set_boolean (&self->default_value, tpspec->default_value);
break;
}
case G_TYPE_ENUM:{
GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
g_value_init (&self->default_value, type);
g_value_set_enum (&self->default_value, tpspec->default_value);
break;
}
case G_TYPE_STRING:{
GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
g_value_init (&self->default_value, type);
g_value_set_string (&self->default_value, tpspec->default_value);
break;
}
default:
GST_WARNING ("incomplete implementation for paramspec type '%s'",
G_PARAM_SPEC_TYPE_NAME (pspec));
ret = FALSE;
break;
}
if (ret) {
self->valid_cache = FALSE;
self->nvalues = 0;
} else {
gst_timed_value_control_source_reset (self);
}
return ret;
}
/*
* gst_control_point_compare:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstControlPoint
*
* Compare function for g_list operations that operates on two #GstControlPoint
* parameters.
*/
static gint
gst_control_point_compare (gconstpointer p1, gconstpointer p2)
{
GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
}
/*
* gst_control_point_find:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstClockTime
*
* Compare function for g_list operations that operates on a #GstControlPoint and
* a #GstClockTime.
*/
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));
}
static GstControlPoint *
_make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
const GValue * value)
{
GstControlPoint *cp;
/* create a new GstControlPoint */
cp = g_slice_new0 (GstControlPoint);
cp->timestamp = timestamp;
g_value_init (&cp->value, self->type);
g_value_copy (value, &cp->value);
return cp;
}
static void
gst_timed_value_control_source_set_internal (GstTimedValueControlSource *
self, GstClockTime timestamp, const GValue * value)
{
GSequenceIter *iter;
/* check if a control point for the timestamp already exists */
/* iter contains the iter right *after* timestamp */
if (G_LIKELY (self->values)) {
iter =
g_sequence_search (self->values, &timestamp,
(GCompareDataFunc) gst_control_point_find, NULL);
if (iter) {
GSequenceIter *prev = g_sequence_iter_prev (iter);
GstControlPoint *cp = g_sequence_get (prev);
/* If the timestamp is the same just update the control point value */
if (cp->timestamp == timestamp) {
/* update control point */
g_value_reset (&cp->value);
g_value_copy (value, &cp->value);
goto done;
}
}
} else {
self->values = g_sequence_new ((GDestroyNotify) gst_control_point_free);
}
/* sort new cp into the prop->values list */
g_sequence_insert_sorted (self->values, _make_new_cp (self, timestamp,
value), (GCompareDataFunc) gst_control_point_compare, NULL);
self->nvalues++;
done:
self->valid_cache = FALSE;
}
/**
* gst_timed_value_control_source_find_control_point_iter:
* @self: the 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.
*
* For use in control source implementations.
*
* Returns: the found #GSequenceIter or %NULL
*/
GSequenceIter *gst_timed_value_control_source_find_control_point_iter
(GstTimedValueControlSource * self, GstClockTime timestamp)
{
GSequenceIter *iter;
if (!self->values)
return NULL;
iter =
g_sequence_search (self->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);
}
/**
* gst_timed_value_control_source_set:
* @self: the #GstTimedValueControlSource object
* @timestamp: the time the control-change is scheduled for
* @value: the control-value
*
* Set the value of given controller-handled property at a certain time.
*
* Returns: FALSE if the values couldn't be set, TRUE otherwise.
*/
gboolean
gst_timed_value_control_source_set (GstTimedValueControlSource * self,
GstClockTime timestamp, const GValue * value)
{
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_return_val_if_fail (G_IS_VALUE (value), FALSE);
g_return_val_if_fail (G_VALUE_TYPE (value) == self->type, FALSE);
g_mutex_lock (self->lock);
gst_timed_value_control_source_set_internal (self, timestamp, value);
g_mutex_unlock (self->lock);
return TRUE;
}
/**
* gst_timed_value_control_source_set_from_list:
* @self: the #GstTimedValueControlSource object
* @timedvalues: (transfer none) (element-type GstController.TimedValue): a list
* with #GstTimedValue items
*
* Sets multiple timed values at once.
*
* Returns: FALSE if the values couldn't be set, TRUE otherwise.
*/
gboolean
gst_timed_value_control_source_set_from_list (GstTimedValueControlSource *
self, const GSList * timedvalues)
{
const GSList *node;
GstTimedValue *tv;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
for (node = timedvalues; node; node = g_slist_next (node)) {
tv = node->data;
if (!GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
GST_FUNCTION);
} else if (!G_IS_VALUE (&tv->value)) {
GST_WARNING ("GstTimedValued with invalid value passed to %s",
GST_FUNCTION);
} else if (G_VALUE_TYPE (&tv->value) != self->type) {
GST_WARNING ("incompatible value type for property");
} else {
g_mutex_lock (self->lock);
gst_timed_value_control_source_set_internal (self, tv->timestamp,
&tv->value);
g_mutex_unlock (self->lock);
res = TRUE;
}
}
return res;
}
/**
* gst_timed_value_control_source_unset:
* @self: the #GstTimedValueControlSource object
* @timestamp: the time the control-change should be removed from
*
* Used to remove the value of given controller-handled property at a certain
* time.
*
* Returns: FALSE if the value couldn't be unset (i.e. not found, TRUE otherwise.
*/
gboolean
gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
GstClockTime timestamp)
{
GSequenceIter *iter;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_mutex_lock (self->lock);
/* check if a control point for the timestamp exists */
if (G_LIKELY (self->values) && (iter =
g_sequence_search (self->values, &timestamp,
(GCompareDataFunc) gst_control_point_find, NULL))) {
GstControlPoint *cp;
/* Iter contains the iter right after timestamp, i.e.
* we need to get the previous one and check the timestamp
*/
iter = g_sequence_iter_prev (iter);
cp = g_sequence_get (iter);
if (cp->timestamp == timestamp) {
g_sequence_remove (iter);
self->nvalues--;
self->valid_cache = FALSE;
res = TRUE;
}
}
g_mutex_unlock (self->lock);
return res;
}
/**
* gst_timed_value_control_source_unset_all:
* @self: the #GstTimedValueControlSource object
*
* Used to remove all time-stamped values of given controller-handled property
*
*/
void
gst_timed_value_control_source_unset_all (GstTimedValueControlSource * self)
{
g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
g_mutex_lock (self->lock);
/* free GstControlPoint structures */
if (self->values) {
g_sequence_free (self->values);
self->values = NULL;
}
self->nvalues = 0;
self->valid_cache = FALSE;
g_mutex_unlock (self->lock);
}
static void
_append_control_point (GstControlPoint * cp, GQueue * res)
{
g_queue_push_tail (res, cp);
}
/**
* gst_timed_value_control_source_get_all:
* @self: the #GstTimedValueControlSource to get the list from
*
* Returns a read-only copy of the list of #GstTimedValue for the given property.
* Free the list after done with it.
*
* Returns: (transfer container) (element-type GstController.TimedValue): a copy
* of the list, or %NULL if the property isn't handled by the controller
*/
GList *
gst_timed_value_control_source_get_all (GstTimedValueControlSource * self)
{
GQueue res = G_QUEUE_INIT;
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), NULL);
g_mutex_lock (self->lock);
if (G_LIKELY (self->values))
g_sequence_foreach (self->values, (GFunc) _append_control_point, &res);
g_mutex_unlock (self->lock);
return res.head;
}
/**
* gst_timed_value_control_source_get_count:
* @self: the #GstTimedValueControlSource to get the number of values from
*
* Get the number of control points that are set.
*
* Returns: the number of control points that are set.
*/
gint
gst_timed_value_control_source_get_count (GstTimedValueControlSource * self)
{
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), 0);
return self->nvalues;
}
/**
* gst_timed_value_control_source_get_base_value_type:
* @self: the #GstTimedValueControlSource
*
* Get the base #GType of the property value.
*
* Returns: the #GType, %G_TYPE_INVALID if not yet known.
*/
GType
gst_timed_value_control_source_get_base_value_type (GstTimedValueControlSource *
self)
{
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self),
G_TYPE_INVALID);
return self->base;
}
/**
* gst_timed_value_control_invalidate_cache:
* @self: the #GstTimedValueControlSource
*
* Reset the controlled value cache.
*/
void
gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self)
{
g_return_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self));
self->valid_cache = FALSE;
}
static void
gst_timed_value_control_source_init (GstTimedValueControlSource * self)
{
self->lock = g_mutex_new ();
}
static void
gst_timed_value_control_source_finalize (GObject * obj)
{
GstTimedValueControlSource *self = GST_TIMED_VALUE_CONTROL_SOURCE (obj);
g_mutex_lock (self->lock);
gst_timed_value_control_source_reset (self);
g_mutex_unlock (self->lock);
g_mutex_free (self->lock);
G_OBJECT_CLASS (gst_timed_value_control_source_parent_class)->finalize (obj);
}
static void
gst_timed_value_control_source_class_init (GstTimedValueControlSourceClass
* klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
gobject_class->finalize = gst_timed_value_control_source_finalize;
csource_class->bind = gst_timed_value_control_source_bind;
}

View file

@ -0,0 +1,114 @@
/* GStreamer
*
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
* 2011 Stefan Sauer <ensonic@users.sf.net>
*
* gsttimedvaluecontrolsource.h: Base class for timeed value based control
* sources
*
* 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.
*/
#ifndef __GST_TIMED_VALUE_CONTROL_SOURCE_H__
#define __GST_TIMED_VALUE_CONTROL_SOURCE_H__
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/gstcontrolsource.h>
G_BEGIN_DECLS
#define GST_TYPE_TIMED_VALUE_CONTROL_SOURCE \
(gst_timed_value_control_source_get_type ())
#define GST_TIMED_VALUE_CONTROL_SOURCE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, GstTimedValueControlSource))
#define GST_TIMED_VALUE_CONTROL_SOURCE_CLASS(vtable) \
(G_TYPE_CHECK_CLASS_CAST ((vtable), GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, GstTimedValueControlSourceClass))
#define GST_IS_TIMED_VALUE_CONTROL_SOURCE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TIMED_VALUE_CONTROL_SOURCE))
#define GST_IS_TIMED_VALUE_CONTROL_SOURCE_CLASS(vtable) \
(G_TYPE_CHECK_CLASS_TYPE ((vtable), GST_TYPE_TIMED_VALUE_CONTROL_SOURCE))
#define GST_TIMED_VALUE_CONTROL_SOURCE_GET_CLASS(inst) \
(G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, GstTimedValueControlSourceClass))
typedef struct _GstTimedValueControlSource GstTimedValueControlSource;
typedef struct _GstTimedValueControlSourceClass GstTimedValueControlSourceClass;
typedef struct _GstTimedValueControlSourcePrivate GstTimedValueControlSourcePrivate;
/**
* GstTimedValueControlSource:
*
* The instance structure of #GstControlSource.
*/
struct _GstTimedValueControlSource {
GstControlSource parent;
/*< protected >*/
GMutex *lock;
GType type; /* type of the handled property */
GType base; /* base-type of the handled property */
GValue default_value; /* default value for the handled property */
GValue minimum_value; /* min value for the handled property */
GValue maximum_value; /* max value for the handled property */
GSequence *values; /* List of GstControlPoint */
gint nvalues; /* Number of control points */
gboolean valid_cache;
GstTimedValueControlSourcePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstTimedValueControlSourceClass {
GstControlSourceClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
#define GST_TIMED_VALUE_CONTROL_SOURCE_LOCK(o) \
g_mutex_lock(((GstTimedValueControlSource *)o)->lock)
#define GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK(o) \
g_mutex_unlock(((GstTimedValueControlSource *)o)->lock)
GType gst_timed_value_control_source_get_type (void);
/* Functions */
GSequenceIter * gst_timed_value_control_source_find_control_point_iter (
GstTimedValueControlSource * self,
GstClockTime timestamp);
gboolean gst_timed_value_control_source_set (GstTimedValueControlSource * self,
GstClockTime timestamp,
const GValue * value);
gboolean gst_timed_value_control_source_set_from_list (GstTimedValueControlSource * self,
const GSList * timedvalues);
gboolean gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
GstClockTime timestamp);
void gst_timed_value_control_source_unset_all (GstTimedValueControlSource *self);
GList * gst_timed_value_control_source_get_all (GstTimedValueControlSource * self);
gint gst_timed_value_control_source_get_count (GstTimedValueControlSource * self);
GType gst_timed_value_control_source_get_base_value_type (
GstTimedValueControlSource * self);
void gst_timed_value_control_invalidate_cache (GstTimedValueControlSource * self);
G_END_DECLS
#endif /* __GST_TIMED_VALUE_CONTROL_SOURCE_H__ */

View file

@ -0,0 +1,404 @@
/* GStreamer
*
* Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* 2011 Stefan Sauer <ensonic@users.sf.net>
*
* gsttriggercontrolsource.c: Control source that provides some values at time-
* stamps
*
* 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.
*/
/**
* SECTION:gsttriggercontrolsource
* @short_description: interpolation control source
*
* #GstTriggerControlSource is a #GstControlSource, that returns values from user-given
* control points. It allows for a tolerance on the time-stamps.
*
* To use #GstTriggerControlSource get a new instance by calling
* gst_trigger_control_source_new(), bind it to a #GParamSpec and set some
* control points by calling gst_timed_value_control_source_set().
*
* All functions are MT-safe.
*/
#include <glib-object.h>
#include <gst/gst.h>
#include "gsttriggercontrolsource.h"
#include "gstinterpolationcontrolsourceprivate.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_TOLERANCE = 1,
};
#define _do_init \
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "trigger control source", 0, \
"timeline value trigger control source")
G_DEFINE_TYPE_WITH_CODE (GstTriggerControlSource, gst_trigger_control_source,
GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, _do_init);
struct _GstTriggerControlSourcePrivate
{
gint64 tolerance;
};
/* control point accessors */
/* 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 (GstTimedValueControlSource * self,
GSequenceIter * iter, GstClockTime timestamp)
{
GstControlPoint *cp;
/* check if there is a value at the registered timestamp */
if (iter) {
gint64 tolerance = ((GstTriggerControlSource *) self)->priv->tolerance;
cp = g_sequence_get (iter);
if (GST_CLOCK_DIFF (cp->timestamp, timestamp) <= tolerance) {
return &cp->value;
} else {
if ((iter = g_sequence_iter_next (iter))) {
cp = g_sequence_get (iter);
if (GST_CLOCK_DIFF (timestamp, cp->timestamp) <= tolerance) {
return &cp->value;
}
}
}
}
if (self->nvalues > 0)
return &self->default_value;
else
return NULL;
}
#define DEFINE_TRIGGER_GET_FUNC_COMPARABLE(type) \
static inline const GValue * \
_interpolate_trigger_get_##type (GstTimedValueControlSource *self, GSequenceIter *iter, GstClockTime timestamp) \
{ \
GstControlPoint *cp; \
\
/* check if there is a value at the registered timestamp */ \
if (iter) { \
gint64 tolerance = ((GstTriggerControlSource *)self)->priv->tolerance; \
gboolean found = FALSE; \
cp = g_sequence_get (iter); \
if (GST_CLOCK_DIFF (cp->timestamp,timestamp) <= tolerance ) { \
found = TRUE; \
} else { \
if ((iter = g_sequence_iter_next (iter))) { \
cp = g_sequence_get (iter); \
if (GST_CLOCK_DIFF (timestamp, cp->timestamp) <= tolerance) { \
found = TRUE; \
} \
} \
} \
if (found) { \
g##type ret = g_value_get_##type (&cp->value); \
if (g_value_get_##type (&self->minimum_value) > ret) \
return &self->minimum_value; \
else if (g_value_get_##type (&self->maximum_value) < ret) \
return &self->maximum_value; \
else \
return &cp->value; \
} \
} \
\
if (self->nvalues > 0) \
return &self->default_value; \
else \
return NULL; \
}
#define DEFINE_TRIGGER_GET(type, ctype, get_func) \
static gboolean \
interpolate_trigger_get_##type (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \
{ \
const GValue *ret; \
GSequenceIter *iter; \
\
g_mutex_lock (self->lock); \
\
iter = gst_timed_value_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 (GstTimedValueControlSource *self, \
GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \
guint i; \
GstClockTime ts = timestamp; \
GstClockTime next_ts = 0; \
ctype *values = (ctype *) _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 < n_values; i++) { \
if (!ret_val || ts >= next_ts) { \
iter1 = gst_timed_value_control_source_find_control_point_iter (self, ts); \
if (!iter1) { \
if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->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 += 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);
/**
* gst_trigger_control_source_new:
*
* This returns a new, unbound #GstTriggerControlSource.
*
* Returns: a new, unbound #GstTriggerControlSource.
*/
GstTriggerControlSource *
gst_trigger_control_source_new (void)
{
return g_object_newv (GST_TYPE_TRIGGER_CONTROL_SOURCE, 0, NULL);
}
static gboolean
gst_trigger_control_source_bind (GstControlSource * csource, GParamSpec * pspec)
{
if (GST_CONTROL_SOURCE_CLASS
(gst_trigger_control_source_parent_class)->bind (csource, pspec)) {
gboolean ret = TRUE;
GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (csource);
switch (gst_timed_value_control_source_get_base_value_type (
(GstTimedValueControlSource *) csource)) {
case G_TYPE_INT:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_int;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_int_value_array;
break;
case G_TYPE_UINT:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_uint;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_uint_value_array;
break;
case G_TYPE_LONG:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_long;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_long_value_array;
break;
case G_TYPE_ULONG:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_ulong;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_ulong_value_array;
break;
case G_TYPE_INT64:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_int64;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_int64_value_array;
break;
case G_TYPE_UINT64:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_uint64;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_uint64_value_array;
break;
case G_TYPE_FLOAT:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_float;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_float_value_array;
break;
case G_TYPE_DOUBLE:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_double;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_double_value_array;
break;
case G_TYPE_BOOLEAN:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_boolean;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_boolean_value_array;
break;
case G_TYPE_ENUM:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_enum;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_enum_value_array;
break;
case G_TYPE_STRING:
csource->get_value =
(GstControlSourceGetValue) interpolate_trigger_get_string;
csource->get_value_array = (GstControlSourceGetValueArray)
interpolate_trigger_get_string_value_array;
break;
default:
ret = FALSE;
break;
}
/* Incomplete implementation */
if (!csource->get_value || !csource->get_value_array) {
ret = FALSE;
}
gst_timed_value_control_invalidate_cache ((GstTimedValueControlSource *)
csource);
GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (csource);
return ret;
}
return FALSE;
}
static void
gst_trigger_control_source_init (GstTriggerControlSource * self)
{
self->priv =
G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_TRIGGER_CONTROL_SOURCE,
GstTriggerControlSourcePrivate);
}
static void
gst_trigger_control_source_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstTriggerControlSource *self = GST_TRIGGER_CONTROL_SOURCE (object);
switch (prop_id) {
case PROP_TOLERANCE:
GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (self);
self->priv->tolerance = g_value_get_int64 (value);
GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_trigger_control_source_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstTriggerControlSource *self = GST_TRIGGER_CONTROL_SOURCE (object);
switch (prop_id) {
case PROP_TOLERANCE:
g_value_set_int64 (value, self->priv->tolerance);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_trigger_control_source_class_init (GstTriggerControlSourceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
g_type_class_add_private (klass, sizeof (GstTriggerControlSourcePrivate));
gobject_class->set_property = gst_trigger_control_source_set_property;
gobject_class->get_property = gst_trigger_control_source_get_property;
csource_class->bind = gst_trigger_control_source_bind;
g_object_class_install_property (gobject_class, PROP_TOLERANCE,
g_param_spec_int64 ("tolerance", "Tolerance",
"Amount of ns a control time can be off to still trigger",
0, G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

View file

@ -0,0 +1,83 @@
/* GStreamer
*
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
* 2011 Stefan Sauer <ensonic@users.sf.net>
*
* gsttriggercontrolsource.h: Control source that provides some values at time-
* stamps
*
* 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.
*/
#ifndef __GST_TRIGGER_CONTROL_SOURCE_H__
#define __GST_TRIGGER_CONTROL_SOURCE_H__
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/controller/gsttimedvaluecontrolsource.h>
G_BEGIN_DECLS
#define GST_TYPE_TRIGGER_CONTROL_SOURCE \
(gst_trigger_control_source_get_type ())
#define GST_TRIGGER_CONTROL_SOURCE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TRIGGER_CONTROL_SOURCE, GstTriggerControlSource))
#define GST_TRIGGER_CONTROL_SOURCE_CLASS(vtable) \
(G_TYPE_CHECK_CLASS_CAST ((vtable), GST_TYPE_TRIGGER_CONTROL_SOURCE, GstTriggerControlSourceClass))
#define GST_IS_TRIGGER_CONTROL_SOURCE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TRIGGER_CONTROL_SOURCE))
#define GST_IS_TRIGGER_CONTROL_SOURCE_CLASS(vtable) \
(G_TYPE_CHECK_CLASS_TYPE ((vtable), GST_TYPE_TRIGGER_CONTROL_SOURCE))
#define GST_TRIGGER_CONTROL_SOURCE_GET_CLASS(inst) \
(G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_TRIGGER_CONTROL_SOURCE, GstTriggerControlSourceClass))
#define GST_TYPE_TRIGGER_WAVEFORM (gst_trigger_waveform_get_type ())
typedef struct _GstTriggerControlSource GstTriggerControlSource;
typedef struct _GstTriggerControlSourceClass GstTriggerControlSourceClass;
typedef struct _GstTriggerControlSourcePrivate GstTriggerControlSourcePrivate;
/**
* GstTriggerControlSource:
*
* The instance structure of #GstControlSource.
*/
struct _GstTriggerControlSource {
GstTimedValueControlSource parent;
/*< private >*/
GstTriggerControlSourcePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstTriggerControlSourceClass {
GstTimedValueControlSourceClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_trigger_control_source_get_type (void);
/* Functions */
GstTriggerControlSource *gst_trigger_control_source_new (void);
G_END_DECLS
#endif /* __GST_TRIGGER_CONTROL_SOURCE_H__ */

View file

@ -126,7 +126,8 @@ main (gint argc, gchar * argv[])
for (i = 0; i < NUM_CP; i++) {
g_value_set_double (&freq, g_random_double_range (50.0, 3000.0));
gst_interpolation_control_source_set (csource, i * tick, &freq);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource,
i * tick, &freq);
}
ct = gst_util_get_timestamp ();
@ -143,7 +144,8 @@ main (gint argc, gchar * argv[])
for (i = 0; i < 100; i++) {
j = g_random_int_range (0, NUM_CP - 1);
g_value_set_double (&freq, g_random_double_range (50.0, 3000.0));
gst_interpolation_control_source_set (csource, j * tick, &freq);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource,
j * tick, &freq);
}
ct = gst_util_get_timestamp ();

View file

@ -28,6 +28,7 @@
#include <gst/check/gstcheck.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstlfocontrolsource.h>
#include <gst/controller/gsttriggercontrolsource.h>
/* LOCAL TEST ELEMENT */
@ -396,6 +397,24 @@ GST_START_TEST (controller_param_twice)
GST_END_TEST;
/* tests if we can run controller methods against any GObject */
GST_START_TEST (controller_any_gobject)
{
GstElement *elem;
gboolean res;
elem = gst_element_factory_make ("bin", "test_elem");
/* that element is not controllable */
res = gst_object_sync_values (GST_OBJECT (elem), 0LL);
/* Syncing should still succeed as there's nothing to sync */
fail_unless (res == TRUE, NULL);
gst_object_unref (elem);
}
GST_END_TEST;
/* tests if we cleanup properly */
GST_START_TEST (controller_controlsource_refcounts)
{
@ -466,10 +485,12 @@ GST_START_TEST (controller_controlsource_empty2)
/* set control values */
g_value_init (&val, G_TYPE_ULONG);
g_value_set_ulong (&val, 0);
gst_interpolation_control_source_set (csource, 0 * GST_SECOND, &val);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource,
0 * GST_SECOND, &val);
/* ... and unset the value */
gst_interpolation_control_source_unset (csource, 0 * GST_SECOND);
gst_timed_value_control_source_unset ((GstTimedValueControlSource *) csource,
0 * GST_SECOND);
/* don't fail on empty control point lists */
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
@ -502,22 +523,23 @@ GST_START_TEST (controller_interpolate_none)
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_NONE));
fail_unless (gst_interpolation_control_source_get_count (csource) == 0);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 0);
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 1);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 1);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 2);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 2);
g_object_unref (csource);
@ -534,64 +556,6 @@ GST_START_TEST (controller_interpolate_none)
GST_END_TEST;
/* test timed value handling in trigger mode */
GST_START_TEST (controller_interpolate_trigger)
{
GstInterpolationControlSource *csource;
GstElement *elem;
gboolean res;
GValue val_ulong = { 0, };
elem = gst_element_factory_make ("testmonosource", "test_source");
/* Get interpolation control source */
csource = gst_interpolation_control_source_new ();
fail_unless (csource != NULL);
fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong",
GST_CONTROL_SOURCE (csource)));
/* set interpolation mode */
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_TRIGGER));
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
0 * GST_SECOND, &val_ulong));
/* set control values */
g_value_set_ulong (&val_ulong, 50);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
fail_unless (res, NULL);
/* now pull in values for some timestamps */
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
0 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
1 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
2 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
g_object_unref (csource);
gst_object_unref (elem);
}
GST_END_TEST;
/* test timed value handling with linear interpolation */
GST_START_TEST (controller_interpolate_linear)
{
@ -616,14 +580,12 @@ GST_START_TEST (controller_interpolate_linear)
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_object_unref (csource);
@ -665,24 +627,20 @@ GST_START_TEST (controller_interpolate_cubic)
/* set control values */
g_value_init (&val_double, G_TYPE_DOUBLE);
g_value_set_double (&val_double, 0.0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_value_set_double (&val_double, 5.0);
res =
gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_value_set_double (&val_double, 2.0);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_value_set_double (&val_double, 8.0);
res =
gst_interpolation_control_source_set (csource, 4 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 4 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_object_unref (csource);
@ -731,14 +689,12 @@ GST_START_TEST (controller_interpolate_cubic_too_few_cp)
/* set 2 control values */
g_value_init (&val_double, G_TYPE_DOUBLE);
g_value_set_double (&val_double, 0.0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_value_set_double (&val_double, 4.0);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_object_unref (csource);
@ -809,19 +765,16 @@ GST_START_TEST (controller_interpolation_unset)
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 50);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
/* verify values */
@ -833,7 +786,8 @@ GST_START_TEST (controller_interpolation_unset)
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
/* unset second */
res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND);
res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND);
fail_unless (res, NULL);
/* verify value again */
@ -843,12 +797,14 @@ GST_START_TEST (controller_interpolation_unset)
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
/* unset all values, reset and try to unset again */
fail_unless (gst_interpolation_control_source_unset (csource,
0 * GST_SECOND));
fail_unless (gst_interpolation_control_source_unset (csource,
2 * GST_SECOND));
gst_interpolation_control_source_unset_all (csource);
fail_if (gst_interpolation_control_source_unset (csource, 2 * GST_SECOND));
fail_unless (gst_timed_value_control_source_unset ((GstTimedValueControlSource
*) csource, 0 * GST_SECOND));
fail_unless (gst_timed_value_control_source_unset ((GstTimedValueControlSource
*) csource, 2 * GST_SECOND));
gst_timed_value_control_source_unset_all ((GstTimedValueControlSource *)
csource);
fail_if (gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND));
g_object_unref (csource);
@ -881,14 +837,12 @@ GST_START_TEST (controller_interpolation_unset_all)
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
/* verify values */
@ -898,7 +852,8 @@ GST_START_TEST (controller_interpolation_unset_all)
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
/* unset all */
gst_interpolation_control_source_unset_all (csource);
gst_timed_value_control_source_unset_all ((GstTimedValueControlSource *)
csource);
g_object_unref (csource);
@ -936,14 +891,12 @@ GST_START_TEST (controller_interpolation_linear_value_array)
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
/* now pull in values for some timestamps */
@ -987,14 +940,12 @@ GST_START_TEST (controller_interpolation_linear_invalid_values)
/* set control values */
g_value_init (&val_float, G_TYPE_FLOAT);
g_value_set_float (&val_float, 200.0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_float);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_float);
fail_unless (res, NULL);
g_value_set_float (&val_float, -200.0);
res =
gst_interpolation_control_source_set (csource, 4 * GST_SECOND,
&val_float);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 4 * GST_SECOND, &val_float);
fail_unless (res, NULL);
g_object_unref (csource);
@ -1056,14 +1007,12 @@ GST_START_TEST (controller_interpolation_linear_default_values)
/* set control values */
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 3 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 3 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
/* now pull in values for some timestamps */
@ -1079,20 +1028,20 @@ GST_START_TEST (controller_interpolation_linear_default_values)
/* set control values */
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
/* unset the old ones */
res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND);
res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 1 * GST_SECOND);
fail_unless (res, NULL);
res = gst_interpolation_control_source_unset (csource, 3 * GST_SECOND);
res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 3 * GST_SECOND);
fail_unless (res, NULL);
/* now pull in values for some timestamps */
@ -1143,14 +1092,12 @@ GST_START_TEST (controller_interpolate_linear_disabled)
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_object_unref (csource);
@ -1158,14 +1105,12 @@ GST_START_TEST (controller_interpolate_linear_disabled)
/* set control values */
g_value_init (&val_double, G_TYPE_DOUBLE);
g_value_set_double (&val_double, 2.0);
res =
gst_interpolation_control_source_set (csource2, 0 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource2, 0 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_value_set_double (&val_double, 4.0);
res =
gst_interpolation_control_source_set (csource2, 2 * GST_SECOND,
&val_double);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource2, 2 * GST_SECOND, &val_double);
fail_unless (res, NULL);
g_object_unref (G_OBJECT (csource2));
@ -1289,11 +1234,13 @@ GST_START_TEST (controller_interpolation_set_from_list)
list = g_slist_append (list, tval);
fail_if (gst_interpolation_control_source_set_from_list (csource, list));
fail_if (gst_timed_value_control_source_set_from_list (
(GstTimedValueControlSource *) csource, list));
/* try again with a valid stamp, should work now */
tval->timestamp = 0;
fail_unless (gst_interpolation_control_source_set_from_list (csource, list));
fail_unless (gst_timed_value_control_source_set_from_list (
(GstTimedValueControlSource *) csource, list));
g_object_unref (csource);
@ -1306,6 +1253,119 @@ GST_START_TEST (controller_interpolation_set_from_list)
GST_END_TEST;
/* test linear interpolation for ts < first control point */
GST_START_TEST (controller_interpolate_linear_before_ts0)
{
GstInterpolationControlSource *csource;
GstElement *elem;
gboolean res;
GValue val_ulong = { 0, };
elem = gst_element_factory_make ("testmonosource", "test_source");
/* Get interpolation control source */
csource = gst_interpolation_control_source_new ();
fail_unless (csource != NULL);
fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong",
GST_CONTROL_SOURCE (csource)));
/* set interpolation mode */
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_LINEAR));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 100);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 0);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 4 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_object_unref (csource);
/* now pull in values for some timestamps after first control point */
gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
gst_object_sync_values (GST_OBJECT (elem), 3 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 4 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
/* now pull in values for some timestamps before first control point */
gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
gst_object_unref (elem);
}
GST_END_TEST;
/* test control-point handling in interpolation control source */
GST_START_TEST (controller_interpolation_cp_count)
{
GstInterpolationControlSource *csource;
GstElement *elem;
gboolean res;
GValue val_ulong = { 0, };
elem = gst_element_factory_make ("testmonosource", "test_source");
/* Get interpolation control source */
csource = gst_interpolation_control_source_new ();
fail_unless (csource != NULL);
fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong",
GST_CONTROL_SOURCE (csource)));
/* set interpolation mode */
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_NONE));
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 0);
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 1);
g_value_set_ulong (&val_ulong, 100);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 2);
/* now unset control values */
res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND);
fail_unless (res, NULL);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 1);
res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND);
fail_unless (res, NULL);
fail_unless (gst_timed_value_control_source_get_count (
(GstTimedValueControlSource *) csource) == 0);
g_object_unref (csource);
gst_object_unref (elem);
}
GST_END_TEST;
/* test lfo control source with sine waveform */
GST_START_TEST (controller_lfo_sine)
{
@ -1720,28 +1780,10 @@ GST_START_TEST (controller_lfo_none)
GST_END_TEST;
/* tests if we can run helper methods against any GObject */
GST_START_TEST (controller_helper_any_gobject)
/* test timed value handling in trigger mode */
GST_START_TEST (controller_trigger_exact)
{
GstElement *elem;
gboolean res;
elem = gst_element_factory_make ("bin", "test_elem");
/* that element is not controllable */
res = gst_object_sync_values (GST_OBJECT (elem), 0LL);
/* Syncing should still succeed as there's nothing to sync */
fail_unless (res == TRUE, NULL);
gst_object_unref (elem);
}
GST_END_TEST;
/* test linear interpolation for ts < first control point */
GST_START_TEST (controller_interpolate_linear_before_ts0)
{
GstInterpolationControlSource *csource;
GstTriggerControlSource *csource;
GstElement *elem;
gboolean res;
GValue val_ulong = { 0, };
@ -1749,54 +1791,50 @@ GST_START_TEST (controller_interpolate_linear_before_ts0)
elem = gst_element_factory_make ("testmonosource", "test_source");
/* Get interpolation control source */
csource = gst_interpolation_control_source_new ();
csource = gst_trigger_control_source_new ();
fail_unless (csource != NULL);
fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong",
GST_CONTROL_SOURCE (csource)));
/* set interpolation mode */
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_LINEAR));
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
0 * GST_SECOND, &val_ulong));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 50);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
fail_unless (res, NULL);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 4 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
g_object_unref (csource);
/* now pull in values for some timestamps after first control point */
/* now pull in values for some timestamps */
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
0 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
1 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
2 * GST_SECOND, &val_ulong));
gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
gst_object_sync_values (GST_OBJECT (elem), 3 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 4 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
/* now pull in values for some timestamps before first control point */
gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
g_object_unref (csource);
gst_object_unref (elem);
}
GST_END_TEST;
/* test control-point handling in interpolation control source */
GST_START_TEST (controller_interpolation_cp_count)
GST_START_TEST (controller_trigger_tolerance)
{
GstInterpolationControlSource *csource;
GstTriggerControlSource *csource;
GstElement *elem;
gboolean res;
GValue val_ulong = { 0, };
@ -1804,44 +1842,42 @@ GST_START_TEST (controller_interpolation_cp_count)
elem = gst_element_factory_make ("testmonosource", "test_source");
/* Get interpolation control source */
csource = gst_interpolation_control_source_new ();
csource = gst_trigger_control_source_new ();
fail_unless (csource != NULL);
fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong",
GST_CONTROL_SOURCE (csource)));
/* set interpolation mode */
fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_NONE));
g_object_set (csource, "tolerance", G_GINT64_CONSTANT (10), NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 0);
g_value_init (&val_ulong, G_TYPE_ULONG);
fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
0 * GST_SECOND, &val_ulong));
/* set control values */
g_value_init (&val_ulong, G_TYPE_ULONG);
g_value_set_ulong (&val_ulong, 0);
res =
gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
&val_ulong);
g_value_set_ulong (&val_ulong, 50);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 0 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 1);
g_value_set_ulong (&val_ulong, 100);
res =
gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
&val_ulong);
res = gst_timed_value_control_source_set ((GstTimedValueControlSource *)
csource, 2 * GST_SECOND, &val_ulong);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 2);
/* now unset control values */
res = gst_interpolation_control_source_unset (csource, 2 * GST_SECOND);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 1);
res = gst_interpolation_control_source_unset (csource, 0 * GST_SECOND);
fail_unless (res, NULL);
fail_unless (gst_interpolation_control_source_get_count (csource) == 0);
/* now pull in values for some timestamps */
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND + 5);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50);
gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0);
gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND - 5);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND);
fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100);
g_object_unref (csource);
gst_object_unref (elem);
}
@ -1863,11 +1899,11 @@ gst_controller_suite (void)
tcase_add_test (tc, controller_new_okay1);
tcase_add_test (tc, controller_new_okay2);
tcase_add_test (tc, controller_param_twice);
tcase_add_test (tc, controller_any_gobject);
tcase_add_test (tc, controller_controlsource_refcounts);
tcase_add_test (tc, controller_controlsource_empty1);
tcase_add_test (tc, controller_controlsource_empty2);
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_cubic_too_few_cp);
@ -1879,6 +1915,8 @@ gst_controller_suite (void)
tcase_add_test (tc, controller_interpolation_linear_default_values);
tcase_add_test (tc, controller_interpolate_linear_disabled);
tcase_add_test (tc, controller_interpolation_set_from_list);
tcase_add_test (tc, controller_interpolate_linear_before_ts0);
tcase_add_test (tc, controller_interpolation_cp_count);
tcase_add_test (tc, controller_lfo_sine);
tcase_add_test (tc, controller_lfo_sine_timeshift);
tcase_add_test (tc, controller_lfo_square);
@ -1886,9 +1924,8 @@ gst_controller_suite (void)
tcase_add_test (tc, controller_lfo_rsaw);
tcase_add_test (tc, controller_lfo_triangle);
tcase_add_test (tc, controller_lfo_none);
tcase_add_test (tc, controller_helper_any_gobject);
tcase_add_test (tc, controller_interpolate_linear_before_ts0);
tcase_add_test (tc, controller_interpolation_cp_count);
tcase_add_test (tc, controller_trigger_exact);
tcase_add_test (tc, controller_trigger_tolerance);
return s;
}

View file

@ -66,18 +66,23 @@ main (gint argc, gchar ** argv)
/* set control values */
g_value_init (&vol, G_TYPE_DOUBLE);
g_value_set_double (&vol, 0.0);
gst_interpolation_control_source_set (csource1, 0 * GST_SECOND, &vol);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource1,
0 * GST_SECOND, &vol);
g_value_set_double (&vol, 1.0);
gst_interpolation_control_source_set (csource1, 5 * GST_SECOND, &vol);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource1,
5 * GST_SECOND, &vol);
g_object_unref (csource1);
g_value_set_double (&vol, 220.0);
gst_interpolation_control_source_set (csource2, 0 * GST_SECOND, &vol);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2,
0 * GST_SECOND, &vol);
g_value_set_double (&vol, 3520.0);
gst_interpolation_control_source_set (csource2, 3 * GST_SECOND, &vol);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2,
3 * GST_SECOND, &vol);
g_value_set_double (&vol, 440.0);
gst_interpolation_control_source_set (csource2, 6 * GST_SECOND, &vol);
gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2,
6 * GST_SECOND, &vol);
g_object_unref (csource2);