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. element properties over time.
</para> </para>
<xi:include href="xml/gsttimedvaluecontrolsource.xml" />
<xi:include href="xml/gstinterpolationcontrolsource.xml" /> <xi:include href="xml/gstinterpolationcontrolsource.xml" />
<xi:include href="xml/gstlfocontrolsource.xml" /> <xi:include href="xml/gstlfocontrolsource.xml" />
<xi:include href="xml/gsttriggercontrolsource.xml" />
</chapter> </chapter>
<chapter id="gstreamer-dataprotocol"> <chapter id="gstreamer-dataprotocol">

View file

@ -53,22 +53,22 @@ gst_dp_version_get_type
# control source classes # control source classes
<SECTION> <SECTION>
<FILE>gstinterpolationcontrolsource</FILE> <FILE>gsttimedvaluecontrolsource</FILE>
<TITLE>GstInterpolationControlSource</TITLE> <TITLE>GstTimedValueControlSource</TITLE>
<INCLUDE>libs/controller/gstinterpolationcontrolsource.h</INCLUDE> <INCLUDE>libs/controller/gsttimedvaluecontrolsource.h</INCLUDE>
GstInterpolationControlSource GstTimedValueControlSource
GstInterpolateMode gst_timed_value_control_source_find_control_point_iter
gst_interpolation_control_source_new gst_timed_value_control_source_set
gst_interpolation_control_source_set gst_timed_value_control_source_set_from_list
gst_interpolation_control_source_set_from_list gst_timed_value_control_source_get_all
gst_interpolation_control_source_set_interpolation_mode gst_timed_value_control_source_unset
gst_interpolation_control_source_get_all gst_timed_value_control_source_unset_all
gst_interpolation_control_source_unset gst_timed_value_control_source_get_count
gst_interpolation_control_source_unset_all gst_timed_value_control_source_get_base_value_type
gst_interpolation_control_source_get_count gst_timed_value_control_invalidate_cache
<SUBSECTION Standard> <SUBSECTION Standard>
GstInterpolationControlSourceClass GstTimedValueControlSourceClass
GstInterpolationControlSourcePrivate GstTimedValueControlSourcePrivate
GST_INTERPOLATION_CONTROL_SOURCE GST_INTERPOLATION_CONTROL_SOURCE
GST_IS_INTERPOLATION_CONTROL_SOURCE GST_IS_INTERPOLATION_CONTROL_SOURCE
GST_INTERPOLATION_CONTROL_SOURCE_CLASS GST_INTERPOLATION_CONTROL_SOURCE_CLASS
@ -76,6 +76,27 @@ GST_IS_INTERPOLATION_CONTROL_SOURCE_CLASS
GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS
GST_TYPE_INTERPOLATION_CONTROL_SOURCE GST_TYPE_INTERPOLATION_CONTROL_SOURCE
<SUBSECTION Private> <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 gst_interpolation_control_source_get_type
</SECTION> </SECTION>
@ -101,6 +122,25 @@ gst_lfo_control_source_get_type
gst_lfo_waveform_get_type gst_lfo_waveform_get_type
</SECTION> </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 # base classes
<SECTION> <SECTION>

View file

@ -18,11 +18,15 @@ gst_push_src_get_type
% controller % controller
#include <gst/controller/gsttimedvaluecontrolsource.h>
#include <gst/controller/gstinterpolationcontrolsource.h> #include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstlfocontrolsource.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_interpolation_control_source_get_type
gst_lfo_control_source_get_type gst_lfo_control_source_get_type
gst_trigger_control_source_get_type
% net % net

View file

