diff options
-rw-r--r-- | docs/libs/gstreamer-libs-docs.sgml | 2 | ||||
-rw-r--r-- | docs/libs/gstreamer-libs-sections.txt | 64 | ||||
-rw-r--r-- | docs/libs/gstreamer-libs.types | 4 | ||||
-rw-r--r-- | docs/random/porting-to-0.11.txt | 6 | ||||
-rw-r--r-- | gst/gstobject.c | 4 | ||||
-rw-r--r-- | libs/gst/controller/Makefile.am | 4 | ||||
-rw-r--r-- | libs/gst/controller/gstinterpolation.c | 328 | ||||
-rw-r--r-- | libs/gst/controller/gstinterpolationcontrolsource.c | 551 | ||||
-rw-r--r-- | libs/gst/controller/gstinterpolationcontrolsource.h | 27 | ||||
-rw-r--r-- | libs/gst/controller/gstinterpolationcontrolsourceprivate.h | 15 | ||||
-rw-r--r-- | libs/gst/controller/gsttimedvaluecontrolsource.c | 603 | ||||
-rw-r--r-- | libs/gst/controller/gsttimedvaluecontrolsource.h | 114 | ||||
-rw-r--r-- | libs/gst/controller/gsttriggercontrolsource.c | 404 | ||||
-rw-r--r-- | libs/gst/controller/gsttriggercontrolsource.h | 83 | ||||
-rw-r--r-- | tests/benchmarks/controller.c | 6 | ||||
-rw-r--r-- | tests/check/libs/controller.c | 499 | ||||
-rw-r--r-- | tests/examples/controller/audio-example.c | 15 |
17 files changed, 1649 insertions, 1080 deletions
diff --git a/docs/libs/gstreamer-libs-docs.sgml b/docs/libs/gstreamer-libs-docs.sgml index 8f12e655a..788c3d836 100644 --- a/docs/libs/gstreamer-libs-docs.sgml +++ b/docs/libs/gstreamer-libs-docs.sgml @@ -55,8 +55,10 @@ element properties over time. </para> + <xi:include href="xml/gsttimedvaluecontrolsource.xml" /> <xi:include href="xml/gstinterpolationcontrolsource.xml" /> <xi:include href="xml/gstlfocontrolsource.xml" /> + <xi:include href="xml/gsttriggercontrolsource.xml" /> </chapter> <chapter id="gstreamer-dataprotocol"> diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt index 2491b29dd..c61a1838d 100644 --- a/docs/libs/gstreamer-libs-sections.txt +++ b/docs/libs/gstreamer-libs-sections.txt @@ -53,28 +53,49 @@ gst_dp_version_get_type # control source classes <SECTION> +<FILE>gsttimedvaluecontrolsource</FILE> +<TITLE>GstTimedValueControlSource</TITLE> +<INCLUDE>libs/controller/gsttimedvaluecontrolsource.h</INCLUDE> +GstTimedValueControlSource +gst_timed_value_control_source_find_control_point_iter +gst_timed_value_control_source_set +gst_timed_value_control_source_set_from_list +gst_timed_value_control_source_get_all +gst_timed_value_control_source_unset +gst_timed_value_control_source_unset_all +gst_timed_value_control_source_get_count +gst_timed_value_control_source_get_base_value_type +gst_timed_value_control_invalidate_cache +<SUBSECTION Standard> +GstTimedValueControlSourceClass +GstTimedValueControlSourcePrivate +GST_INTERPOLATION_CONTROL_SOURCE +GST_IS_INTERPOLATION_CONTROL_SOURCE +GST_INTERPOLATION_CONTROL_SOURCE_CLASS +GST_IS_INTERPOLATION_CONTROL_SOURCE_CLASS +GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS +GST_TYPE_INTERPOLATION_CONTROL_SOURCE +<SUBSECTION Private> +gst_timed_value_control_source_get_type +</SECTION> + +<SECTION> <FILE>gstinterpolationcontrolsource</FILE> <TITLE>GstInterpolationControlSource</TITLE> <INCLUDE>libs/controller/gstinterpolationcontrolsource.h</INCLUDE> GstInterpolationControlSource GstInterpolateMode gst_interpolation_control_source_new -gst_interpolation_control_source_set -gst_interpolation_control_source_set_from_list gst_interpolation_control_source_set_interpolation_mode -gst_interpolation_control_source_get_all -gst_interpolation_control_source_unset -gst_interpolation_control_source_unset_all -gst_interpolation_control_source_get_count <SUBSECTION Standard> GstInterpolationControlSourceClass GstInterpolationControlSourcePrivate -GST_INTERPOLATION_CONTROL_SOURCE -GST_IS_INTERPOLATION_CONTROL_SOURCE -GST_INTERPOLATION_CONTROL_SOURCE_CLASS -GST_IS_INTERPOLATION_CONTROL_SOURCE_CLASS -GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS -GST_TYPE_INTERPOLATION_CONTROL_SOURCE +GST_TIMED_VALUE_CONTROL_SOURCE +GST_IS_TIMED_VALUE_CONTROL_SOURCE +GST_TIMED_VALUE_CONTROL_SOURCE_CLASS +GST_IS_TIMED_VALUE_CONTROL_SOURCE_CLASS +GST_TIMED_VALUE_CONTROL_SOURCE_GET_CLASS +GST_TYPE_TIMED_VALUE_CONTROL_SOURCE <SUBSECTION Private> gst_interpolation_control_source_get_type </SECTION> @@ -101,6 +122,25 @@ gst_lfo_control_source_get_type gst_lfo_waveform_get_type </SECTION> +<SECTION> +<FILE>gsttriggercontrolsource</FILE> +<TITLE>GstTriggerControlSource</TITLE> +<INCLUDE>libs/controller/gsttriggercontrolsource.h</INCLUDE> +GstTriggerControlSource +gst_trigger_control_source_new +<SUBSECTION Standard> +GstTriggerControlSourceClass +GstTriggerControlSourcePrivate +GST_TRIGGER_CONTROL_SOURCE +GST_IS_TRIGGER_CONTROL_SOURCE +GST_TRIGGER_CONTROL_SOURCE_CLASS +GST_IS_TRIGGER_CONTROL_SOURCE_CLASS +GST_TRIGGER_CONTROL_SOURCE_GET_CLASS +GST_TYPE_TRIGGER_CONTROL_SOURCE +<SUBSECTION Private> +gst_trigger_control_source_get_type +</SECTION> + # base classes <SECTION> diff --git a/docs/libs/gstreamer-libs.types b/docs/libs/gstreamer-libs.types index 62594a4f4..a75d55b4f 100644 --- a/docs/libs/gstreamer-libs.types +++ b/docs/libs/gstreamer-libs.types @@ -18,11 +18,15 @@ gst_push_src_get_type % controller +#include <gst/controller/gsttimedvaluecontrolsource.h> #include <gst/controller/gstinterpolationcontrolsource.h> #include <gst/controller/gstlfocontrolsource.h> +#include <gst/controller/gsttriggercontrolsource.h> +gst_timed_value_control_source_get_type gst_interpolation_control_source_get_type gst_lfo_control_source_get_type +gst_trigger_control_source_get_type % net diff --git a/docs/random/porting-to-0.11.txt b/docs/random/porting-to-0.11.txt index 33dddaf00..57eba376e 100644 --- a/docs/random/porting-to-0.11.txt +++ b/docs/random/porting-to-0.11.txt @@ -447,4 +447,8 @@ The 0.11 porting guide properties fetch the value array. Also GstValueArray is gone. The fields of GstValueArray are now passed directly to gst_object_get_value_array as arguments. - + + GstInterpolationControlSource has been split. There is a new + GstTimedValueControlSource baseclass and 2 sub classes: + GstInterpolationControlSource and GstTriggerControlSource. The API for setting + and getting the timestamps is in GstTimedValueControlSource. diff --git a/gst/gstobject.c b/gst/gstobject.c index 21c3126f0..c3b8db7d4 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -121,8 +121,8 @@ * </para></listitem> * <listitem><para> * Set the control values - * gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1); - * gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2); + * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,0 * GST_SECOND, value1); + * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,1 * GST_SECOND, value2); * </para></listitem> * <listitem><para> * start your pipeline diff --git a/libs/gst/controller/Makefile.am b/libs/gst/controller/Makefile.am index c5e61b211..793caadfa 100644 --- a/libs/gst/controller/Makefile.am +++ b/libs/gst/controller/Makefile.am @@ -2,7 +2,9 @@ lib_LTLIBRARIES = libgstcontroller-@GST_MAJORMINOR@.la libgstcontroller_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \ + gsttimedvaluecontrolsource.h \ gstinterpolationcontrolsource.h \ + gsttriggercontrolsource.h \ gstlfocontrolsource.h noinst_HEADERS = \ @@ -10,8 +12,10 @@ noinst_HEADERS = \ gstlfocontrolsourceprivate.h libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \ + gsttimedvaluecontrolsource.c \ gstinterpolation.c \ gstinterpolationcontrolsource.c \ + gsttriggercontrolsource.c \ gstlfocontrolsource.c libgstcontroller_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) diff --git a/libs/gst/controller/gstinterpolation.c b/libs/gst/controller/gstinterpolation.c index 40bdb6a4f..7098f3a1b 100644 --- a/libs/gst/controller/gstinterpolation.c +++ b/libs/gst/controller/gstinterpolation.c @@ -33,55 +33,10 @@ GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT); #define EMPTY(x) (x) -/* common helper */ - -static gint -gst_control_point_find (gconstpointer p1, gconstpointer p2) -{ - GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp; - GstClockTime ct2 = *(GstClockTime *) p2; - - return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1)); -} - -/* - * gst_interpolation_control_source_find_control_point_iter: - * @self: the interpolation control source to search in - * @timestamp: the search key - * - * Find last value before given timestamp in control point list. - * If all values in the control point list come after the given - * timestamp or no values exist, %NULL is returned. - * - * Returns: the found #GSequenceIter or %NULL - */ -static GSequenceIter *gst_interpolation_control_source_find_control_point_iter - (GstInterpolationControlSource * self, GstClockTime timestamp) -{ - GSequenceIter *iter; - - if (!self->priv->values) - return NULL; - - iter = - g_sequence_search (self->priv->values, ×tamp, - (GCompareDataFunc) gst_control_point_find, NULL); - - /* g_sequence_search() returns the iter where timestamp - * would be inserted, i.e. the iter > timestamp, so - * we need to get the previous one. And of course, if - * there is no previous one, we return NULL. */ - if (g_sequence_iter_is_begin (iter)) - return NULL; - - return g_sequence_iter_prev (iter); -} - /* steps-like (no-)interpolation, default */ /* just returns the value for the most recent key-frame */ static inline const GValue * -_interpolate_none_get (GstInterpolationControlSource * self, - GSequenceIter * iter) +_interpolate_none_get (GstTimedValueControlSource * self, GSequenceIter * iter) { const GValue *ret; @@ -90,14 +45,14 @@ _interpolate_none_get (GstInterpolationControlSource * self, ret = &cp->value; } else { - ret = &self->priv->default_value; + ret = &self->default_value; } return ret; } #define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \ static inline const GValue * \ -_interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter) \ +_interpolate_none_get_##type (GstTimedValueControlSource *self, GSequenceIter *iter) \ { \ const GValue *ret; \ \ @@ -105,28 +60,28 @@ _interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter GstControlPoint *cp = g_sequence_get (iter); \ g##type ret_val = g_value_get_##type (&cp->value); \ \ - if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \ - ret = &self->priv->minimum_value; \ - else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \ - ret = &self->priv->maximum_value; \ + if (g_value_get_##type (&self->minimum_value) > ret_val) \ + ret = &self->minimum_value; \ + else if (g_value_get_##type (&self->maximum_value) < ret_val) \ + ret = &self->maximum_value; \ else \ ret = &cp->value; \ } else { \ - ret = &self->priv->default_value; \ + ret = &self->default_value; \ } \ return ret; \ } #define DEFINE_NONE_GET(type,ctype,get_func) \ static gboolean \ -interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ +interpolate_none_get_##type (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \ { \ const GValue *ret; \ GSequenceIter *iter; \ \ g_mutex_lock (self->lock); \ \ - iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ + iter = gst_timed_value_control_source_find_control_point_iter (self, timestamp); \ ret = get_func (self, iter); \ g_value_copy (ret, value); \ g_mutex_unlock (self->lock); \ @@ -134,7 +89,7 @@ interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime t } \ \ static gboolean \ -interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \ +interpolate_none_get_##type##_value_array (GstTimedValueControlSource *self, \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \ { \ guint i; \ @@ -148,10 +103,10 @@ interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, g_mutex_lock (self->lock); \ for(i = 0; i < n_values; i++) { \ if (!ret_val || ts >= next_ts) { \ - iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \ + iter1 = gst_timed_value_control_source_find_control_point_iter (self, ts); \ if (!iter1) { \ - if (G_LIKELY (self->priv->values)) \ - iter2 = g_sequence_get_begin_iter (self->priv->values); \ + if (G_LIKELY (self->values)) \ + iter2 = g_sequence_get_begin_iter (self->values); \ else \ iter2 = NULL; \ } else { \ @@ -224,178 +179,6 @@ static GstInterpolateMethod interpolate_none = { (GstControlSourceGetValueArray) interpolate_none_get_string_value_array }; -/* returns the default value of the property, except for times with specific values */ -/* needed for one-shot events, such as notes and triggers */ -static inline const GValue * -_interpolate_trigger_get (GstInterpolationControlSource * self, - GSequenceIter * iter, GstClockTime timestamp) -{ - GstControlPoint *cp; - - /* check if there is a value at the registered timestamp */ - if (iter) { - cp = g_sequence_get (iter); - if (timestamp == cp->timestamp) { - return &cp->value; - } - } - if (self->priv->nvalues > 0) - return &self->priv->default_value; - else - return NULL; -} - -#define DEFINE_TRIGGER_GET_FUNC_COMPARABLE(type) \ -static inline const GValue * \ -_interpolate_trigger_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter, GstClockTime timestamp) \ -{ \ - GstControlPoint *cp; \ - \ - /* check if there is a value at the registered timestamp */ \ - if (iter) { \ - cp = g_sequence_get (iter); \ - if (timestamp == cp->timestamp) { \ - g##type ret = g_value_get_##type (&cp->value); \ - if (g_value_get_##type (&self->priv->minimum_value) > ret) \ - return &self->priv->minimum_value; \ - else if (g_value_get_##type (&self->priv->maximum_value) < ret) \ - return &self->priv->maximum_value; \ - else \ - return &cp->value; \ - } \ - } \ - \ - if (self->priv->nvalues > 0) \ - return &self->priv->default_value; \ - else \ - return NULL; \ -} - -#define DEFINE_TRIGGER_GET(type, ctype, get_func) \ -static gboolean \ -interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ -{ \ - const GValue *ret; \ - GSequenceIter *iter; \ - \ - g_mutex_lock (self->lock); \ - \ - iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ - ret = get_func (self, iter, timestamp); \ - if (!ret) { \ - g_mutex_unlock (self->lock); \ - return FALSE; \ - } \ - \ - g_value_copy (ret, value); \ - g_mutex_unlock (self->lock); \ - return TRUE; \ -} \ -\ -static gboolean \ -interpolate_trigger_get_##type##_value_array (GstInterpolationControlSource *self, \ - GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \ -{ \ - guint i; \ - GstClockTime ts = timestamp; \ - GstClockTime next_ts = 0; \ - ctype *values = (ctype *) _values; \ - const GValue *ret_val = NULL; \ - ctype ret = 0; \ - GSequenceIter *iter1 = NULL, *iter2 = NULL; \ - gboolean triggered = FALSE; \ - \ - g_mutex_lock (self->lock); \ - for(i = 0; i < n_values; i++) { \ - if (!ret_val || ts >= next_ts) { \ - iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \ - if (!iter1) { \ - if (G_LIKELY (self->priv->values)) \ - iter2 = g_sequence_get_begin_iter (self->priv->values); \ - else \ - iter2 = NULL; \ - } else { \ - iter2 = g_sequence_iter_next (iter1); \ - } \ - \ - if (iter2 && !g_sequence_iter_is_end (iter2)) { \ - GstControlPoint *cp; \ - \ - cp = g_sequence_get (iter2); \ - next_ts = cp->timestamp; \ - } else { \ - next_ts = GST_CLOCK_TIME_NONE; \ - } \ - \ - ret_val = get_func (self, iter1, ts); \ - if (!ret_val) { \ - g_mutex_unlock (self->lock); \ - return FALSE; \ - } \ - ret = g_value_get_##type (ret_val); \ - triggered = TRUE; \ - } else if (triggered) { \ - ret_val = get_func (self, iter1, ts); \ - if (!ret_val) { \ - g_mutex_unlock (self->lock); \ - return FALSE; \ - } \ - ret = g_value_get_##type (ret_val); \ - triggered = FALSE; \ - } \ - *values = ret; \ - ts += interval; \ - values++; \ - } \ - g_mutex_unlock (self->lock); \ - return TRUE; \ -} - -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int); -DEFINE_TRIGGER_GET (int, gint, _interpolate_trigger_get_int); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint); -DEFINE_TRIGGER_GET (uint, guint, _interpolate_trigger_get_uint); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (long); -DEFINE_TRIGGER_GET (long, glong, _interpolate_trigger_get_long); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (ulong); -DEFINE_TRIGGER_GET (ulong, gulong, _interpolate_trigger_get_ulong); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int64); -DEFINE_TRIGGER_GET (int64, gint64, _interpolate_trigger_get_int64); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint64); -DEFINE_TRIGGER_GET (uint64, guint64, _interpolate_trigger_get_uint64); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (float); -DEFINE_TRIGGER_GET (float, gfloat, _interpolate_trigger_get_float); -DEFINE_TRIGGER_GET_FUNC_COMPARABLE (double); -DEFINE_TRIGGER_GET (double, gdouble, _interpolate_trigger_get_double); - -DEFINE_TRIGGER_GET (boolean, gboolean, _interpolate_trigger_get); -DEFINE_TRIGGER_GET (enum, gint, _interpolate_trigger_get); -DEFINE_TRIGGER_GET (string, const gchar *, _interpolate_trigger_get); - -static GstInterpolateMethod interpolate_trigger = { - (GstControlSourceGetValue) interpolate_trigger_get_int, - (GstControlSourceGetValueArray) interpolate_trigger_get_int_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_uint, - (GstControlSourceGetValueArray) interpolate_trigger_get_uint_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_long, - (GstControlSourceGetValueArray) interpolate_trigger_get_long_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_ulong, - (GstControlSourceGetValueArray) interpolate_trigger_get_ulong_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_int64, - (GstControlSourceGetValueArray) interpolate_trigger_get_int64_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_uint64, - (GstControlSourceGetValueArray) interpolate_trigger_get_uint64_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_float, - (GstControlSourceGetValueArray) interpolate_trigger_get_float_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_double, - (GstControlSourceGetValueArray) interpolate_trigger_get_double_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_boolean, - (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_enum, - (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array, - (GstControlSourceGetValue) interpolate_trigger_get_string, - (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array -}; /* linear interpolation */ /* smoothes inbetween values */ @@ -419,7 +202,7 @@ _interpolate_linear_internal_##vtype (GstClockTime timestamp1, g##vtype value1, } \ \ static gboolean \ -interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ +interpolate_linear_get_##vtype (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \ { \ g##vtype ret, min, max; \ GSequenceIter *iter; \ @@ -427,20 +210,20 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim \ g_mutex_lock (self->lock); \ \ - min = g_value_get_##vtype (&self->priv->minimum_value); \ - max = g_value_get_##vtype (&self->priv->maximum_value); \ + min = g_value_get_##vtype (&self->minimum_value); \ + max = g_value_get_##vtype (&self->maximum_value); \ \ - iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ + iter = gst_timed_value_control_source_find_control_point_iter (self, timestamp); \ if (iter) { \ cp1 = g_sequence_get (iter); \ iter = g_sequence_iter_next (iter); \ } else { \ cp.timestamp = G_GUINT64_CONSTANT(0); \ - g_value_init (&cp.value, self->priv->type); \ - g_value_copy (&self->priv->default_value, &cp.value); \ + g_value_init (&cp.value, self->type); \ + g_value_copy (&self->default_value, &cp.value); \ cp1 = &cp; \ - if (G_LIKELY (self->priv->values)) \ - iter = g_sequence_get_begin_iter (self->priv->values); \ + if (G_LIKELY (self->values)) \ + iter = g_sequence_get_begin_iter (self->values); \ } \ if (iter && !g_sequence_iter_is_end (iter)) \ cp2 = g_sequence_get (iter); \ @@ -454,7 +237,7 @@ interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTim } \ \ static gboolean \ -interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \ +interpolate_linear_get_##vtype##_value_array (GstTimedValueControlSource *self, \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \ { \ guint i; \ @@ -468,19 +251,19 @@ interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *sel g_mutex_lock (self->lock); \ \ cp.timestamp = G_GUINT64_CONSTANT(0); \ - g_value_init (&cp.value, self->priv->type); \ - g_value_copy (&self->priv->default_value, &cp.value); \ + g_value_init (&cp.value, self->type); \ + g_value_copy (&self->default_value, &cp.value); \ \ - min = g_value_get_##vtype (&self->priv->minimum_value); \ - max = g_value_get_##vtype (&self->priv->maximum_value); \ + min = g_value_get_##vtype (&self->minimum_value); \ + max = g_value_get_##vtype (&self->maximum_value); \ \ for(i = 0; i < n_values; i++) { \ if (timestamp >= next_ts) { \ - iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \ + iter1 = gst_timed_value_control_source_find_control_point_iter (self, ts); \ if (!iter1) { \ cp1 = &cp; \ - if (G_LIKELY (self->priv->values)) \ - iter2 = g_sequence_get_begin_iter (self->priv->values); \ + if (G_LIKELY (self->values)) \ + iter2 = g_sequence_get_begin_iter (self->values); \ else \ iter2 = NULL; \ } else { \ @@ -560,9 +343,9 @@ static GstInterpolateMethod interpolate_linear = { #define DEFINE_CUBIC_GET(vtype,round, convert) \ static void \ -_interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ +_interpolate_cubic_update_cache_##vtype (GstTimedValueControlSource *self) \ { \ - gint i, n = self->priv->nvalues; \ + gint i, n = self->nvalues; \ gdouble *o = g_new0 (gdouble, n); \ gdouble *p = g_new0 (gdouble, n); \ gdouble *q = g_new0 (gdouble, n); \ @@ -577,7 +360,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ g##vtype y_prev, y, y_next; \ \ /* Fill linear system of equations */ \ - iter = g_sequence_get_begin_iter (self->priv->values); \ + iter = g_sequence_get_begin_iter (self->values); \ cp = g_sequence_get (iter); \ x = cp->timestamp; \ y = g_value_get_##vtype (&cp->value); \ @@ -622,7 +405,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ \ /* Save cache next in the GstControlPoint */ \ \ - iter = g_sequence_get_begin_iter (self->priv->values); \ + iter = g_sequence_get_begin_iter (self->values); \ for (i = 0; i < n; i++) { \ cp = g_sequence_get (iter); \ cp->cache.cubic.h = h[i]; \ @@ -640,11 +423,11 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ } \ \ static inline void \ -_interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlPoint *cp1, g##vtype value1, GstControlPoint *cp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \ +_interpolate_cubic_get_##vtype (GstTimedValueControlSource *self, GstControlPoint *cp1, g##vtype value1, GstControlPoint *cp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \ { \ - if (!self->priv->valid_cache) { \ + if (!self->valid_cache) { \ _interpolate_cubic_update_cache_##vtype (self); \ - self->priv->valid_cache = TRUE; \ + self->valid_cache = TRUE; \ } \ \ if (cp2) { \ @@ -670,31 +453,31 @@ _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlP } \ \ static gboolean \ -interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ +interpolate_cubic_get_##vtype (GstTimedValueControlSource *self, GstClockTime timestamp, GValue *value) \ { \ g##vtype ret, min, max; \ GSequenceIter *iter; \ GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \ \ - if (self->priv->nvalues <= 2) \ + if (self->nvalues <= 2) \ return interpolate_linear_get_##vtype (self, timestamp, value); \ \ g_mutex_lock (self->lock); \ \ - min = g_value_get_##vtype (&self->priv->minimum_value); \ - max = g_value_get_##vtype (&self->priv->maximum_value); \ + min = g_value_get_##vtype (&self->minimum_value); \ + max = g_value_get_##vtype (&self->maximum_value); \ \ - iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ + iter = gst_timed_value_control_source_find_control_point_iter (self, timestamp); \ if (iter) { \ cp1 = g_sequence_get (iter); \ iter = g_sequence_iter_next (iter); \ } else { \ cp.timestamp = G_GUINT64_CONSTANT(0); \ - g_value_init (&cp.value, self->priv->type); \ - g_value_copy (&self->priv->default_value, &cp.value); \ + g_value_init (&cp.value, self->type); \ + g_value_copy (&self->default_value, &cp.value); \ cp1 = &cp; \ - if (G_LIKELY (self->priv->values)) \ - iter = g_sequence_get_begin_iter (self->priv->values); \ + if (G_LIKELY (self->values)) \ + iter = g_sequence_get_begin_iter (self->values); \ } \ if (iter && !g_sequence_iter_is_end (iter)) \ cp2 = g_sequence_get (iter); \ @@ -708,7 +491,7 @@ interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime } \ \ static gboolean \ -interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \ +interpolate_cubic_get_##vtype##_value_array (GstTimedValueControlSource *self, \ GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer _values) \ { \ guint i; \ @@ -719,25 +502,25 @@ interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \ g##vtype val1 = 0, val2 = 0, min, max; \ \ - if (self->priv->nvalues <= 2) \ + if (self->nvalues <= 2) \ return interpolate_linear_get_##vtype##_value_array (self, timestamp, interval, n_values, values); \ \ g_mutex_lock (self->lock); \ \ cp.timestamp = G_GUINT64_CONSTANT(0); \ - g_value_init (&cp.value, self->priv->type); \ - g_value_copy (&self->priv->default_value, &cp.value); \ + g_value_init (&cp.value, self->type); \ + g_value_copy (&self->default_value, &cp.value); \ \ - min = g_value_get_##vtype (&self->priv->minimum_value); \ - max = g_value_get_##vtype (&self->priv->maximum_value); \ + min = g_value_get_##vtype (&self->minimum_value); \ + max = g_value_get_##vtype (&self->maximum_value); \ \ for(i = 0; i < n_values; i++) { \ if (timestamp >= next_ts) { \ - iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \ + iter1 = gst_timed_value_control_source_find_control_point_iter (self, ts); \ if (!iter1) { \ cp1 = &cp; \ - if (G_LIKELY (self->priv->values)) \ - iter2 = g_sequence_get_begin_iter (self->priv->values); \ + if (G_LIKELY (self->values)) \ + iter2 = g_sequence_get_begin_iter (self->values); \ else \ iter2 = NULL; \ } else { \ @@ -801,7 +584,6 @@ static GstInterpolateMethod interpolate_cubic = { /* register all interpolation methods */ GstInterpolateMethod *priv_gst_interpolation_methods[] = { &interpolate_none, - &interpolate_trigger, &interpolate_linear, &interpolate_cubic, &interpolate_cubic diff --git a/libs/gst/controller/gstinterpolationcontrolsource.c b/libs/gst/controller/gstinterpolationcontrolsource.c index 4a81cadd2..037bc7528 100644 --- a/libs/gst/controller/gstinterpolationcontrolsource.c +++ b/libs/gst/controller/gstinterpolationcontrolsource.c @@ -31,7 +31,7 @@ * To use #GstInterpolationControlSource get a new instance by calling * gst_interpolation_control_source_new(), bind it to a #GParamSpec, select a interpolation mode with * gst_interpolation_control_source_set_interpolation_mode() and set some control points by calling - * gst_interpolation_control_source_set(). + * gst_timed_value_control_source_set(). * * All functions are MT-safe. * @@ -48,54 +48,17 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define _do_init \ - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "interpolation control source", 0, "timeline value interpolating control source") + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "interpolation control source", 0, \ + "timeline value interpolating control source") G_DEFINE_TYPE_WITH_CODE (GstInterpolationControlSource, - gst_interpolation_control_source, GST_TYPE_CONTROL_SOURCE, _do_init); + gst_interpolation_control_source, GST_TYPE_TIMED_VALUE_CONTROL_SOURCE, + _do_init); -static GObjectClass *parent_class = NULL; - -/* - * gst_control_point_free: - * @prop: the object to free - * - * Private method which frees all data allocated by a #GstControlPoint - * instance. - */ -static void -gst_control_point_free (GstControlPoint * cp) +struct _GstInterpolationControlSourcePrivate { - g_return_if_fail (cp); - - g_value_unset (&cp->value); - g_slice_free (GstControlPoint, cp); -} - -static void -gst_interpolation_control_source_reset (GstInterpolationControlSource * self) -{ - GstControlSource *csource = (GstControlSource *) self; - - csource->get_value = NULL; - csource->get_value_array = NULL; - - self->priv->type = self->priv->base = G_TYPE_INVALID; - - if (G_IS_VALUE (&self->priv->default_value)) - g_value_unset (&self->priv->default_value); - if (G_IS_VALUE (&self->priv->minimum_value)) - g_value_unset (&self->priv->minimum_value); - if (G_IS_VALUE (&self->priv->maximum_value)) - g_value_unset (&self->priv->maximum_value); - - if (self->priv->values) { - g_sequence_free (self->priv->values); - self->priv->values = NULL; - } - - self->priv->nvalues = 0; - self->priv->valid_cache = FALSE; -} + GstInterpolateMode interpolation_mode; +}; /** * gst_interpolation_control_source_new: @@ -142,525 +105,101 @@ gst_interpolation_control_source_set_interpolation_mode ( "interpolation mode"); } - if (mode == GST_INTERPOLATE_USER) { - GST_WARNING ("User interpolation mode is not implemented yet"); - return FALSE; - } - - g_mutex_lock (self->lock); - switch (self->priv->base) { + GST_TIMED_VALUE_CONTROL_SOURCE_LOCK (self); + switch (gst_timed_value_control_source_get_base_value_type ( + (GstTimedValueControlSource *) self)) { case G_TYPE_INT: csource->get_value = priv_gst_interpolation_methods[mode]->get_int; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_int_value_array; break; - case G_TYPE_UINT:{ + case G_TYPE_UINT: csource->get_value = priv_gst_interpolation_methods[mode]->get_uint; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_uint_value_array; break; - } - case G_TYPE_LONG:{ + case G_TYPE_LONG: csource->get_value = priv_gst_interpolation_methods[mode]->get_long; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_long_value_array; break; - } - case G_TYPE_ULONG:{ + case G_TYPE_ULONG: csource->get_value = priv_gst_interpolation_methods[mode]->get_ulong; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_ulong_value_array; break; - } - case G_TYPE_INT64:{ + case G_TYPE_INT64: csource->get_value = priv_gst_interpolation_methods[mode]->get_int64; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_int64_value_array; break; - } - case G_TYPE_UINT64:{ + case G_TYPE_UINT64: csource->get_value = priv_gst_interpolation_methods[mode]->get_uint64; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_uint64_value_array; break; - } - case G_TYPE_FLOAT:{ + case G_TYPE_FLOAT: csource->get_value = priv_gst_interpolation_methods[mode]->get_float; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_float_value_array; break; - } - case G_TYPE_DOUBLE:{ + case G_TYPE_DOUBLE: csource->get_value = priv_gst_interpolation_methods[mode]->get_double; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_double_value_array; break; - } - case G_TYPE_BOOLEAN:{ + case G_TYPE_BOOLEAN: csource->get_value = priv_gst_interpolation_methods[mode]->get_boolean; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_boolean_value_array; break; - } - case G_TYPE_ENUM:{ + case G_TYPE_ENUM: csource->get_value = priv_gst_interpolation_methods[mode]->get_enum; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_enum_value_array; break; - } - case G_TYPE_STRING:{ + case G_TYPE_STRING: csource->get_value = priv_gst_interpolation_methods[mode]->get_string; csource->get_value_array = priv_gst_interpolation_methods[mode]->get_string_value_array; break; - } default: ret = FALSE; break; } /* Incomplete implementation */ - if (!ret || !csource->get_value || !csource->get_value_array) { - gst_interpolation_control_source_reset (self); + if (!csource->get_value || !csource->get_value_array) { ret = FALSE; } - - self->priv->valid_cache = FALSE; + gst_timed_value_control_invalidate_cache ((GstTimedValueControlSource *) + csource); self->priv->interpolation_mode = mode; - g_mutex_unlock (self->lock); + GST_TIMED_VALUE_CONTROL_SOURCE_UNLOCK (self); return ret; } static gboolean -gst_interpolation_control_source_bind (GstControlSource * source, +gst_interpolation_control_source_bind (GstControlSource * csource, GParamSpec * pspec) { - GType type, base; - GstInterpolationControlSource *self = - (GstInterpolationControlSource *) source; - gboolean ret = TRUE; - - /* get the fundamental base type */ - self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec); - while ((type = g_type_parent (type))) - base = type; - - self->priv->base = base; - /* restore type */ - type = self->priv->type; - - if (!gst_interpolation_control_source_set_interpolation_mode (self, - self->priv->interpolation_mode)) - return FALSE; - - switch (base) { - case G_TYPE_INT:{ - GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_int (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_int (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_int (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_UINT:{ - GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_uint (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_uint (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_uint (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_LONG:{ - GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_long (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_long (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_long (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_ULONG:{ - GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_ulong (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_ulong (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_ulong (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_INT64:{ - GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_int64 (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_int64 (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_int64 (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_UINT64:{ - GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_uint64 (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_uint64 (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_uint64 (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_FLOAT:{ - GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_float (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_float (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_float (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_DOUBLE:{ - GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_double (&self->priv->default_value, tpspec->default_value); - g_value_init (&self->priv->minimum_value, type); - g_value_set_double (&self->priv->minimum_value, tpspec->minimum); - g_value_init (&self->priv->maximum_value, type); - g_value_set_double (&self->priv->maximum_value, tpspec->maximum); - break; - } - case G_TYPE_BOOLEAN:{ - GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_boolean (&self->priv->default_value, tpspec->default_value); - break; - } - case G_TYPE_ENUM:{ - GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_enum (&self->priv->default_value, tpspec->default_value); - break; - } - case G_TYPE_STRING:{ - GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec); - - g_value_init (&self->priv->default_value, type); - g_value_set_string (&self->priv->default_value, tpspec->default_value); - break; - } - default: - GST_WARNING ("incomplete implementation for paramspec type '%s'", - G_PARAM_SPEC_TYPE_NAME (pspec)); - ret = FALSE; - break; - } - - if (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, ×tamp, - (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); + if (GST_CONTROL_SOURCE_CLASS + (gst_interpolation_control_source_parent_class)->bind (csource, pspec)) { + GstInterpolationControlSource *self = + GST_INTERPOLATION_CONTROL_SOURCE (csource); - 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, ×tamp, - (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; - } + if (gst_interpolation_control_source_set_interpolation_mode (self, + self->priv->interpolation_mode)) + return TRUE; } - g_mutex_unlock (self->lock); - - return res; + return FALSE; } -/** - * gst_interpolation_control_source_unset_all: - * @self: the #GstInterpolationControlSource object - * - * Used to remove all time-stamped values of given controller-handled property - * - */ -void -gst_interpolation_control_source_unset_all (GstInterpolationControlSource * - self) -{ - g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self)); - - g_mutex_lock (self->lock); - /* free GstControlPoint structures */ - if (self->priv->values) { - g_sequence_free (self->priv->values); - self->priv->values = NULL; - } - self->priv->nvalues = 0; - self->priv->valid_cache = FALSE; - - g_mutex_unlock (self->lock); -} - -static void -_append_control_point (GstControlPoint * cp, GQueue * res) -{ - g_queue_push_tail (res, cp); -} - -/** - * gst_interpolation_control_source_get_all: - * @self: the #GstInterpolationControlSource to get the list from - * - * Returns a read-only copy of the list of #GstTimedValue for the given property. - * Free the list after done with it. - * - * Returns: (transfer container) (element-type GstController.TimedValue): a copy - * of the list, or %NULL if the property isn't handled by the controller - */ -GList * -gst_interpolation_control_source_get_all (GstInterpolationControlSource * self) -{ - GQueue res = G_QUEUE_INIT; - - g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL); - - g_mutex_lock (self->lock); - if (G_LIKELY (self->priv->values)) - g_sequence_foreach (self->priv->values, (GFunc) _append_control_point, - &res); - g_mutex_unlock (self->lock); - - return res.head; -} - -/** - * gst_interpolation_control_source_get_count: - * @self: the #GstInterpolationControlSource to get the number of values from - * - * Returns the number of control points that are set. - * - * Returns: the number of control points that are set. - * - */ -gint -gst_interpolation_control_source_get_count (GstInterpolationControlSource * - self) -{ - g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0); - return self->priv->nvalues; -} - - static void gst_interpolation_control_source_init (GstInterpolationControlSource * self) { - self->lock = g_mutex_new (); self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE, GstInterpolationControlSourcePrivate); @@ -668,35 +207,13 @@ gst_interpolation_control_source_init (GstInterpolationControlSource * self) } static void -gst_interpolation_control_source_finalize (GObject * obj) -{ - GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj); - - g_mutex_lock (self->lock); - gst_interpolation_control_source_reset (self); - g_mutex_unlock (self->lock); - g_mutex_free (self->lock); - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_interpolation_control_source_dispose (GObject * obj) -{ - G_OBJECT_CLASS (parent_class)->dispose (obj); -} - -static void gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass * klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass); - parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (GstInterpolationControlSourcePrivate)); - gobject_class->finalize = gst_interpolation_control_source_finalize; - gobject_class->dispose = gst_interpolation_control_source_dispose; csource_class->bind = gst_interpolation_control_source_bind; } diff --git a/libs/gst/controller/gstinterpolationcontrolsource.h b/libs/gst/controller/gstinterpolationcontrolsource.h index 82cd479b9..7b810cfef 100644 --- a/libs/gst/controller/gstinterpolationcontrolsource.h +++ b/libs/gst/controller/gstinterpolationcontrolsource.h @@ -27,7 +27,7 @@ #include <glib-object.h> #include <gst/gst.h> -#include <gst/gstcontrolsource.h> +#include <gst/controller/gsttimedvaluecontrolsource.h> G_BEGIN_DECLS @@ -51,23 +51,18 @@ typedef struct _GstInterpolationControlSourcePrivate GstInterpolationControlSour /** * GstInterpolateMode: * @GST_INTERPOLATE_NONE: steps-like interpolation, default - * @GST_INTERPOLATE_TRIGGER: returns the default value of the property, - * except for times with specific values * @GST_INTERPOLATE_LINEAR: linear interpolation * @GST_INTERPOLATE_QUADRATIC: square interpolation (deprecated, maps to cubic) * @GST_INTERPOLATE_CUBIC: cubic interpolation - * @GST_INTERPOLATE_USER: user-provided interpolation (not yet available) * * The various interpolation modes available. */ typedef enum { GST_INTERPOLATE_NONE, - GST_INTERPOLATE_TRIGGER, GST_INTERPOLATE_LINEAR, GST_INTERPOLATE_QUADRATIC, - GST_INTERPOLATE_CUBIC, - GST_INTERPOLATE_USER + GST_INTERPOLATE_CUBIC } GstInterpolateMode; /** @@ -76,17 +71,15 @@ typedef enum * The instance structure of #GstControlSource. */ struct _GstInterpolationControlSource { - GstControlSource parent; + GstTimedValueControlSource parent; - /* <private> */ - GMutex *lock; + /*< private >*/ GstInterpolationControlSourcePrivate *priv; - gpointer _gst_reserved[GST_PADDING]; }; struct _GstInterpolationControlSourceClass { - GstControlSourceClass parent_class; + GstTimedValueControlSourceClass parent_class; /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -101,16 +94,6 @@ GstInterpolationControlSource * gboolean gst_interpolation_control_source_set_interpolation_mode (GstInterpolationControlSource *self, GstInterpolateMode mode); -gboolean gst_interpolation_control_source_set (GstInterpolationControlSource * self, - GstClockTime timestamp, - const GValue * value); -gboolean gst_interpolation_control_source_set_from_list (GstInterpolationControlSource * self, - const GSList * timedvalues); -gboolean gst_interpolation_control_source_unset (GstInterpolationControlSource * self, - GstClockTime timestamp); -void gst_interpolation_control_source_unset_all (GstInterpolationControlSource *self); -GList * gst_interpolation_control_source_get_all (GstInterpolationControlSource * self); -gint gst_interpolation_control_source_get_count (GstInterpolationControlSource * self); G_END_DECLS diff --git a/libs/gst/controller/gstinterpolationcontrolsourceprivate.h b/libs/gst/controller/gstinterpolationcontrolsourceprivate.h index 516effda1..5447121f1 100644 --- a/libs/gst/controller/gstinterpolationcontrolsourceprivate.h +++ b/libs/gst/controller/gstinterpolationcontrolsourceprivate.h @@ -80,21 +80,6 @@ typedef struct _GstControlPoint } GstControlPoint; -struct _GstInterpolationControlSourcePrivate -{ - GType type; /* type of the handled property */ - GType base; /* base-type of the handled property */ - - GValue default_value; /* default value for the handled property */ - GValue minimum_value; /* min value for the handled property */ - GValue maximum_value; /* max value for the handled property */ - GstInterpolateMode interpolation_mode; - - GSequence *values; /* List of GstControlPoint */ - gint nvalues; /* Number of control points */ - gboolean valid_cache; -}; - extern GstInterpolateMethod *priv_gst_interpolation_methods[]; extern guint priv_gst_num_interpolation_methods; diff --git a/libs/gst/controller/gsttimedvaluecontrolsource.c b/libs/gst/controller/gsttimedvaluecontrolsource.c new file mode 100644 index 000000000..46fc61a52 --- /dev/null +++ b/libs/gst/controller/gsttimedvaluecontrolsource.c @@ -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, ×tamp, + (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, ×tamp, + (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, ×tamp, + (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; +} diff --git a/libs/gst/controller/gsttimedvaluecontrolsource.h b/libs/gst/controller/gsttimedvaluecontrolsource.h new file mode 100644 index 000000000..b8645e6d1 --- /dev/null +++ b/libs/gst/controller/gsttimedvaluecontrolsource.h @@ -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__ */ diff --git a/libs/gst/controller/gsttriggercontrolsource.c b/libs/gst/controller/gsttriggercontrolsource.c new file mode 100644 index 000000000..f6ca81519 --- /dev/null +++ b/libs/gst/controller/gsttriggercontrolsource.c @@ -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)); + +} diff --git a/libs/gst/controller/gsttriggercontrolsource.h b/libs/gst/controller/gsttriggercontrolsource.h new file mode 100644 index 000000000..f3d993935 --- /dev/null +++ b/libs/gst/controller/gsttriggercontrolsource.h @@ -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__ */ diff --git a/tests/benchmarks/controller.c b/tests/benchmarks/controller.c index ff95e44f1..f196bd92e 100644 --- a/tests/benchmarks/controller.c +++ b/tests/benchmarks/controller.c @@ -126,7 +126,8 @@ main (gint argc, gchar * argv[]) for (i = 0; i < NUM_CP; i++) { g_value_set_double (&freq, g_random_double_range (50.0, 3000.0)); - gst_interpolation_control_source_set (csource, i * tick, &freq); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource, + i * tick, &freq); } ct = gst_util_get_timestamp (); @@ -143,7 +144,8 @@ main (gint argc, gchar * argv[]) for (i = 0; i < 100; i++) { j = g_random_int_range (0, NUM_CP - 1); g_value_set_double (&freq, g_random_double_range (50.0, 3000.0)); - gst_interpolation_control_source_set (csource, j * tick, &freq); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource, + j * tick, &freq); } ct = gst_util_get_timestamp (); diff --git a/tests/check/libs/controller.c b/tests/check/libs/controller.c index f326c04a1..3fc51174b 100644 --- a/tests/check/libs/controller.c +++ b/tests/check/libs/controller.c @@ -28,6 +28,7 @@ #include <gst/check/gstcheck.h> #include <gst/controller/gstinterpolationcontrolsource.h> #include <gst/controller/gstlfocontrolsource.h> +#include <gst/controller/gsttriggercontrolsource.h> /* LOCAL TEST ELEMENT */ @@ -396,6 +397,24 @@ GST_START_TEST (controller_param_twice) GST_END_TEST; +/* tests if we can run controller methods against any GObject */ +GST_START_TEST (controller_any_gobject) +{ + GstElement *elem; + gboolean res; + + elem = gst_element_factory_make ("bin", "test_elem"); + + /* that element is not controllable */ + res = gst_object_sync_values (GST_OBJECT (elem), 0LL); + /* Syncing should still succeed as there's nothing to sync */ + fail_unless (res == TRUE, NULL); + + gst_object_unref (elem); +} + +GST_END_TEST; + /* tests if we cleanup properly */ GST_START_TEST (controller_controlsource_refcounts) { @@ -466,10 +485,12 @@ GST_START_TEST (controller_controlsource_empty2) /* set control values */ g_value_init (&val, G_TYPE_ULONG); g_value_set_ulong (&val, 0); - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, &val); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource, + 0 * GST_SECOND, &val); /* ... and unset the value */ - gst_interpolation_control_source_unset (csource, 0 * GST_SECOND); + gst_timed_value_control_source_unset ((GstTimedValueControlSource *) csource, + 0 * GST_SECOND); /* don't fail on empty control point lists */ gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND); @@ -502,22 +523,23 @@ GST_START_TEST (controller_interpolate_none) fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, GST_INTERPOLATE_NONE)); - fail_unless (gst_interpolation_control_source_get_count (csource) == 0); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 0); /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 1); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 1); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 2); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 2); g_object_unref (csource); @@ -534,64 +556,6 @@ GST_START_TEST (controller_interpolate_none) GST_END_TEST; -/* test timed value handling in trigger mode */ -GST_START_TEST (controller_interpolate_trigger) -{ - GstInterpolationControlSource *csource; - GstElement *elem; - gboolean res; - GValue val_ulong = { 0, }; - - elem = gst_element_factory_make ("testmonosource", "test_source"); - - /* Get interpolation control source */ - csource = gst_interpolation_control_source_new (); - - fail_unless (csource != NULL); - fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong", - GST_CONTROL_SOURCE (csource))); - - /* set interpolation mode */ - fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, - GST_INTERPOLATE_TRIGGER)); - - g_value_init (&val_ulong, G_TYPE_ULONG); - fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), - 0 * GST_SECOND, &val_ulong)); - - /* set control values */ - g_value_set_ulong (&val_ulong, 50); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); - fail_unless (res, NULL); - g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); - fail_unless (res, NULL); - - - /* now pull in values for some timestamps */ - fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), - 0 * GST_SECOND, &val_ulong)); - gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND); - fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); - fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), - 1 * GST_SECOND, &val_ulong)); - gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND); - fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0); - fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), - 2 * GST_SECOND, &val_ulong)); - gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND); - fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100); - - g_object_unref (csource); - gst_object_unref (elem); -} - -GST_END_TEST; - /* test timed value handling with linear interpolation */ GST_START_TEST (controller_interpolate_linear) { @@ -616,14 +580,12 @@ GST_START_TEST (controller_interpolate_linear) /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_object_unref (csource); @@ -665,24 +627,20 @@ GST_START_TEST (controller_interpolate_cubic) /* set control values */ g_value_init (&val_double, G_TYPE_DOUBLE); g_value_set_double (&val_double, 0.0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_double); fail_unless (res, NULL); g_value_set_double (&val_double, 5.0); - res = - gst_interpolation_control_source_set (csource, 1 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND, &val_double); fail_unless (res, NULL); g_value_set_double (&val_double, 2.0); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_double); fail_unless (res, NULL); g_value_set_double (&val_double, 8.0); - res = - gst_interpolation_control_source_set (csource, 4 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 4 * GST_SECOND, &val_double); fail_unless (res, NULL); g_object_unref (csource); @@ -731,14 +689,12 @@ GST_START_TEST (controller_interpolate_cubic_too_few_cp) /* set 2 control values */ g_value_init (&val_double, G_TYPE_DOUBLE); g_value_set_double (&val_double, 0.0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_double); fail_unless (res, NULL); g_value_set_double (&val_double, 4.0); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_double); fail_unless (res, NULL); g_object_unref (csource); @@ -809,19 +765,16 @@ GST_START_TEST (controller_interpolation_unset) /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 1 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 50); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); /* verify values */ @@ -833,7 +786,8 @@ GST_START_TEST (controller_interpolation_unset) fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); /* unset second */ - res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND); + res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND); fail_unless (res, NULL); /* verify value again */ @@ -843,12 +797,14 @@ GST_START_TEST (controller_interpolation_unset) fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); /* unset all values, reset and try to unset again */ - fail_unless (gst_interpolation_control_source_unset (csource, - 0 * GST_SECOND)); - fail_unless (gst_interpolation_control_source_unset (csource, - 2 * GST_SECOND)); - gst_interpolation_control_source_unset_all (csource); - fail_if (gst_interpolation_control_source_unset (csource, 2 * GST_SECOND)); + fail_unless (gst_timed_value_control_source_unset ((GstTimedValueControlSource + *) csource, 0 * GST_SECOND)); + fail_unless (gst_timed_value_control_source_unset ((GstTimedValueControlSource + *) csource, 2 * GST_SECOND)); + gst_timed_value_control_source_unset_all ((GstTimedValueControlSource *) + csource); + fail_if (gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND)); g_object_unref (csource); @@ -881,14 +837,12 @@ GST_START_TEST (controller_interpolation_unset_all) /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 1 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND, &val_ulong); fail_unless (res, NULL); /* verify values */ @@ -898,7 +852,8 @@ GST_START_TEST (controller_interpolation_unset_all) fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100); /* unset all */ - gst_interpolation_control_source_unset_all (csource); + gst_timed_value_control_source_unset_all ((GstTimedValueControlSource *) + csource); g_object_unref (csource); @@ -936,14 +891,12 @@ GST_START_TEST (controller_interpolation_linear_value_array) /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); /* now pull in values for some timestamps */ @@ -987,14 +940,12 @@ GST_START_TEST (controller_interpolation_linear_invalid_values) /* set control values */ g_value_init (&val_float, G_TYPE_FLOAT); g_value_set_float (&val_float, 200.0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_float); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_float); fail_unless (res, NULL); g_value_set_float (&val_float, -200.0); - res = - gst_interpolation_control_source_set (csource, 4 * GST_SECOND, - &val_float); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 4 * GST_SECOND, &val_float); fail_unless (res, NULL); g_object_unref (csource); @@ -1056,14 +1007,12 @@ GST_START_TEST (controller_interpolation_linear_default_values) /* set control values */ g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 1 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 3 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 3 * GST_SECOND, &val_ulong); fail_unless (res, NULL); /* now pull in values for some timestamps */ @@ -1079,20 +1028,20 @@ GST_START_TEST (controller_interpolation_linear_default_values) /* set control values */ g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); /* unset the old ones */ - res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND); + res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 1 * GST_SECOND); fail_unless (res, NULL); - res = gst_interpolation_control_source_unset (csource, 3 * GST_SECOND); + res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 3 * GST_SECOND); fail_unless (res, NULL); /* now pull in values for some timestamps */ @@ -1143,14 +1092,12 @@ GST_START_TEST (controller_interpolate_linear_disabled) /* set control values */ g_value_init (&val_ulong, G_TYPE_ULONG); g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); g_object_unref (csource); @@ -1158,14 +1105,12 @@ GST_START_TEST (controller_interpolate_linear_disabled) /* set control values */ g_value_init (&val_double, G_TYPE_DOUBLE); g_value_set_double (&val_double, 2.0); - res = - gst_interpolation_control_source_set (csource2, 0 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource2, 0 * GST_SECOND, &val_double); fail_unless (res, NULL); g_value_set_double (&val_double, 4.0); - res = - gst_interpolation_control_source_set (csource2, 2 * GST_SECOND, - &val_double); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource2, 2 * GST_SECOND, &val_double); fail_unless (res, NULL); g_object_unref (G_OBJECT (csource2)); @@ -1289,11 +1234,13 @@ GST_START_TEST (controller_interpolation_set_from_list) list = g_slist_append (list, tval); - fail_if (gst_interpolation_control_source_set_from_list (csource, list)); + fail_if (gst_timed_value_control_source_set_from_list ( + (GstTimedValueControlSource *) csource, list)); /* try again with a valid stamp, should work now */ tval->timestamp = 0; - fail_unless (gst_interpolation_control_source_set_from_list (csource, list)); + fail_unless (gst_timed_value_control_source_set_from_list ( + (GstTimedValueControlSource *) csource, list)); g_object_unref (csource); @@ -1306,6 +1253,119 @@ GST_START_TEST (controller_interpolation_set_from_list) GST_END_TEST; + +/* test linear interpolation for ts < first control point */ +GST_START_TEST (controller_interpolate_linear_before_ts0) +{ + GstInterpolationControlSource *csource; + GstElement *elem; + gboolean res; + GValue val_ulong = { 0, }; + + elem = gst_element_factory_make ("testmonosource", "test_source"); + + /* Get interpolation control source */ + csource = gst_interpolation_control_source_new (); + + fail_unless (csource != NULL); + fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong", + GST_CONTROL_SOURCE (csource))); + + /* set interpolation mode */ + fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, + GST_INTERPOLATE_LINEAR)); + + /* set control values */ + g_value_init (&val_ulong, G_TYPE_ULONG); + g_value_set_ulong (&val_ulong, 100); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); + fail_unless (res, NULL); + g_value_set_ulong (&val_ulong, 0); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 4 * GST_SECOND, &val_ulong); + fail_unless (res, NULL); + + g_object_unref (csource); + + /* now pull in values for some timestamps after first control point */ + gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100); + gst_object_sync_values (GST_OBJECT (elem), 3 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); + gst_object_sync_values (GST_OBJECT (elem), 4 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0); + + /* now pull in values for some timestamps before first control point */ + gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); + gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0); + + gst_object_unref (elem); +} + +GST_END_TEST; + +/* test control-point handling in interpolation control source */ +GST_START_TEST (controller_interpolation_cp_count) +{ + GstInterpolationControlSource *csource; + GstElement *elem; + gboolean res; + GValue val_ulong = { 0, }; + + elem = gst_element_factory_make ("testmonosource", "test_source"); + + /* Get interpolation control source */ + csource = gst_interpolation_control_source_new (); + + fail_unless (csource != NULL); + fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong", + GST_CONTROL_SOURCE (csource))); + + /* set interpolation mode */ + fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, + GST_INTERPOLATE_NONE)); + + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 0); + + /* set control values */ + g_value_init (&val_ulong, G_TYPE_ULONG); + g_value_set_ulong (&val_ulong, 0); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); + fail_unless (res, NULL); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 1); + g_value_set_ulong (&val_ulong, 100); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); + fail_unless (res, NULL); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 2); + + /* now unset control values */ + res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND); + fail_unless (res, NULL); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 1); + + res = gst_timed_value_control_source_unset ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND); + fail_unless (res, NULL); + fail_unless (gst_timed_value_control_source_get_count ( + (GstTimedValueControlSource *) csource) == 0); + + g_object_unref (csource); + + gst_object_unref (elem); +} + +GST_END_TEST; + /* test lfo control source with sine waveform */ GST_START_TEST (controller_lfo_sine) { @@ -1720,28 +1780,10 @@ GST_START_TEST (controller_lfo_none) GST_END_TEST; -/* tests if we can run helper methods against any GObject */ -GST_START_TEST (controller_helper_any_gobject) -{ - GstElement *elem; - gboolean res; - - elem = gst_element_factory_make ("bin", "test_elem"); - - /* that element is not controllable */ - res = gst_object_sync_values (GST_OBJECT (elem), 0LL); - /* Syncing should still succeed as there's nothing to sync */ - fail_unless (res == TRUE, NULL); - - gst_object_unref (elem); -} - -GST_END_TEST; - -/* test linear interpolation for ts < first control point */ -GST_START_TEST (controller_interpolate_linear_before_ts0) +/* test timed value handling in trigger mode */ +GST_START_TEST (controller_trigger_exact) { - GstInterpolationControlSource *csource; + GstTriggerControlSource *csource; GstElement *elem; gboolean res; GValue val_ulong = { 0, }; @@ -1749,54 +1791,50 @@ GST_START_TEST (controller_interpolate_linear_before_ts0) elem = gst_element_factory_make ("testmonosource", "test_source"); /* Get interpolation control source */ - csource = gst_interpolation_control_source_new (); + csource = gst_trigger_control_source_new (); fail_unless (csource != NULL); fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong", GST_CONTROL_SOURCE (csource))); - /* set interpolation mode */ - fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, - GST_INTERPOLATE_LINEAR)); + g_value_init (&val_ulong, G_TYPE_ULONG); + fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), + 0 * GST_SECOND, &val_ulong)); /* set control values */ - g_value_init (&val_ulong, G_TYPE_ULONG); - g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + g_value_set_ulong (&val_ulong, 50); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); - g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 4 * GST_SECOND, - &val_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_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); + /* 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); - 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 */ + 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, 50); - gst_object_sync_values (GST_OBJECT (elem), 0 * 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 control-point handling in interpolation control source */ -GST_START_TEST (controller_interpolation_cp_count) +GST_START_TEST (controller_trigger_tolerance) { - GstInterpolationControlSource *csource; + GstTriggerControlSource *csource; GstElement *elem; gboolean res; GValue val_ulong = { 0, }; @@ -1804,44 +1842,42 @@ GST_START_TEST (controller_interpolation_cp_count) elem = gst_element_factory_make ("testmonosource", "test_source"); /* Get interpolation control source */ - csource = gst_interpolation_control_source_new (); + csource = gst_trigger_control_source_new (); fail_unless (csource != NULL); fail_unless (gst_object_set_control_source (GST_OBJECT (elem), "ulong", GST_CONTROL_SOURCE (csource))); - /* set interpolation mode */ - fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource, - GST_INTERPOLATE_NONE)); + g_object_set (csource, "tolerance", G_GINT64_CONSTANT (10), NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 0); + g_value_init (&val_ulong, G_TYPE_ULONG); + fail_if (gst_control_source_get_value (GST_CONTROL_SOURCE (csource), + 0 * GST_SECOND, &val_ulong)); /* set control values */ - g_value_init (&val_ulong, G_TYPE_ULONG); - g_value_set_ulong (&val_ulong, 0); - res = - gst_interpolation_control_source_set (csource, 0 * GST_SECOND, - &val_ulong); + g_value_set_ulong (&val_ulong, 50); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 0 * GST_SECOND, &val_ulong); fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 1); g_value_set_ulong (&val_ulong, 100); - res = - gst_interpolation_control_source_set (csource, 2 * GST_SECOND, - &val_ulong); + res = gst_timed_value_control_source_set ((GstTimedValueControlSource *) + csource, 2 * GST_SECOND, &val_ulong); fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 2); - /* now unset control values */ - res = gst_interpolation_control_source_unset (csource, 2 * GST_SECOND); - fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 1); - res = gst_interpolation_control_source_unset (csource, 0 * GST_SECOND); - fail_unless (res, NULL); - fail_unless (gst_interpolation_control_source_get_count (csource) == 0); + /* now pull in values for some timestamps */ + gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); + gst_object_sync_values (GST_OBJECT (elem), 0 * GST_SECOND + 5); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 50); + gst_object_sync_values (GST_OBJECT (elem), 1 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 0); + gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND - 5); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100); + gst_object_sync_values (GST_OBJECT (elem), 2 * GST_SECOND); + fail_unless_equals_int (GST_TEST_MONO_SOURCE (elem)->val_ulong, 100); g_object_unref (csource); - gst_object_unref (elem); } @@ -1863,11 +1899,11 @@ gst_controller_suite (void) tcase_add_test (tc, controller_new_okay1); tcase_add_test (tc, controller_new_okay2); tcase_add_test (tc, controller_param_twice); + tcase_add_test (tc, controller_any_gobject); tcase_add_test (tc, controller_controlsource_refcounts); tcase_add_test (tc, controller_controlsource_empty1); tcase_add_test (tc, controller_controlsource_empty2); tcase_add_test (tc, controller_interpolate_none); - tcase_add_test (tc, controller_interpolate_trigger); tcase_add_test (tc, controller_interpolate_linear); tcase_add_test (tc, controller_interpolate_cubic); tcase_add_test (tc, controller_interpolate_cubic_too_few_cp); @@ -1879,6 +1915,8 @@ gst_controller_suite (void) tcase_add_test (tc, controller_interpolation_linear_default_values); tcase_add_test (tc, controller_interpolate_linear_disabled); tcase_add_test (tc, controller_interpolation_set_from_list); + tcase_add_test (tc, controller_interpolate_linear_before_ts0); + tcase_add_test (tc, controller_interpolation_cp_count); tcase_add_test (tc, controller_lfo_sine); tcase_add_test (tc, controller_lfo_sine_timeshift); tcase_add_test (tc, controller_lfo_square); @@ -1886,9 +1924,8 @@ gst_controller_suite (void) tcase_add_test (tc, controller_lfo_rsaw); tcase_add_test (tc, controller_lfo_triangle); tcase_add_test (tc, controller_lfo_none); - tcase_add_test (tc, controller_helper_any_gobject); - tcase_add_test (tc, controller_interpolate_linear_before_ts0); - tcase_add_test (tc, controller_interpolation_cp_count); + tcase_add_test (tc, controller_trigger_exact); + tcase_add_test (tc, controller_trigger_tolerance); return s; } diff --git a/tests/examples/controller/audio-example.c b/tests/examples/controller/audio-example.c index 76805b186..c0acba6f5 100644 --- a/tests/examples/controller/audio-example.c +++ b/tests/examples/controller/audio-example.c @@ -66,18 +66,23 @@ main (gint argc, gchar ** argv) /* set control values */ g_value_init (&vol, G_TYPE_DOUBLE); g_value_set_double (&vol, 0.0); - gst_interpolation_control_source_set (csource1, 0 * GST_SECOND, &vol); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource1, + 0 * GST_SECOND, &vol); g_value_set_double (&vol, 1.0); - gst_interpolation_control_source_set (csource1, 5 * GST_SECOND, &vol); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource1, + 5 * GST_SECOND, &vol); g_object_unref (csource1); g_value_set_double (&vol, 220.0); - gst_interpolation_control_source_set (csource2, 0 * GST_SECOND, &vol); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2, + 0 * GST_SECOND, &vol); g_value_set_double (&vol, 3520.0); - gst_interpolation_control_source_set (csource2, 3 * GST_SECOND, &vol); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2, + 3 * GST_SECOND, &vol); g_value_set_double (&vol, 440.0); - gst_interpolation_control_source_set (csource2, 6 * GST_SECOND, &vol); + gst_timed_value_control_source_set ((GstTimedValueControlSource *) csource2, + 6 * GST_SECOND, &vol); g_object_unref (csource2); |