@ -447,4 +447,8 @@ The 0.11 porting guide
properties fetch the value array. Also GstValueArray is gone. The fields of properties fetch the value array. Also GstValueArray is gone. The fields of
GstValueArray are now passed directly to gst_object_get_value_array as GstValueArray are now passed directly to gst_object_get_value_array as
arguments. 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> * </para></listitem>
* <listitem><para> * <listitem><para>
* Set the control values * Set the control values
* gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1); * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,0 * GST_SECOND, value1);
* gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2); * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,1 * GST_SECOND, value2);
* </para></listitem> * </para></listitem>
* <listitem><para> * <listitem><para>
* start your pipeline * 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@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller
libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \ libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \
gsttimedvaluecontrolsource.h \
gstinterpolationcontrolsource.h \ gstinterpolationcontrolsource.h \
gsttriggercontrolsource.h \
gstlfocontrolsource.h gstlfocontrolsource.h
noinst_HEADERS = \ noinst_HEADERS = \
@ -10,8 +12,10 @@ noinst_HEADERS = \
gstlfocontrolsourceprivate.h gstlfocontrolsourceprivate.h
libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \ libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \
gsttimedvaluecontrolsource.c \
gstinterpolation.c \ gstinterpolation.c \
gstinterpolationcontrolsource.c \ gstinterpolationcontrolsource.c \
gsttriggercontrolsource.c \
gstlfocontrolsource.c gstlfocontrolsource.c
libgstcontroller_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) 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) #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 */ /* steps-like (no-)interpolation, default */
/* just returns the value for the most recent key-frame */ /* just returns the value for the most recent key-frame */
static inline const GValue * static inline const GValue *
_interpolate_none_get (GstInterpolationControlSource * self, _interpolate_none_get (GstTimedValueControlSource * self, GSequenceIter * iter)
GSequenceIter * iter)
{ {
const GValue *ret; const GValue *ret;
@ -90,14 +45,14 @@ _interpolate_none_get (GstInterpolationControlSource * self,
ret = &cp->value; ret = &cp->value;
} else { } else {
ret = &self->priv->default_value; ret = &self->default_value;
} }
return ret; return ret;
} }
#define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \ #define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \
static inline const GValue * \ static inline const GValue * \
_interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter) \ _interpolate_none_get_##type (GstTimedValueControlSource *self, GSequenceIter *iter) \
{ \ { \
const GValue *ret; \ const GValue *ret; \
\ \
@ -105,28 +60,28 @@ _interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter
GstControlPoint *cp = g_sequence_get (iter); \ GstControlPoint *cp = g_sequence_get (iter); \
g##type ret_val = g_value_get_##type (&cp->value); \ g##type ret_val = g_value_get_##type (&cp->value); \
\ \
if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \ if (g_value_get_##type (&self->minimum_value) > ret_val) \
ret = &self->priv->minimum_value; \ ret = &self->minimum_value; \
else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \ else if (g_value_get_##type (&self->maximum_value) < ret_val) \
ret = &self->priv->maximum_value; \ ret = &self->maximum_value; \
else \ else \
ret = &cp->value; \ ret = &cp->value; \
} else { \ } else { \
ret = &self->priv->default_value; \ ret = &self->default_value; \
} \ } \
return ret; \ return ret; \
} }
#define DEFINE_NONE_GET(type,ctype,get_func) \ #define DEFINE_NONE_GET(type,ctype,get_func) \
static gboolean \ 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; \ const GValue *ret; \
GSequenceIter *iter; \ GSequenceIter *iter; \
\ \
g_mutex_lock (self->lock); \ 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); \ ret = get_func (self, iter); \
g_value_copy (ret, value); \ g_value_copy (ret, value); \
g_mutex_unlock (self->lock); \ g_mutex_unlock (self->lock); \
@ -134,7 +89,7 @@ interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime t
} \ } \
\ \
static gboolean \ 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) \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \ { \
guint i; \ guint i; \
@ -148,10 +103,10 @@ interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self,
g_mutex_lock (self->lock); \ g_mutex_lock (self->lock); \
for(i = 0; i < n_values; i++) { \ for(i = 0; i < n_values; i++) { \
if (!ret_val || ts >= next_ts) { \ 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 (!iter1) { \
if (G_LIKELY (self->priv->values)) \ if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->priv->values); \ iter2 = g_sequence_get_begin_iter (self->values); \
else \ else \
iter2 = NULL; \ iter2 = NULL; \
} else { \ } else { \
@ -224,178 +179,6 @@ static GstInterpolateMethod interpolate_none = {
(GstControlSourceGetValueArray) interpolate_none_get_string_value_array (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 */ /* linear interpolation */
/* smoothes inbetween values */ /* smoothes inbetween values */
@ -419,7 +202,7 @@ _interpolate_linear_internal_##vtype (GstClockTime timestamp1, g##vtype value1,
} \ } \
\ \
static gboolean \ 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; \ g##vtype ret, min, max; \
GSequenceIter *iter; \ GSequenceIter *iter; \
@ -427,20 +210,20 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim
\ \
g_mutex_lock (self->lock); \ g_mutex_lock (self->lock); \
\ \
min = g_value_get_##vtype (&self->priv->minimum_value); \ min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_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) { \ if (iter) { \
cp1 = g_sequence_get (iter); \ cp1 = g_sequence_get (iter); \
iter = g_sequence_iter_next (iter); \ iter = g_sequence_iter_next (iter); \
} else { \ } else { \
cp.timestamp = G_GUINT64_CONSTANT(0); \ cp.timestamp = G_GUINT64_CONSTANT(0); \
g_value_init (&cp.value, self->priv->type); \ g_value_init (&cp.value, self->type); \
g_value_copy (&self->priv->default_value, &cp.value); \ g_value_copy (&self->default_value, &cp.value); \
cp1 = &cp; \ cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \ if (G_LIKELY (self->values)) \
iter = g_sequence_get_begin_iter (self->priv->values); \ iter = g_sequence_get_begin_iter (self->values); \
} \ } \
if (iter && !g_sequence_iter_is_end (iter)) \ if (iter && !g_sequence_iter_is_end (iter)) \
cp2 = g_sequence_get (iter); \ cp2 = g_sequence_get (iter); \
@ -454,7 +237,7 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim
} \ } \
\ \
static gboolean \ 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) \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \ { \
guint i; \ guint i; \
@ -468,19 +251,19 @@ interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *sel
g_mutex_lock (self->lock); \ g_mutex_lock (self->lock); \
\ \
cp.timestamp = G_GUINT64_CONSTANT(0); \ cp.timestamp = G_GUINT64_CONSTANT(0); \
g_value_init (&cp.value, self->priv->type); \ g_value_init (&cp.value, self->type); \
g_value_copy (&self->priv->default_value, &cp.value); \ g_value_copy (&self->default_value, &cp.value); \
\ \
min = g_value_get_##vtype (&self->priv->minimum_value); \ min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_value); \ max = g_value_get_##vtype (&self->maximum_value); \
\ \
for(i = 0; i < n_values; i++) { \ for(i = 0; i < n_values; i++) { \
if (timestamp >= next_ts) { \ 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) { \ if (!iter1) { \
cp1 = &cp; \ cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \ if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->priv->values); \ iter2 = g_sequence_get_begin_iter (self->values); \
else \ else \
iter2 = NULL; \ iter2 = NULL; \
} else { \ } else { \
@ -560,9 +343,9 @@ static GstInterpolateMethod interpolate_linear = {
#define DEFINE_CUBIC_GET(vtype,round, convert) \ #define DEFINE_CUBIC_GET(vtype,round, convert) \
static void \ 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 *o = g_new0 (gdouble, n); \
gdouble *p = g_new0 (gdouble, n); \ gdouble *p = g_new0 (gdouble, n); \
gdouble *q = 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; \ g##vtype y_prev, y, y_next; \
\ \
/* Fill linear system of equations */ \ /* 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); \ cp = g_sequence_get (iter); \
x = cp->timestamp; \ x = cp->timestamp; \
y = g_value_get_##vtype (&cp->value); \ y = g_value_get_##vtype (&cp->value); \
@ -622,7 +405,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
\ \
/* Save cache next in the GstControlPoint */ \ /* 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++) { \ for (i = 0; i < n; i++) { \
cp = g_sequence_get (iter); \ cp = g_sequence_get (iter); \
cp->cache.cubic.h = h[i]; \ cp->cache.cubic.h = h[i]; \
@ -640,11 +423,11 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
} \ } \
\ \
static inline void \ 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); \ _interpolate_cubic_update_cache_##vtype (self); \
self->priv->valid_cache = TRUE; \ self->valid_cache = TRUE; \
} \ } \
\ \
if (cp2) { \ if (cp2) { \
@ -670,31 +453,31 @@ _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlP
} \ } \
\ \
static gboolean \ 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; \ g##vtype ret, min, max; \
GSequenceIter *iter; \ GSequenceIter *iter; \
GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \ GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
\ \
if (self->priv->nvalues <= 2) \ if (self->nvalues <= 2) \
return interpolate_linear_get_##vtype (self, timestamp, value); \ return interpolate_linear_get_##vtype (self, timestamp, value); \
\ \
g_mutex_lock (self->lock); \ g_mutex_lock (self->lock); \
\ \
min = g_value_get_##vtype (&self->priv->minimum_value); \ min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_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) { \ if (iter) { \
cp1 = g_sequence_get (iter); \ cp1 = g_sequence_get (iter); \
iter = g_sequence_iter_next (iter); \ iter = g_sequence_iter_next (iter); \
} else { \ } else { \
cp.timestamp = G_GUINT64_CONSTANT(0); \ cp.timestamp = G_GUINT64_CONSTANT(0); \
g_value_init (&cp.value, self->priv->type); \ g_value_init (&cp.value, self->type); \
g_value_copy (&self->priv->default_value, &cp.value); \ g_value_copy (&self->default_value, &cp.value); \
cp1 = &cp; \ cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \ if (G_LIKELY (self->values)) \
iter = g_sequence_get_begin_iter (self->priv->values); \ iter = g_sequence_get_begin_iter (self->values); \
} \ } \
if (iter && !g_sequence_iter_is_end (iter)) \ if (iter && !g_sequence_iter_is_end (iter)) \
cp2 = g_sequence_get (iter); \ cp2 = g_sequence_get (iter); \
@ -708,7 +491,7 @@ interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime
} \ } \
\ \
static gboolean \ 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) \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \
{ \ { \
guint i; \ guint i; \
@ -719,25 +502,25 @@ interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self
GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \ GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
g##vtype val1 = 0, val2 = 0, min, max; \ 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); \ return interpolate_linear_get_##vtype##_value_array (self, timestamp, interval, n_values, values); \
\ \
g_mutex_lock (self->lock); \ g_mutex_lock (self->lock); \
\ \
cp.timestamp = G_GUINT64_CONSTANT(0); \ cp.timestamp = G_GUINT64_CONSTANT(0); \
g_value_init (&cp.value, self->priv->type); \ g_value_init (&cp.value, self->type); \
g_value_copy (&self->priv->default_value, &cp.value); \ g_value_copy (&self->default_value, &cp.value); \
\ \
min = g_value_get_##vtype (&self->priv->minimum_value); \ min = g_value_get_##vtype (&self->minimum_value); \
max = g_value_get_##vtype (&self->priv->maximum_value); \ max = g_value_get_##vtype (&self->maximum_value); \
\ \
for(i = 0; i < n_values; i++) { \ for(i = 0; i < n_values; i++) { \
if (timestamp >= next_ts) { \ 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) { \ if (!iter1) { \
cp1 = &cp; \ cp1 = &cp; \
if (G_LIKELY (self->priv->values)) \ if (G_LIKELY (self->values)) \
iter2 = g_sequence_get_begin_iter (self->priv->values); \ iter2 = g_sequence_get_begin_iter (self->values); \
else \ else \
iter2 = NULL; \ iter2 = NULL; \
} else { \ } else { \
@ -801,7 +584,6 @@ static GstInterpolateMethod interpolate_cubic = {
/* register all interpolation methods */ /* register all interpolation methods */
GstInterpolateMethod *priv_gst_interpolation_methods[] = { GstInterpolateMethod *priv_gst_interpolation_methods[] = {
&interpolate_none, &interpolate_none,
&interpolate_trigger,
&interpolate_linear, &interpolate_linear,
&interpolate_cubic, &interpolate_cubic,
&interpolate_cubic &interpolate_cubic

View file

@ -31,7 +31,7 @@
* To use #GstInterpolationControlSource get a new instance by calling * 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_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_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. * All functions are MT-safe.
* *
@ -48,54 +48,17 @@
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define _do_init \ #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, 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; struct _GstInterpolationControlSourcePrivate
/*
* 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); GstInterpolateMode interpolation_mode;
};
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;
}
/** /**
* gst_interpolation_control_source_new: * gst_interpolation_control_source_new:
@ -142,561 +105,115 @@ gst_interpolation_control_source_set_interpolation_mode (
"interpolation mode"); "interpolation mode");
} }
if (mode == GST_INTERPOLATE_USER) { GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (self);
GST_WARNING ("User interpolation mode is not implemented yet"); switch (gst_timed_value_control_source_get_base_value_type (
return FALSE; (GstTimedValueControlSource *) self)) {
}
g_mutex_lock (self->lock);
switch (self->priv->base) {
case G_TYPE_INT: case G_TYPE_INT:
csource->get_value = priv_gst_interpolation_methods[mode]->get_int; csource->get_value = priv_gst_interpolation_methods[mode]->get_int;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_int_value_array; priv_gst_interpolation_methods[mode]->get_int_value_array;
break; break;
case G_TYPE_UINT:{ case G_TYPE_UINT:
csource->get_value = priv_gst_interpolation_methods[mode]->get_uint; csource->get_value = priv_gst_interpolation_methods[mode]->get_uint;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_uint_value_array; priv_gst_interpolation_methods[mode]->get_uint_value_array;
break; break;
} case G_TYPE_LONG:
case G_TYPE_LONG:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_long; csource->get_value = priv_gst_interpolation_methods[mode]->get_long;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_long_value_array; priv_gst_interpolation_methods[mode]->get_long_value_array;
break; break;
} case G_TYPE_ULONG:
case G_TYPE_ULONG:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong; csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_ulong_value_array; priv_gst_interpolation_methods[mode]->get_ulong_value_array;
break; break;
} case G_TYPE_INT64:
case G_TYPE_INT64:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_int64; csource->get_value = priv_gst_interpolation_methods[mode]->get_int64;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_int64_value_array; priv_gst_interpolation_methods[mode]->get_int64_value_array;
break; break;
} case G_TYPE_UINT64:
case G_TYPE_UINT64:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64; csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_uint64_value_array; priv_gst_interpolation_methods[mode]->get_uint64_value_array;
break; break;
} case G_TYPE_FLOAT:
case G_TYPE_FLOAT:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_float; csource->get_value = priv_gst_interpolation_methods[mode]->get_float;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_float_value_array; priv_gst_interpolation_methods[mode]->get_float_value_array;
break; break;
} case G_TYPE_DOUBLE:
case G_TYPE_DOUBLE:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_double; csource->get_value = priv_gst_interpolation_methods[mode]->get_double;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_double_value_array; priv_gst_interpolation_methods[mode]->get_double_value_array;
break; break;
} case G_TYPE_BOOLEAN:
case G_TYPE_BOOLEAN:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean; csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_boolean_value_array; priv_gst_interpolation_methods[mode]->get_boolean_value_array;
break; break;
} case G_TYPE_ENUM:
case G_TYPE_ENUM:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_enum; csource->get_value = priv_gst_interpolation_methods[mode]->get_enum;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_enum_value_array; priv_gst_interpolation_methods[mode]->get_enum_value_array;
break; break;
} case G_TYPE_STRING:
case G_TYPE_STRING:{
csource->get_value = priv_gst_interpolation_methods[mode]->get_string; csource->get_value = priv_gst_interpolation_methods[mode]->get_string;
csource->get_value_array = csource->get_value_array =
priv_gst_interpolation_methods[mode]->get_string_value_array; priv_gst_interpolation_methods[mode]->get_string_value_array;
break; break;
}
default: default:
ret = FALSE; ret = FALSE;
break; break;
} }
/* Incomplete implementation */ /* Incomplete implementation */
if (!ret || !csource->get_value || !csource->get_value_array) { if (!csource->get_value || !csource->get_value_array) {
gst_interpolation_control_source_reset (self);
ret = FALSE; ret = FALSE;
} }
gst_timed_value_control_invalidate_cache ((GstTimedValueControlSource *)
self->priv->valid_cache = FALSE; csource);
self->priv->interpolation_mode = mode; self->priv->interpolation_mode = mode;
g_mutex_unlock (self->lock); GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (self);
return ret; return ret;
} }
static gboolean static gboolean
gst_interpolation_control_source_bind (GstControlSource * source, gst_interpolation_control_source_bind (GstControlSource * csource,
GParamSpec * pspec) GParamSpec * pspec)
{ {
GType type, base; if (GST_CONTROL_SOURCE_CLASS
GstInterpolationControlSource *self = (gst_interpolation_control_source_parent_class)->bind (csource, pspec)) {
(GstInterpolationControlSource *) source; GstInterpolationControlSource *self =
gboolean ret = TRUE; GST_INTERPOLATION_CONTROL_SOURCE (csource);
/* get the fundamental base type */ if (gst_interpolation_control_source_set_interpolation_mode (self,
self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec); self->priv->interpolation_mode))
while ((type = g_type_parent (type))) return TRUE;
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;
} }
return FALSE;
if (ret) {
self->priv->valid_cache = FALSE;
self->priv->nvalues = 0;
} else {
gst_interpolation_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 (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 static void
gst_interpolation_control_source_init (GstInterpolationControlSource * self) gst_interpolation_control_source_init (GstInterpolationControlSource * self)
{ {
self->lock = g_mutex_new ();
self->priv = self->priv =
G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE, G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE,
GstInterpolationControlSourcePrivate); GstInterpolationControlSourcePrivate);
self->priv->interpolation_mode = GST_INTERPOLATE_NONE; 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 static void
gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
* klass) * klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass); GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, g_type_class_add_private (klass,
sizeof (GstInterpolationControlSourcePrivate)); 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; csource_class->bind = gst_interpolation_control_source_bind;
} }

View file

@ -27,7 +27,7 @@
#include <glib-object.h> #include <glib-object.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/gstcontrolsource.h> #include <gst/controller/gsttimedvaluecontrolsource.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -51,23 +51,18 @@ typedef struct _GstInterpolationControlSourcePrivate GstInterpolationControlSour
/** /**
* GstInterpolateMode: * GstInterpolateMode:
* @GST_INTERPOLATE_NONE: steps-like interpolation, default * @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_LINEAR: linear interpolation
* @GST_INTERPOLATE_QUADRATIC: square interpolation (deprecated, maps to cubic) * @GST_INTERPOLATE_QUADRATIC: square interpolation (deprecated, maps to cubic)
* @GST_INTERPOLATE_CUBIC: cubic interpolation * @GST_INTERPOLATE_CUBIC: cubic interpolation
* @GST_INTERPOLATE_USER: user-provided interpolation (not yet available)
* *
* The various interpolation modes available. * The various interpolation modes available.
*/ */
typedef enum typedef enum
{ {
GST_INTERPOLATE_NONE, GST_INTERPOLATE_NONE,
GST_INTERPOLATE_TRIGGER,
GST_INTERPOLATE_LINEAR, GST_INTERPOLATE_LINEAR,
GST_INTERPOLATE_QUADRATIC, GST_INTERPOLATE_QUADRATIC,
GST_INTERPOLATE_CUBIC, GST_INTERPOLATE_CUBIC
GST_INTERPOLATE_USER
} GstInterpolateMode; } GstInterpolateMode;
/** /**
@ -76,17 +71,15 @@ typedef enum
* The instance structure of #GstControlSource. * The instance structure of #GstControlSource.
*/ */
struct _GstInterpolationControlSource { struct _GstInterpolationControlSource {
GstControlSource parent; GstTimedValueControlSource parent;
/* <private> */ /*< private >*/
GMutex *lock;
GstInterpolationControlSourcePrivate *priv; GstInterpolationControlSourcePrivate *priv;
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];
}; };
struct _GstInterpolationControlSourceClass { struct _GstInterpolationControlSourceClass {
GstControlSourceClass parent_class; GstTimedValueControlSourceClass parent_class;
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];
@ -101,16 +94,6 @@ GstInterpolationControlSource *
gboolean gst_interpolation_control_source_set_interpolation_mode gboolean gst_interpolation_control_source_set_interpolation_mode
(GstInterpolationControlSource *self, (GstInterpolationControlSource *self,
GstInterpolateMode mode); 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 G_END_DECLS

View file

@ -80,21 +80,6 @@ typedef struct _GstControlPoint
} 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 GstInterpolateMethod *priv_gst_interpolation_methods[];
extern guint priv_gst_num_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++) { for (i = 0; i < NUM_CP; i++) {
g_value_set_double (&freq, g_random_double_range (50.0, 3000.0)); 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 (); ct = gst_util_get_timestamp ();
@ -143,7 +144,8 @@ main (gint argc, gchar * argv[])
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
j = g_random_int_range (0, NUM_CP - 1); j = g_random_int_range (0, NUM_CP - 1);
g_value_set_double (&freq, g_random_double_range (50.0, 3000.0)); 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 (); ct = gst_util_get_timestamp ();

View file

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

View file

@ -66,18 +66,23 @@ main (gint argc, gchar ** argv)
/* set control values */ /* set control values */
g_value_init (&vol, G_TYPE_DOUBLE); g_value_init (&vol, G_TYPE_DOUBLE);
g_value_set_double (&vol, 0.0); 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); 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_object_unref (csource1);
g_value_set_double (&vol, 220.0); 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); 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); 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); g_object_unref (csource2);