libs/gst/controller/: API: Refactor GstController into the core controller which...
authorSebastian Dröge <slomo@circular-chaos.org>
Fri, 6 Jul 2007 21:50:02 +0000 (21:50 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Fri, 6 Jul 2007 21:50:02 +0000 (21:50 +0000)
Original commit message from CVS:
Reviewed by: Stefan Kost <ensonic@users.sf.net>
* libs/gst/controller/Makefile.am:
* libs/gst/controller/gstcontroller.c:
(gst_controlled_property_add_interpolation_control_source),
(gst_controlled_property_new), (gst_controlled_property_free),
(gst_controller_find_controlled_property),
(gst_controller_new_valist), (gst_controller_new_list),
(gst_controller_new), (gst_controller_remove_properties_valist),
(gst_controller_remove_properties_list),
(gst_controller_remove_properties),
(gst_controller_set_property_disabled),
(gst_controller_set_disabled), (gst_controller_set_control_source),
(gst_controller_get_control_source), (gst_controller_get),
(gst_controller_sync_values), (gst_controller_get_value_array),
(_gst_controller_dispose), (gst_controller_get_type),
(gst_controlled_property_set_interpolation_mode),
(gst_controller_set), (gst_controller_set_from_list),
(gst_controller_unset), (gst_controller_unset_all),
(gst_controller_get_all), (gst_controller_set_interpolation_mode):
* libs/gst/controller/gstcontroller.h:
* libs/gst/controller/gstcontrollerprivate.h:
* libs/gst/controller/gstcontrolsource.c:
(gst_control_source_class_init), (gst_control_source_init),
(gst_control_source_get_value),
(gst_control_source_get_value_array), (gst_control_source_bind):
* libs/gst/controller/gstcontrolsource.h:
* libs/gst/controller/gsthelper.c: (gst_object_set_control_source),
(gst_object_get_control_source):
* libs/gst/controller/gstinterpolation.c:
(gst_interpolation_control_source_find_control_point_node),
(gst_interpolation_control_source_get_first_value),
(_interpolate_none_get), (interpolate_none_get),
(interpolate_none_get_boolean_value_array),
(interpolate_none_get_enum_value_array),
(interpolate_none_get_string_value_array),
(_interpolate_trigger_get), (interpolate_trigger_get),
(interpolate_trigger_get_boolean_value_array),
(interpolate_trigger_get_enum_value_array),
(interpolate_trigger_get_string_value_array):
* libs/gst/controller/gstinterpolationcontrolsource.c:
(gst_control_point_free), (gst_interpolation_control_source_reset),
(gst_interpolation_control_source_new),
(gst_interpolation_control_source_set_interpolation_mode),
(gst_interpolation_control_source_bind),
(gst_control_point_compare), (gst_control_point_find),
(gst_interpolation_control_source_set_internal),
(gst_interpolation_control_source_set),
(gst_interpolation_control_source_set_from_list),
(gst_interpolation_control_source_unset),
(gst_interpolation_control_source_unset_all),
(gst_interpolation_control_source_get_all),
(gst_interpolation_control_source_get_count),
(gst_interpolation_control_source_init),
(gst_interpolation_control_source_finalize),
(gst_interpolation_control_source_dispose),
(gst_interpolation_control_source_class_init):
* libs/gst/controller/gstinterpolationcontrolsource.h:
* libs/gst/controller/gstinterpolationcontrolsourceprivate.h:
API: Refactor GstController into the core controller which can take
a GstControlSource for providing actual values for timestamps.
Implement a interpolation control source and use this for backward
compatibility, deprecate a bunch of functions that are now handled
by GstControlSource or GstInterpolationControlSource.
Make it possible to disable the controller completely or only for
specific properties. Fixes #450711.
* docs/libs/gstreamer-libs-docs.sgml:
* docs/libs/gstreamer-libs-sections.txt:
* docs/libs/gstreamer-libs.types:
Add new functions and classes to the docs.
* tests/check/libs/controller.c: (GST_START_TEST),
(gst_controller_suite):
* tests/examples/controller/audio-example.c: (main):
Port unit test and example to the new API and add some new
unit tests.

17 files changed:
ChangeLog
docs/libs/gstreamer-libs-docs.sgml
docs/libs/gstreamer-libs-sections.txt
docs/libs/gstreamer-libs.types
libs/gst/controller/Makefile.am
libs/gst/controller/gstcontroller.c
libs/gst/controller/gstcontroller.h
libs/gst/controller/gstcontrollerprivate.h
libs/gst/controller/gstcontrolsource.c [new file with mode: 0644]
libs/gst/controller/gstcontrolsource.h [new file with mode: 0644]
libs/gst/controller/gsthelper.c
libs/gst/controller/gstinterpolation.c
libs/gst/controller/gstinterpolationcontrolsource.c [new file with mode: 0644]
libs/gst/controller/gstinterpolationcontrolsource.h [new file with mode: 0644]
libs/gst/controller/gstinterpolationcontrolsourceprivate.h [new file with mode: 0644]
tests/check/libs/controller.c
tests/examples/controller/audio-example.c

index a602e91..ac4709d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+2007-07-06  Sebastian Dröge  <slomo@circular-chaos.org>
+
+       Reviewed by: Stefan Kost <ensonic@users.sf.net>
+
+       * libs/gst/controller/Makefile.am:
+       * libs/gst/controller/gstcontroller.c:
+       (gst_controlled_property_add_interpolation_control_source),
+       (gst_controlled_property_new), (gst_controlled_property_free),
+       (gst_controller_find_controlled_property),
+       (gst_controller_new_valist), (gst_controller_new_list),
+       (gst_controller_new), (gst_controller_remove_properties_valist),
+       (gst_controller_remove_properties_list),
+       (gst_controller_remove_properties),
+       (gst_controller_set_property_disabled),
+       (gst_controller_set_disabled), (gst_controller_set_control_source),
+       (gst_controller_get_control_source), (gst_controller_get),
+       (gst_controller_sync_values), (gst_controller_get_value_array),
+       (_gst_controller_dispose), (gst_controller_get_type),
+       (gst_controlled_property_set_interpolation_mode),
+       (gst_controller_set), (gst_controller_set_from_list),
+       (gst_controller_unset), (gst_controller_unset_all),
+       (gst_controller_get_all), (gst_controller_set_interpolation_mode):
+       * libs/gst/controller/gstcontroller.h:
+       * libs/gst/controller/gstcontrollerprivate.h:
+       * libs/gst/controller/gstcontrolsource.c:
+       (gst_control_source_class_init), (gst_control_source_init),
+       (gst_control_source_get_value),
+       (gst_control_source_get_value_array), (gst_control_source_bind):
+       * libs/gst/controller/gstcontrolsource.h:
+       * libs/gst/controller/gsthelper.c: (gst_object_set_control_source),
+       (gst_object_get_control_source):
+       * libs/gst/controller/gstinterpolation.c:
+       (gst_interpolation_control_source_find_control_point_node),
+       (gst_interpolation_control_source_get_first_value),
+       (_interpolate_none_get), (interpolate_none_get),
+       (interpolate_none_get_boolean_value_array),
+       (interpolate_none_get_enum_value_array),
+       (interpolate_none_get_string_value_array),
+       (_interpolate_trigger_get), (interpolate_trigger_get),
+       (interpolate_trigger_get_boolean_value_array),
+       (interpolate_trigger_get_enum_value_array),
+       (interpolate_trigger_get_string_value_array):
+       * libs/gst/controller/gstinterpolationcontrolsource.c:
+       (gst_control_point_free), (gst_interpolation_control_source_reset),
+       (gst_interpolation_control_source_new),
+       (gst_interpolation_control_source_set_interpolation_mode),
+       (gst_interpolation_control_source_bind),
+       (gst_control_point_compare), (gst_control_point_find),
+       (gst_interpolation_control_source_set_internal),
+       (gst_interpolation_control_source_set),
+       (gst_interpolation_control_source_set_from_list),
+       (gst_interpolation_control_source_unset),
+       (gst_interpolation_control_source_unset_all),
+       (gst_interpolation_control_source_get_all),
+       (gst_interpolation_control_source_get_count),
+       (gst_interpolation_control_source_init),
+       (gst_interpolation_control_source_finalize),
+       (gst_interpolation_control_source_dispose),
+       (gst_interpolation_control_source_class_init):
+       * libs/gst/controller/gstinterpolationcontrolsource.h:
+       * libs/gst/controller/gstinterpolationcontrolsourceprivate.h:
+       API: Refactor GstController into the core controller which can take
+       a GstControlSource for providing actual values for timestamps.
+       Implement a interpolation control source and use this for backward
+       compatibility, deprecate a bunch of functions that are now handled
+       by GstControlSource or GstInterpolationControlSource.
+       Make it possible to disable the controller completely or only for
+       specific properties. Fixes #450711.
+       * docs/libs/gstreamer-libs-docs.sgml:
+       * docs/libs/gstreamer-libs-sections.txt:
+       * docs/libs/gstreamer-libs.types:
+       Add new functions and classes to the docs.
+       * tests/check/libs/controller.c: (GST_START_TEST),
+       (gst_controller_suite):
+       * tests/examples/controller/audio-example.c: (main):
+       Port unit test and example to the new API and add some new
+       unit tests.
+
 2007-07-05  Wim Taymans  <wim.taymans@gmail.com>
 
        Patch by: Mark Nauwelaerts <manauw at skynet be>
index 37e6cd8..081cb81 100644 (file)
@@ -17,6 +17,8 @@
 <!ENTITY GstCheckBufferStraw SYSTEM "xml/gstcheckbufferstraw.xml">
 
 <!ENTITY GstController SYSTEM "xml/gstcontroller.xml">
+<!ENTITY GstControlSource SYSTEM "xml/gstcontrolsource.xml">
+<!ENTITY GstInterpolationControlSource SYSTEM "xml/gstinterpolationcontrolsource.xml">
 <!ENTITY GstControllerGObject SYSTEM "xml/gstcontrollergobject.xml">
 <!ENTITY GstDataProtocol SYSTEM "xml/gstdataprotocol.xml">
 
@@ -66,6 +68,8 @@
     <chapter id="gstreamer-control">
       <title>GStreamer Dynamic Parameter Control</title>
       &GstController;
+      &GstControlSource;
+      &GstInterpolationControlSource;
       &GstControllerGObject;
     </chapter>
 
index ca4f1ad..85efa35 100644 (file)
@@ -59,7 +59,6 @@ gst_dp_version_get_type
 <TITLE>GstController</TITLE>
 <INCLUDE>gst/controller/gstcontroller.h</INCLUDE>
 GstController
-GstInterpolateMode
 gst_controller_init
 gst_controller_new
 gst_controller_new_list
@@ -67,16 +66,20 @@ gst_controller_new_valist
 gst_controller_remove_properties
 gst_controller_remove_properties_list
 gst_controller_remove_properties_valist
+gst_controller_set_disabled
+gst_controller_set_property_disabled
+gst_controller_suggest_next_sync
+gst_controller_sync_values
+gst_controller_get_control_source
+gst_controller_set_control_source
+gst_controller_get
+gst_controller_get_value_arrays
+gst_controller_get_value_array
 gst_controller_set
 gst_controller_set_from_list
 gst_controller_unset
 gst_controller_unset_all
-gst_controller_get
 gst_controller_get_all
-gst_controller_suggest_next_sync
-gst_controller_sync_values
-gst_controller_get_value_arrays
-gst_controller_get_value_array
 gst_controller_set_interpolation_mode
 GST_PARAM_CONTROLLABLE
 <SUBSECTION Standard>
@@ -89,13 +92,63 @@ GST_IS_CONTROLLER_CLASS
 GST_CONTROLLER_GET_CLASS
 GST_TYPE_CONTROLLER
 <SUBSECTION Private>
-InterpolateGet
-InterpolateGetValueArray
 GST_CONTROLLED_PROPERTY
 gst_controller_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gstcontrolsource</FILE>
+<TITLE>GstControlSource</TITLE>
+<INCLUDE>libs/controller/gstcontrolsource.h</INCLUDE>
+GstControlSource
+GstControlSourceClass
+GstControlSourceBind
+GstControlSourceGetValue
+GstControlSourceGetValueArray
+GstTimedValue
+GstValueArray
+gst_control_source_bind
+gst_control_source_get_value
+gst_control_source_get_value_array
+<SUBSECTION Standard>
+GST_CONTROL_SOURCE
+GST_IS_CONTROL_SOURCE
+GST_CONTROL_SOURCE_CLASS
+GST_IS_CONTROL_SOURCE_CLASS
+GST_CONTROL_SOURCE_GET_CLASS
+GST_TYPE_CONTROL_SOURCE
+<SUBSECTION Private>
+gst_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
+<SUBSECTION Private>
+gst_interpolation_control_source_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gstcontrollergobject</FILE>
 <TITLE>GstControllerGObject</TITLE>
 <INCLUDE>libs/controller/gstcontroller.h</INCLUDE>
@@ -105,6 +158,8 @@ gst_object_get_controller
 gst_object_set_controller
 gst_object_suggest_next_sync
 gst_object_sync_values
+gst_object_get_control_source
+gst_object_set_control_source
 gst_object_get_value_arrays
 gst_object_get_value_array
 gst_object_get_control_rate
@@ -113,7 +168,6 @@ gst_object_set_control_rate
 <SUBSECTION Private>
 </SECTION>
 
-
 # base classes
 
 <SECTION>
index c44b021..6730d77 100644 (file)
@@ -2,6 +2,10 @@
 
 #include <gst/controller/gstcontroller.h>
 gst_controller_get_type
+#include <gst/controller/gstcontrolsource.h>
+gst_control_source_get_type
+#include <gst/controller/gstinterpolationcontrolsource.h>
+gst_interpolation_control_source_get_type
 
 #include <gst/base/gstadapter.h>
 gst_adapter_get_type
index 1c0ccda..4aeded6 100644 (file)
@@ -2,14 +2,21 @@ lib_LTLIBRARIES = libgstcontroller-@GST_MAJORMINOR@.la
 
 libgstcontroller_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller
 libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \
-       gstcontroller.h
-noinst_HEADERS = gstcontrollerprivate.h
+       gstcontroller.h \
+       gstcontrolsource.h \
+       gstinterpolationcontrolsource.h
+
+noinst_HEADERS = \
+       gstcontrollerprivate.h \
+       gstinterpolationcontrolsourceprivate.h
 
 libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \
        lib.c \
        gstcontroller.c \
        gstinterpolation.c \
-       gsthelper.c
+       gsthelper.c \
+       gstcontrolsource.c \
+       gstinterpolationcontrolsource.c
 
 libgstcontroller_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
 libgstcontroller_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS)
index f6b94a1..3df8f97 100644 (file)
  *     controller = g_object_control_properties(object, "prop1", "prop2",...);
  *   </para></listitem>
  *   <listitem><para>
- *     set how the controller will smooth inbetween values.
- *     gst_controller_set_interpolation_mode(controller,"prop1",mode);
+ *     Get a #GstControlSource for the property and set it up.
+ *     csource = gst_interpolation_control_source_new ();
+ *     gst_interpolation_control_source_set_interpolation_mode(csource, mode);
+ *     gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
+ *     gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
  *   </para></listitem>
  *   <listitem><para>
- *     set key values
- *     gst_controller_set (controller, "prop1" ,0 * GST_SECOND, value1);
- *     gst_controller_set (controller, "prop1" ,1 * GST_SECOND, value2);
+ *     Set the #GstControlSource in the controller.
+ *     gst_controller_set_control_source (controller, "prop1", csource);
  *   </para></listitem>
  *   <listitem><para>
  *     start your pipeline
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
-#include "gstcontrollerprivate.h"
+
 #include "gstcontroller.h"
+#include "gstcontrollerprivate.h"
+#include "gstcontrolsource.h"
+#include "gstinterpolationcontrolsource.h"
 
 #define GST_CAT_DEFAULT gst_controller_debug
 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
@@ -91,188 +96,20 @@ struct _GstControllerPrivate
   GstClockTime last_sync;
 };
 
-/* imports from gst-interpolation.c */
-
-extern GList
-    * gst_controlled_property_find_control_point_node (GstControlledProperty *
-    prop, GstClockTime timestamp);
-extern GstInterpolateMethod *interpolation_methods[];
-extern guint num_interpolation_methods;
-
-/* callbacks */
-
-void
-on_object_controlled_property_changed (const GObject * object, GParamSpec * arg,
-    gpointer user_data)
-{
-  GstControlledProperty *prop = GST_CONTROLLED_PROPERTY (user_data);
-  GstController *ctrl;
-
-  GST_LOG ("notify for '%s'", prop->name);
-
-  ctrl = g_object_get_qdata (G_OBJECT (object), __gst_controller_key);
-  g_return_if_fail (ctrl);
-
-  if (g_mutex_trylock (ctrl->lock)) {
-    if (!G_IS_VALUE (&prop->live_value.value)) {
-      g_value_init (&prop->live_value.value, prop->type);
-    }
-    g_object_get_property (G_OBJECT (object), prop->name,
-        &prop->live_value.value);
-    prop->live_value.timestamp = prop->last_value.timestamp;
-    g_mutex_unlock (ctrl->lock);
-    GST_DEBUG ("-> is live update : ts=%" G_GUINT64_FORMAT,
-        prop->live_value.timestamp);
-  }
-}
-
 /* helper */
 
-/*
- * 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));
-/* this does not produce an gint :(
-  return ((ct1 - ct2));
-*/
-}
-
-/*
- * 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));
-/* this does not produce an gint :(
-  return ((ct1 - ct2));
-*/
-}
-
-/*
- * gst_controlled_property_set_interpolation_mode:
- * @self: the controlled property object to change
- * @mode: the new interpolation mode
- *
- * Sets the given Interpolation mode for the controlled property and activates
- * the respective interpolation hooks.
- *
- * Returns: %TRUE for success
- */
-static gboolean
-gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
-    GstInterpolateMode mode)
-{
-  gboolean res = TRUE;
-
-  if (mode >= num_interpolation_methods || interpolation_methods[mode] == NULL) {
-    GST_WARNING ("interpolation mode %d invalid or not implemented yet", mode);
-    return FALSE;
-  }
-
-  self->interpolation = mode;
-  if (mode != GST_INTERPOLATE_USER) {
-    switch (self->base) {
-      case G_TYPE_INT:
-        self->get = interpolation_methods[mode]->get_int;
-        self->get_value_array =
-            interpolation_methods[mode]->get_int_value_array;
-        break;
-      case G_TYPE_UINT:
-        self->get = interpolation_methods[mode]->get_uint;
-        self->get_value_array =
-            interpolation_methods[mode]->get_uint_value_array;
-        break;
-      case G_TYPE_LONG:
-        self->get = interpolation_methods[mode]->get_long;
-        self->get_value_array =
-            interpolation_methods[mode]->get_long_value_array;
-        break;
-      case G_TYPE_ULONG:
-        self->get = interpolation_methods[mode]->get_ulong;
-        self->get_value_array =
-            interpolation_methods[mode]->get_ulong_value_array;
-        break;
-      case G_TYPE_FLOAT:
-        self->get = interpolation_methods[mode]->get_float;
-        self->get_value_array =
-            interpolation_methods[mode]->get_float_value_array;
-        break;
-      case G_TYPE_DOUBLE:
-        self->get = interpolation_methods[mode]->get_double;
-        self->get_value_array =
-            interpolation_methods[mode]->get_double_value_array;
-        break;
-      case G_TYPE_BOOLEAN:
-        self->get = interpolation_methods[mode]->get_boolean;
-        self->get_value_array =
-            interpolation_methods[mode]->get_boolean_value_array;
-        break;
-      case G_TYPE_ENUM:
-        self->get = interpolation_methods[mode]->get_enum;
-        self->get_value_array =
-            interpolation_methods[mode]->get_enum_value_array;
-        break;
-      case G_TYPE_STRING:
-        self->get = interpolation_methods[mode]->get_string;
-        self->get_value_array =
-            interpolation_methods[mode]->get_string_value_array;
-        break;
-      default:
-        self->get = NULL;
-        self->get_value_array = NULL;
-    }
-    if (!self->get || !self->get_value_array) {
-      GST_WARNING ("incomplete implementation for type %lu/%lu:'%s'/'%s'",
-          self->type, self->base,
-          g_type_name (self->type), g_type_name (self->base));
-      res = FALSE;
-    }
-    if (mode == GST_INTERPOLATE_QUADRATIC) {
-      GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
-          "interpolation mode");
-    }
-  } else {
-    /* TODO shouldn't this also get a GstInterpolateMethod *user_method
-       for the case mode==GST_INTERPOLATE_USER
-     */
-    res = FALSE;
-  }
-
-  self->valid_cache = FALSE;
-
-  return (res);
-}
-
 static void
-gst_controlled_property_prepend_default (GstControlledProperty * prop)
+gst_controlled_property_add_interpolation_control_source (GstControlledProperty
+    * self)
 {
-  GstControlPoint *cp = g_new0 (GstControlPoint, 1);
-
-  cp->timestamp = 0;
-  g_value_init (&cp->value, prop->type);
-  g_value_copy (&prop->default_value, &cp->value);
-  prop->values = g_list_prepend (prop->values, cp);
-  prop->nvalues++;
+  GstControlSource *csource =
+      GST_CONTROL_SOURCE (gst_interpolation_control_source_new ());
+
+  GST_INFO
+      ("Adding a GstInterpolationControlSource because of backward compatibility");
+  g_return_if_fail (!self->csource);
+  gst_control_source_bind (GST_CONTROL_SOURCE (csource), self->pspec);
+  self->csource = csource;
 }
 
 /*
@@ -305,162 +142,19 @@ gst_controlled_property_new (GObject * object, const gchar * name)
     /* check if this param is not construct-only */
     g_return_val_if_fail (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY), NULL);
 
-    /* TODO do sanity checks
-       we don't control some pspec->value_type:
-       G_TYPE_PARAM_BOXED
-       G_TYPE_PARAM_ENUM
-       G_TYPE_PARAM_FLAGS
-       G_TYPE_PARAM_OBJECT
-       G_TYPE_PARAM_PARAM
-       G_TYPE_PARAM_POINTER
-       G_TYPE_PARAM_STRING
-     */
-
     if ((prop = g_new0 (GstControlledProperty, 1))) {
-      gchar *signal_name;
-      GType base;
-
-      prop->name = pspec->name; /* so we don't use the same mem twice */
-      prop->type = G_PARAM_SPEC_VALUE_TYPE (pspec);
-      /* get the fundamental base type */
-      prop->base = prop->type;
-      while ((base = g_type_parent (prop->base))) {
-        prop->base = base;
-      }
-      /* initialize mode specific accessor callbacks */
-      if (!gst_controlled_property_set_interpolation_mode (prop,
-              GST_INTERPOLATE_NONE))
-        goto Error;
-      /* prepare our gvalues */
-      g_value_init (&prop->default_value, prop->type);
-      g_value_init (&prop->result_value, prop->type);
-      g_value_init (&prop->last_value.value, prop->type);
-      switch (prop->base) {
-        case G_TYPE_INT:{
-          GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
-
-          g_value_set_int (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_int (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_int (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_UINT:{
-          GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
-
-          g_value_set_uint (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_uint (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_uint (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_LONG:{
-          GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
-
-          g_value_set_long (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_long (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_long (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_ULONG:{
-          GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
-
-          g_value_set_ulong (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_ulong (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_ulong (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_FLOAT:{
-          GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
-
-          g_value_set_float (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_float (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_float (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_DOUBLE:{
-          GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
-
-          g_value_set_double (&prop->default_value, tpspec->default_value);
-          g_value_init (&prop->min_value, prop->type);
-          g_value_set_double (&prop->min_value, tpspec->minimum);
-          g_value_init (&prop->max_value, prop->type);
-          g_value_set_double (&prop->max_value, tpspec->maximum);
-        }
-          break;
-        case G_TYPE_BOOLEAN:{
-          GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
-
-          g_value_set_boolean (&prop->default_value, tpspec->default_value);
-        }
-          break;
-        case G_TYPE_ENUM:{
-          GParamSpecEnum *tpspec = G_PARAM_SPEC_ENUM (pspec);
-
-          g_value_set_enum (&prop->default_value, tpspec->default_value);
-        }
-          break;
-        case G_TYPE_STRING:{
-          GParamSpecString *tpspec = G_PARAM_SPEC_STRING (pspec);
-
-          g_value_set_string (&prop->default_value, tpspec->default_value);
-        }
-          break;
-        default:
-          GST_WARNING ("incomplete implementation for paramspec type '%s'",
-              G_PARAM_SPEC_TYPE_NAME (pspec));
-      }
-
-      prop->valid_cache = FALSE;
-      prop->nvalues = 0;
-
-      /* Add a control point at timestamp 0 with the default value
-       * to make the life of interpolators easier. */
-      gst_controlled_property_prepend_default (prop);
-
-      signal_name = g_alloca (8 + 1 + strlen (name));
-      g_sprintf (signal_name, "notify::%s", name);
-      prop->notify_handler_id =
-          g_signal_connect (object, signal_name,
-          G_CALLBACK (on_object_controlled_property_changed), (gpointer) prop);
+      prop->pspec = pspec;
+      prop->name = pspec->name;
+      prop->disabled = FALSE;
     }
   } else {
     GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
         name);
   }
-  return (prop);
-Error:
-  if (prop)
-    g_free (prop);
-  return (NULL);
+  return prop;
 }
 
 /*
- * 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_free (cp);
-}
-
-/*
-
  * gst_controlled_property_free:
  * @prop: the object to free
  *
@@ -470,20 +164,8 @@ gst_control_point_free (GstControlPoint * cp)
 static void
 gst_controlled_property_free (GstControlledProperty * prop)
 {
-  g_list_foreach (prop->values, (GFunc) gst_control_point_free, NULL);
-  g_list_free (prop->values);
-
-  g_value_unset (&prop->default_value);
-  g_value_unset (&prop->result_value);
-  g_value_unset (&prop->last_value.value);
-  if (G_IS_VALUE (&prop->live_value.value))
-    g_value_unset (&prop->live_value.value);
-
-  if (G_IS_VALUE (&prop->min_value))
-    g_value_unset (&prop->min_value);
-  if (G_IS_VALUE (&prop->max_value))
-    g_value_unset (&prop->max_value);
-
+  if (prop->csource)
+    g_object_unref (prop->csource);
   g_free (prop);
 }
 
@@ -507,12 +189,12 @@ gst_controller_find_controlled_property (GstController * self,
   for (node = self->properties; node; node = g_list_next (node)) {
     prop = node->data;
     if (!strcmp (prop->name, name)) {
-      return (prop);
+      return prop;
     }
   }
   GST_DEBUG ("controller does not (yet) manage property '%s'", name);
 
-  return (NULL);
+  return NULL;
 }
 
 /* methods */
@@ -538,17 +220,6 @@ gst_controller_new_valist (GObject * object, va_list var_args)
 
   GST_INFO ("setting up a new controller");
 
-  /* TODO should this method check if the given object implements GstParent and
-     if so instantiate a GstParentController ?
-
-     BilboEd: This is too specific to be put here, don't we want
-     GstController to be as generic as possible ?
-
-     Ensonic: So we will have gst_parent_controller_new as well and maybe a
-     convinience function that automatically chooses the right one (how to name it)?
-     GstParent will be in core after all.
-   */
-
   self = g_object_get_qdata (object, __gst_controller_key);
   /* create GstControlledProperty for each property */
   while ((name = va_arg (var_args, gchar *))) {
@@ -585,7 +256,7 @@ gst_controller_new_valist (GObject * object, va_list var_args)
 
   if (self)
     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
-  return (self);
+  return self;
 }
 
 /**
@@ -646,7 +317,7 @@ gst_controller_new_list (GObject * object, GList * list)
 
   if (self)
     GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
-  return (self);
+  return self;
 }
 
 /**
@@ -670,7 +341,7 @@ gst_controller_new (GObject * object, ...)
   self = gst_controller_new_valist (object, var_args);
   va_end (var_args);
 
-  return (self);
+  return self;
 }
 
 /**
@@ -696,7 +367,7 @@ gst_controller_remove_properties_valist (GstController * self, va_list var_args)
     g_mutex_lock (self->lock);
     if ((prop = gst_controller_find_controlled_property (self, name))) {
       self->properties = g_list_remove (self->properties, prop);
-      g_signal_handler_disconnect (self->object, prop->notify_handler_id);
+      //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
       gst_controlled_property_free (prop);
     } else {
       res = FALSE;
@@ -704,7 +375,7 @@ gst_controller_remove_properties_valist (GstController * self, va_list var_args)
     g_mutex_unlock (self->lock);
   }
 
-  return (res);
+  return res;
 }
 
 /**
@@ -733,7 +404,7 @@ gst_controller_remove_properties_list (GstController * self, GList * list)
     g_mutex_lock (self->lock);
     if ((prop = gst_controller_find_controlled_property (self, name))) {
       self->properties = g_list_remove (self->properties, prop);
-      g_signal_handler_disconnect (self->object, prop->notify_handler_id);
+      //g_signal_handler_disconnect (self->object, prop->notify_handler_id);
       gst_controlled_property_free (prop);
     } else {
       res = FALSE;
@@ -741,7 +412,7 @@ gst_controller_remove_properties_list (GstController * self, GList * list)
     g_mutex_unlock (self->lock);
   }
 
-  return (res);
+  return res;
 }
 
 /**
@@ -765,210 +436,138 @@ gst_controller_remove_properties (GstController * self, ...)
   res = gst_controller_remove_properties_valist (self, var_args);
   va_end (var_args);
 
-  return (res);
-}
-
-static gboolean
-gst_controller_set_unlocked (GstController * self, GstControlledProperty * prop,
-    GstClockTime timestamp, GValue * value)
-{
-  gboolean res = FALSE;
-
-  if (G_VALUE_TYPE (value) == prop->type) {
-    GstControlPoint *cp;
-    GList *node;
-
-    /* check if a control point for the timestamp already exists */
-    if ((node = g_list_find_custom (prop->values, &timestamp,
-                gst_control_point_find))) {
-      cp = node->data;
-      g_value_reset (&cp->value);
-      g_value_copy (value, &cp->value);
-    } else {
-      /* create a new GstControlPoint */
-      cp = g_new0 (GstControlPoint, 1);
-      cp->timestamp = timestamp;
-      g_value_init (&cp->value, prop->type);
-      g_value_copy (value, &cp->value);
-      /* and sort it into the prop->values list */
-      prop->values =
-          g_list_insert_sorted (prop->values, cp, gst_control_point_compare);
-      prop->nvalues++;
-    }
-    prop->valid_cache = FALSE;
-    res = TRUE;
-  } else {
-    GST_WARNING ("incompatible value type for property '%s'", prop->name);
-  }
-
   return res;
 }
 
 /**
- * gst_controller_set:
- * @self: the controller object which handles the properties
- * @property_name: the name of the property to set
- * @timestamp: the time the control-change is schedules for
- * @value: the control-value
+ * gst_controller_set_property_disabled:
+ * @self: the #GstController which should be disabled
+ * @property_name: property to disable
+ * @disabled: boolean that specifies whether to disable the controller
+ * or not.
  *
- * Set the value of given controller-handled property at a certain time.
+ * This function is used to disable the #GstController on a property for
+ * some time, i.e. gst_controller_sync_values() will do nothing for the
+ * property.
  *
- * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
+ * Since: 0.10.14
  */
-gboolean
-gst_controller_set (GstController * self, gchar * property_name,
-    GstClockTime timestamp, GValue * value)
+
+void
+gst_controller_set_property_disabled (GstController * self,
+    gchar * property_name, gboolean disabled)
 {
-  gboolean res = FALSE;
   GstControlledProperty *prop;
 
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-  g_return_val_if_fail (property_name, 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_if_fail (GST_IS_CONTROLLER (self));
+  g_return_if_fail (property_name);
 
   g_mutex_lock (self->lock);
   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    res = gst_controller_set_unlocked (self, prop, timestamp, value);
+    prop->disabled = disabled;
   }
   g_mutex_unlock (self->lock);
-
-  return (res);
 }
 
+
 /**
- * gst_controller_set_from_list:
- * @self: the controller object which handles the properties
- * @property_name: the name of the property to set
- * @timedvalues: a list with #GstTimedValue items
+ * gst_controller_set_disabled:
+ * @self: the #GstController which should be disabled
+ * @disabled: boolean that specifies whether to disable the controller
+ * or not.
  *
- * Sets multiple timed values at once.
+ * This function is used to disable all properties of the #GstController
+ * for some time, i.e. gst_controller_sync_values() will do nothing.
  *
- * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
+ * Since: 0.10.14
  */
 
-gboolean
-gst_controller_set_from_list (GstController * self, gchar * property_name,
-    GSList * timedvalues)
+void
+gst_controller_set_disabled (GstController * self, gboolean disabled)
 {
-  gboolean res = FALSE;
+  GList *node;
   GstControlledProperty *prop;
-  GSList *node;
-  GstTimedValue *tv;
 
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-  g_return_val_if_fail (property_name, FALSE);
+  g_return_if_fail (GST_IS_CONTROLLER (self));
 
   g_mutex_lock (self->lock);
-  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    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 "
-            "for property '%s'", GST_FUNCTION, property_name);
-      } else if (!G_IS_VALUE (&tv->value)) {
-        GST_WARNING ("GstTimedValued with invalid value passed to %s "
-            "for property '%s'", GST_FUNCTION, property_name);
-      } else {
-        res =
-            gst_controller_set_unlocked (self, prop, tv->timestamp, &tv->value);
-      }
-    }
+  for (node = self->properties; node; node = node->next) {
+    prop = node->data;
+    prop->disabled = disabled;
   }
   g_mutex_unlock (self->lock);
-
-  return (res);
 }
 
 /**
- * gst_controller_unset:
- * @self: the controller object which handles the properties
- * @property_name: the name of the property to unset
- * @timestamp: the time the control-change should be removed from
+ * gst_controller_set_control_source:
+ * @self: the controller object
+ * @property_name: name of the property for which the #GstControlSource should be set
+ * @csource: the #GstControlSource that should be used for the property
  *
- * Used to remove the value of given controller-handled property at a certain
- * time.
+ * Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
+ * for this property it will be unreferenced.
  *
- * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
+ * Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
+ * couldn't be bound to the property, %TRUE if everything worked as expected.
+ *
+ * Since: 0.10.14
  */
 gboolean
-gst_controller_unset (GstController * self, gchar * property_name,
-    GstClockTime timestamp)
+gst_controller_set_control_source (GstController * self, gchar * property_name,
+    GstControlSource * csource)
 {
-  gboolean res = FALSE;
   GstControlledProperty *prop;
-
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-  g_return_val_if_fail (property_name, FALSE);
-  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
+  gboolean ret = FALSE;
 
   g_mutex_lock (self->lock);
   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    GList *node;
-
-    /* check if a control point for the timestamp exists */
-    if ((node = g_list_find_custom (prop->values, &timestamp,
-                gst_control_point_find))) {
-      GstControlPoint *cp = node->data;
-
-      if (cp->timestamp == 0) {
-        /* Restore the default node */
-        g_value_reset (&cp->value);
-        g_value_copy (&prop->default_value, &cp->value);
-      } else {
-        if (node == prop->last_requested_value)
-          prop->last_requested_value = NULL;
-        gst_control_point_free (node->data);    /* free GstControlPoint */
-        prop->values = g_list_delete_link (prop->values, node);
-        prop->nvalues--;
-      }
-      prop->valid_cache = FALSE;
-      res = TRUE;
+    GstControlSource *old = prop->csource;
+
+    if (csource && (ret = gst_control_source_bind (csource, prop->pspec))) {
+      g_object_ref (csource);
+      prop->csource = csource;
+    } else if (!csource) {
+      ret = TRUE;
+      prop->csource = NULL;
     }
+
+    if (ret && old)
+      g_object_unref (old);
   }
   g_mutex_unlock (self->lock);
 
-  return (res);
+  return ret;
 }
 
 /**
- * gst_controller_unset_all:
- * @self: the controller object which handles the properties
- * @property_name: the name of the property to unset
+ * gst_controller_get_control_source:
+ * @self: the controller object
+ * @property_name: name of the property for which the #GstControlSource should be get
  *
- * Used to remove all time-stamped values of given controller-handled property
+ * Gets the corresponding #GstControlSource for the property. This should be unreferenced
+ * again after use.
  *
- * Returns: %FALSE if the values couldn't be unset (ex : properties not handled
- * by controller), %TRUE otherwise
- * Since: 0.10.5
+ * Returns: the #GstControlSource for @property_name or NULL if the property is not
+ * controlled by this controller or no #GstControlSource was assigned yet.
+ *
+ * Since: 0.10.14
  */
-gboolean
-gst_controller_unset_all (GstController * self, gchar * property_name)
+GstControlSource *
+gst_controller_get_control_source (GstController * self, gchar * property_name)
 {
-  gboolean res = FALSE;
   GstControlledProperty *prop;
-
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-  g_return_val_if_fail (property_name, FALSE);
+  GstControlSource *ret = NULL;
 
   g_mutex_lock (self->lock);
   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    /* free GstControlPoint structures */
-    g_list_foreach (prop->values, (GFunc) gst_control_point_free, NULL);
-    g_list_free (prop->values);
-    prop->last_requested_value = NULL;
-    prop->values = NULL;
-    prop->nvalues = 0;
-    prop->valid_cache = FALSE;
-
-    /* Insert the default control point again */
-    gst_controlled_property_prepend_default (prop);
-
-    res = TRUE;
+    ret = prop->csource;
   }
   g_mutex_unlock (self->lock);
 
-  return (res);
+  if (ret)
+    g_object_ref (ret);
+
+  return ret;
 }
 
 /**
@@ -995,42 +594,24 @@ gst_controller_get (GstController * self, gchar * property_name,
 
   g_mutex_lock (self->lock);
   if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    /* get current value via interpolator */
-    val = prop->get (prop, timestamp);
-  }
-  g_mutex_unlock (self->lock);
-
-  return (val);
-}
-
-/**
- * gst_controller_get_all:
- * @self: the controller to get the list from
- * @property_name: the name of the property to get the list for
- *
- * Returns a read-only copy of the list of #GstTimedValue for the given property.
- * Free the list after done with it.
- *
- * <note><para>This doesn't modify the controlled GObject property!</para></note>
- *
- * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
- */
-const GList *
-gst_controller_get_all (GstController * self, gchar * property_name)
-{
-  GList *res = NULL;
-  GstControlledProperty *prop;
-
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
-  g_return_val_if_fail (property_name, NULL);
-
-  g_mutex_lock (self->lock);
-  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    res = g_list_copy (prop->values);
+    val = g_new0 (GValue, 1);
+    g_value_init (val, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
+    if (prop->csource) {
+      gboolean res;
+
+      /* get current value via control source */
+      res = gst_control_source_get_value (prop->csource, timestamp, val);
+      if (!res) {
+        g_free (val);
+        val = FALSE;
+      }
+    } else {
+      g_object_get_property (self->object, prop->name, val);
+    }
   }
   g_mutex_unlock (self->lock);
 
-  return (res);
+  return val;
 }
 
 /**
@@ -1081,8 +662,7 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
 {
   GstControlledProperty *prop;
   GList *node;
-  GValue *value;
-  gboolean live = FALSE;
+  gboolean ret = FALSE;
 
   g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
@@ -1092,46 +672,27 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
   g_mutex_lock (self->lock);
   /* go over the controlled properties of the controller */
   for (node = self->properties; node; node = g_list_next (node)) {
+    GValue value = { 0, };
     prop = node->data;
+
     GST_DEBUG ("  property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
         timestamp);
 
-    live = FALSE;
-    if (G_UNLIKELY (G_IS_VALUE (&prop->live_value.value))) {
-      GList *lnode =
-          gst_controlled_property_find_control_point_node (prop, timestamp);
-      if (G_UNLIKELY (!lnode)) {
-        GST_DEBUG ("    no control changes in the queue");
-        live = TRUE;
-      } else {
-        GstControlPoint *cp = lnode->data;
-
-        if (prop->live_value.timestamp < cp->timestamp) {
-          g_value_unset (&prop->live_value.value);
-          GST_DEBUG ("    live value resetted");
-        } else if (prop->live_value.timestamp < timestamp) {
-          live = TRUE;
-        }
-      }
-    }
-    if (G_LIKELY (!live)) {
-      /* get current value via interpolator */
-      value = prop->get (prop, timestamp);
-      prop->last_value.timestamp = timestamp;
-      g_value_copy (value, &prop->last_value.value);
-      g_object_set_property (self->object, prop->name, value);
+    if (!prop->csource || prop->disabled)
+      continue;
+
+    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
+    ret = gst_control_source_get_value (prop->csource, timestamp, &value);
+    if (ret) {
+      g_object_set_property (self->object, prop->name, &value);
+      g_value_unset (&value);
     }
   }
-  if (G_LIKELY (!live))
-    self->priv->last_sync = timestamp;
+  self->priv->last_sync = timestamp;
 
   g_mutex_unlock (self->lock);
-  /* TODO what can here go wrong, to return FALSE ?
-     BilboEd : Nothing I guess, as long as all the checks are made when creating the controller,
-     adding/removing controlled properties, etc...
-   */
 
-  return (TRUE);
+  return ret;
 }
 
 /**
@@ -1207,47 +768,19 @@ gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
   if ((prop =
           gst_controller_find_controlled_property (self,
               value_array->property_name))) {
-    /* get current value_array via interpolator */
-    res = prop->get_value_array (prop, timestamp, value_array);
-  }
+    /* get current value_array via control source */
 
-  g_mutex_unlock (self->lock);
-  return (res);
-}
+    if (!prop->csource)
+      goto out;
 
-/**
- * gst_controller_set_interpolation_mode:
- * @self: the controller object
- * @property_name: the name of the property for which to change the interpolation
- * @mode: interpolation mode
- *
- * Sets the given interpolation mode on the given property.
- *
- * <note><para>User interpolation is not yet available and quadratic interpolation
- * is deprecated and maps to cubic interpolation.</para></note>
- *
- * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
- */
-gboolean
-gst_controller_set_interpolation_mode (GstController * self,
-    gchar * property_name, GstInterpolateMode mode)
-{
-  gboolean res = FALSE;
-  GstControlledProperty *prop;
-
-  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-  g_return_val_if_fail (property_name, FALSE);
-
-  g_mutex_lock (self->lock);
-  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
-    /* TODO shouldn't this also get a GstInterpolateMethod *user_method
-       for the case mode==GST_INTERPOLATE_USER
-     */
-    res = gst_controlled_property_set_interpolation_mode (prop, mode);
+    res =
+        gst_control_source_get_value_array (prop->csource, timestamp,
+        value_array);
   }
-  g_mutex_unlock (self->lock);
 
-  return (res);
+out:
+  g_mutex_unlock (self->lock);
+  return res;
 }
 
 /* gobject handling */
@@ -1322,7 +855,6 @@ _gst_controller_dispose (GObject * object)
       for (node = self->properties; node; node = g_list_next (node)) {
         GstControlledProperty *prop = node->data;
 
-        g_signal_handler_disconnect (self->object, prop->notify_handler_id);
         gst_controlled_property_free (prop);
       }
       g_list_free (self->properties);
@@ -1391,7 +923,7 @@ _gst_controller_class_init (GstControllerClass * klass)
 }
 
 GType
-gst_controller_get_type (void)
+gst_controller_get_type ()
 {
   static GType type = 0;
 
@@ -1412,3 +944,277 @@ gst_controller_get_type (void)
   }
   return type;
 }
+
+/* FIXME: backward compatibility functions */
+
+/*
+ * gst_controlled_property_set_interpolation_mode:
+ * @self: the controlled property object to change
+ * @mode: the new interpolation mode
+ *
+ * Sets the given Interpolation mode for the controlled property and activates
+ * the respective interpolation hooks.
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: %TRUE for success
+ */
+static gboolean
+gst_controlled_property_set_interpolation_mode (GstControlledProperty * self,
+    GstInterpolateMode mode)
+{
+  GstInterpolationControlSource *icsource;
+
+  /* FIXME: backward compat, add GstInterpolationControlSource */
+  if (!self->csource)
+    gst_controlled_property_add_interpolation_control_source (self);
+
+  g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self->csource),
+      FALSE);
+
+  icsource = GST_INTERPOLATION_CONTROL_SOURCE (self->csource);
+
+  return gst_interpolation_control_source_set_interpolation_mode (icsource,
+      mode);
+}
+
+/**
+ * gst_controller_set:
+ * @self: the controller object which handles the properties
+ * @property_name: the name of the property to set
+ * @timestamp: the time the control-change is schedules for
+ * @value: the control-value
+ *
+ * Set the value of given controller-handled property at a certain time.
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
+ */
+gboolean
+gst_controller_set (GstController * self, gchar * property_name,
+    GstClockTime timestamp, GValue * value)
+{
+  gboolean res = FALSE;
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
+  g_return_val_if_fail (property_name, FALSE);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    /* FIXME: backward compat, add GstInterpolationControlSource */
+    if (!prop->csource)
+      gst_controlled_property_add_interpolation_control_source (prop);
+
+    if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
+      goto out;
+    res =
+        gst_interpolation_control_source_set (GST_INTERPOLATION_CONTROL_SOURCE
+        (prop->csource), timestamp, value);
+  }
+
+out:
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_controller_set_from_list:
+ * @self: the controller object which handles the properties
+ * @property_name: the name of the property to set
+ * @timedvalues: a list with #GstTimedValue items
+ *
+ * Sets multiple timed values at once.
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
+ */
+
+gboolean
+gst_controller_set_from_list (GstController * self, gchar * property_name,
+    GSList * timedvalues)
+{
+  gboolean res = FALSE;
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
+  g_return_val_if_fail (property_name, FALSE);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    /* FIXME: backward compat, add GstInterpolationControlSource */
+    if (!prop->csource)
+      gst_controlled_property_add_interpolation_control_source (prop);
+
+    if (!GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
+      goto out;
+
+    res =
+        gst_interpolation_control_source_set_from_list
+        (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource), timedvalues);
+  }
+
+out:
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_controller_unset:
+ * @self: the controller object which handles the properties
+ * @property_name: the name of the property to unset
+ * @timestamp: the time the control-change should be removed from
+ *
+ * Used to remove the value of given controller-handled property at a certain
+ * time.
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
+ */
+gboolean
+gst_controller_unset (GstController * self, gchar * property_name,
+    GstClockTime timestamp)
+{
+  gboolean res = FALSE;
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
+  g_return_val_if_fail (property_name, FALSE);
+  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
+      goto out;
+
+    res =
+        gst_interpolation_control_source_unset (GST_INTERPOLATION_CONTROL_SOURCE
+        (prop->csource), timestamp);
+  }
+
+out:
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_controller_unset_all:
+ * @self: the controller object which handles the properties
+ * @property_name: the name of the property to unset
+ *
+ * Used to remove all time-stamped values of given controller-handled property
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: %FALSE if the values couldn't be unset (ex : properties not handled
+ * by controller), %TRUE otherwise
+ * Since: 0.10.5
+ */
+gboolean
+gst_controller_unset_all (GstController * self, gchar * property_name)
+{
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
+  g_return_val_if_fail (property_name, FALSE);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
+      goto out;
+
+    gst_interpolation_control_source_unset_all (GST_INTERPOLATION_CONTROL_SOURCE
+        (prop->csource));
+  }
+
+out:
+  g_mutex_unlock (self->lock);
+
+  return TRUE;
+}
+
+/**
+ * gst_controller_get_all:
+ * @self: the controller to get the list from
+ * @property_name: the name of the property to get the list for
+ *
+ * Returns a read-only copy of the list of #GstTimedValue for the given property.
+ * Free the list after done with it.
+ *
+ * <note><para>This doesn't modify the controlled GObject property!</para></note>
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
+ */
+const GList *
+gst_controller_get_all (GstController * self, gchar * property_name)
+{
+  const GList *res = NULL;
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
+  g_return_val_if_fail (property_name, NULL);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    if (!prop->csource || !GST_IS_INTERPOLATION_CONTROL_SOURCE (prop->csource))
+      goto out;
+
+    res =
+        gst_interpolation_control_source_get_all
+        (GST_INTERPOLATION_CONTROL_SOURCE (prop->csource));
+  }
+
+out:
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_controller_set_interpolation_mode:
+ * @self: the controller object
+ * @property_name: the name of the property for which to change the interpolation
+ * @mode: interpolation mode
+ *
+ * Sets the given interpolation mode on the given property.
+ *
+ * <note><para>User interpolation is not yet available and quadratic interpolation
+ * is deprecated and maps to cubic interpolation.</para></note>
+ *
+ * Deprecated: Use #GstControlSource, for example #GstInterpolationControlSource
+ * directly.
+ *
+ * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
+ */
+gboolean
+gst_controller_set_interpolation_mode (GstController * self,
+    gchar * property_name, GstInterpolateMode mode)
+{
+  gboolean res = FALSE;
+  GstControlledProperty *prop;
+
+  g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
+  g_return_val_if_fail (property_name, FALSE);
+
+  g_mutex_lock (self->lock);
+  if ((prop = gst_controller_find_controlled_property (self, property_name))) {
+    res = gst_controlled_property_set_interpolation_mode (prop, mode);
+  }
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
index 2f2bbcd..d8514e1 100644 (file)
@@ -30,6 +30,9 @@
 #include <glib/gprintf.h>
 #include <gst/gst.h>
 
+#include "gstcontrolsource.h"
+#include "gstinterpolationcontrolsource.h"
+
 G_BEGIN_DECLS
 
 /**
@@ -41,59 +44,6 @@ G_BEGIN_DECLS
  */
 #define        GST_PARAM_CONTROLLABLE  (1 << (G_PARAM_USER_SHIFT + 1))
 
-
-/**
- * GstTimedValue:
- *
- * a structure for value+time
- */
-typedef struct _GstTimedValue
-{
-  GstClockTime timestamp;       /* timestamp of the value change */
-  GValue value;                 /* the new value */
-} GstTimedValue;
-
-
-/**
- * GstValueArray:
- * @property_name: the name of the property this array belongs to
- * @nbsamples: number of samples requested
- * @sample_interval: interval between each sample
- * @values: pointer to the array
- *
- * Structure to receive multiple values at once.
- */
-typedef struct _GstValueArray
-{
-  gchar *property_name;
-  gint nbsamples;
-  GstClockTime sample_interval;
-  gpointer *values;
-} GstValueArray;
-
-
-/**
- * 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 (not yet available)
- * @GST_INTERPOLATE_CUBIC: cubic interpolation (not yet available)
- * @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
-} GstInterpolateMode;
-
 /* type macros */
 
 #define GST_TYPE_CONTROLLER           (gst_controller_get_type ())
@@ -107,7 +57,6 @@ typedef struct _GstController GstController;
 typedef struct _GstControllerClass GstControllerClass;
 typedef struct _GstControllerPrivate GstControllerPrivate;
 
-
 /**
  * GstController:
  *
@@ -135,7 +84,7 @@ struct _GstControllerClass
   gpointer       _gst_reserved[GST_PADDING];
 };
 
-GType gst_controller_get_type (void);
+GType gst_controller_get_type ();
 
 /* GstController functions */
 
@@ -149,33 +98,22 @@ gboolean gst_controller_remove_properties_list (GstController * self,
                                                GList *list);
 gboolean gst_controller_remove_properties (GstController * self, ...) G_GNUC_NULL_TERMINATED;
 
-gboolean gst_controller_set (GstController * self, gchar * property_name,
-    GstClockTime timestamp, GValue * value);
-gboolean gst_controller_set_from_list (GstController * self,
-    gchar * property_name, GSList * timedvalues);
-
-gboolean gst_controller_unset (GstController * self, gchar * property_name,
-    GstClockTime timestamp);
-gboolean gst_controller_unset_all (GstController * self, gchar * property_name);
-
-GValue *gst_controller_get (GstController * self, gchar * property_name,
-    GstClockTime timestamp);
-const GList *gst_controller_get_all (GstController * self,
-    gchar * property_name);
+void gst_controller_set_disabled (GstController *self, gboolean disabled);
+void gst_controller_set_property_disabled (GstController *self, gchar * property_name, gboolean disabled);
+gboolean gst_controller_set_control_source (GstController *self, gchar * property_name, GstControlSource *csource);
+GstControlSource * gst_controller_get_control_source (GstController *self, gchar * property_name);
 
 GstClockTime gst_controller_suggest_next_sync (GstController *self);
 gboolean gst_controller_sync_values (GstController * self,
     GstClockTime timestamp);
 
+GValue *gst_controller_get (GstController * self, gchar * property_name,
+    GstClockTime timestamp);
 gboolean gst_controller_get_value_arrays (GstController * self,
     GstClockTime timestamp, GSList * value_arrays);
 gboolean gst_controller_get_value_array (GstController * self,
     GstClockTime timestamp, GstValueArray * value_array);
 
-gboolean gst_controller_set_interpolation_mode (GstController * self,
-    gchar * property_name, GstInterpolateMode mode);
-
-
 /* GObject convenience functions */
 
 GstController *gst_object_control_properties (GObject * object, ...) G_GNUC_NULL_TERMINATED;
@@ -187,6 +125,9 @@ gboolean gst_object_set_controller (GObject * object, GstController * controller
 GstClockTime gst_object_suggest_next_sync (GObject * object);
 gboolean gst_object_sync_values (GObject * object, GstClockTime timestamp);
 
+gboolean gst_object_set_control_source (GObject *object, gchar * property_name, GstControlSource *csource);
+GstControlSource * gst_object_get_control_source (GObject *object, gchar * property_name);
+
 gboolean gst_object_get_value_arrays (GObject * object,
     GstClockTime timestamp, GSList * value_arrays);
 gboolean gst_object_get_value_array (GObject * object,
@@ -199,5 +140,25 @@ void gst_object_set_control_rate (GObject * object, GstClockTime control_rate);
 
 gboolean gst_controller_init (int * argc, char ***argv);
 
+
+/* FIXME: deprecated functions */
+#ifndef GST_DISABLE_DEPRECATED
+gboolean gst_controller_set (GstController * self, gchar * property_name,
+    GstClockTime timestamp, GValue * value);
+gboolean gst_controller_set_from_list (GstController * self,
+    gchar * property_name, GSList * timedvalues);
+
+gboolean gst_controller_unset (GstController * self, gchar * property_name,
+    GstClockTime timestamp);
+gboolean gst_controller_unset_all (GstController * self, gchar * property_name);
+
+const GList *gst_controller_get_all (GstController * self,
+    gchar * property_name);
+
+gboolean gst_controller_set_interpolation_mode (GstController * self,
+    gchar * property_name, GstInterpolateMode mode);
+#endif /* GST_DISABLE_DEPRECATED */
+
 G_END_DECLS
+
 #endif /* __GST_CONTROLLER_H__ */
index f5a7a2c..e4fafee 100644 (file)
 #include <gst/gst.h>
 
 #include "gstcontroller.h"
+#include "gstcontrolsource.h"
 
 G_BEGIN_DECLS
 
-struct _GstControlledProperty;
-
-typedef GValue *(*InterpolateGet) (struct _GstControlledProperty * prop,
-        GstClockTime timestamp);
-typedef gboolean (*InterpolateGetValueArray) (struct _GstControlledProperty * prop,
-        GstClockTime timestamp, GstValueArray * value_array);
-
-/**
- * GstInterpolateMethod:
- *
- * Function pointer structure to do user-defined interpolation methods
- */
-typedef struct _GstInterpolateMethod
-{
-  InterpolateGet get_int;
-  InterpolateGetValueArray get_int_value_array;
-  InterpolateGet get_uint;
-  InterpolateGetValueArray get_uint_value_array;
-  InterpolateGet get_long;
-  InterpolateGetValueArray get_long_value_array;
-  InterpolateGet get_ulong;
-  InterpolateGetValueArray get_ulong_value_array;
-  InterpolateGet get_float;
-  InterpolateGetValueArray get_float_value_array;
-  InterpolateGet get_double;
-  InterpolateGetValueArray get_double_value_array;
-  InterpolateGet get_boolean;
-  InterpolateGetValueArray get_boolean_value_array;
-  InterpolateGet get_enum;
-  InterpolateGetValueArray get_enum_value_array;
-  InterpolateGet get_string;
-  InterpolateGetValueArray get_string_value_array;
-} GstInterpolateMethod;
-
-/**
- * GstControlPoint:
- *
- * a internal structure for value+time and various temporary
- * values used for interpolation. This "inherits" from
- * GstTimedValue.
- */
-/* FIXME 0.11: This should be merged with GstTimedValue for 0.11 */
-typedef struct _GstControlPoint
-{
-  /* fields from GstTimedValue. DO NOT CHANGE! */
-  GstClockTime timestamp;       /* timestamp of the value change */
-  GValue value;                 /* the new value */
-
-  /* internal fields */
-
-  /* Caches for the interpolators */
-  union {
-    struct {
-      gdouble h;
-      gdouble z;
-    } cubic;
-  } cache;
-
-} GstControlPoint;
-
 /**
  * GstControlledProperty:
  */
 typedef struct _GstControlledProperty
 {
+  GParamSpec *pspec;            /* GParamSpec for this property */
   gchar *name;                  /* name of the property */
-  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 min_value;             /* min value for the handled property */
-  GValue max_value;             /* max value for the handled property */
-  GValue result_value;          /* result value location for the interpolation method */
-  GstControlPoint last_value;     /* the last value a _sink call wrote */
-  GstControlPoint live_value;     /* temporary value override for live input */
-  gulong notify_handler_id;     /* id of the notify::<name> signal handler */
-  GstInterpolateMode interpolation;     /* Interpolation mode */
-  /* TODO instead of *method, have pointers to get() and get_value_array() here
-     gst_controller_set_interpolation_mode() will pick the right ones for the
-     properties value type
-     GstInterpolateMethod *method; // User-implemented handler (if interpolation == GST_INTERPOLATE_USER)
-  */
-  InterpolateGet get;
-  InterpolateGetValueArray get_value_array;
-
-  GList *values;                /* List of GstControlPoint */
-  gint nvalues;                 /* Number of control points */
-  GList *last_requested_value;  /* last search result, can be used for incremental searches */
-  gboolean valid_cache;
+  GstControlSource *csource;    /* GstControlSource for this property */
+  gboolean disabled;
 } GstControlledProperty;
 
 #define GST_CONTROLLED_PROPERTY(obj)    ((GstControlledProperty *)(obj))
diff --git a/libs/gst/controller/gstcontrolsource.c b/libs/gst/controller/gstcontrolsource.c
new file mode 100644 (file)
index 0000000..ad705f0
--- /dev/null
@@ -0,0 +1,158 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstcontrolsource.c: Interface declaration for 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:gstcontrolsource
+ * @short_description: base class for control source sources
+ *
+ * The #GstControlSource is a base class for control value sources that could
+ * be used by #GstController to get timestamp-value pairs.
+ *
+ * A #GstControlSource is used by first getting an instance, binding it to a
+ * #GParamSpec (for example by using gst_controller_set_control_source()) and
+ * then by having it used by the #GstController or calling
+ * gst_control_source_get_value() or gst_control_source_get_value_array().
+ *
+ * For implementing a new #GstControlSource one has to implement a
+ * #GstControlSourceBind method, which will depending on the #GParamSpec set up
+ * the control source for use and sets the #GstControlSourceGetValue and
+ * #GstControlSourceGetValueArray functions. These are then used by
+ * gst_control_source_get_value() or gst_control_source_get_value_array()
+ * to get values for specific timestamps.
+ *
+ */
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "gstcontrolsource.h"
+
+#define GST_CAT_DEFAULT gst_controller_debug
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
+
+static void gst_control_source_class_init (GstControlSourceClass * klass);
+static void gst_control_source_init (GstControlSource * self);
+
+G_DEFINE_ABSTRACT_TYPE (GstControlSource, gst_control_source, G_TYPE_OBJECT);
+
+static GObjectClass *parent_class = NULL;
+
+static void
+gst_control_source_class_init (GstControlSourceClass * klass)
+{
+  //GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  /* Has to be implemented by children */
+  klass->bind = NULL;
+}
+
+static void
+gst_control_source_init (GstControlSource * self)
+{
+  /* Set default handlers that print a warning */
+  self->get_value = NULL;
+  self->get_value_array = NULL;
+  self->bound = FALSE;
+}
+
+/**
+ * gst_control_source_get_value:
+ * @self: the #GstControlSource object
+ * @timestamp: the time for which the value should be returned
+ * @value: the value
+ *
+ * Gets the value for this #GstControlSource at a given timestamp.
+ *
+ * Returns: FALSE if the value couldn't be returned, TRUE otherwise.
+ */
+gboolean
+gst_control_source_get_value (GstControlSource * self, GstClockTime timestamp,
+    GValue * value)
+{
+  g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE);
+
+  if (self->get_value) {
+    return self->get_value (self, timestamp, value);
+  } else {
+    GST_ERROR ("Not bound to a specific property yet!");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_control_source_get_value_array:
+ * @self: the #GstControlSource object
+ * @timestamp: the time that should be processed
+ * @value_array: array to put control-values in
+ *
+ * Gets an array of values for one element property.
+ *
+ * All fields of @value_array must be filled correctly. Especially the
+ * @value_array->values array must be big enough to keep the requested amount
+ * of values.
+ *
+ * The type of the values in the array is the same as the property's type.
+ *
+ * Returns: %TRUE if the given array could be filled, %FALSE otherwise
+ */
+gboolean
+gst_control_source_get_value_array (GstControlSource * self,
+    GstClockTime timestamp, GstValueArray * value_array)
+{
+  g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE);
+
+  if (self->get_value_array) {
+    return self->get_value_array (self, timestamp, value_array);
+  } else {
+    GST_ERROR ("Not bound to a specific property yet!");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_control_source_bind:
+ * @self: the #GstControlSource object
+ * @pspec: #GParamSpec for the property for which this #GstControlSource should generate values.
+ *
+ * Binds a #GstControlSource to a specific property. This must be called only once for a
+ * #GstControlSource.
+ *
+ * Returns: %TRUE if the #GstControlSource was bound correctly, %FALSE otherwise.
+ */
+gboolean
+gst_control_source_bind (GstControlSource * self, GParamSpec * pspec)
+{
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (GST_IS_CONTROL_SOURCE (self), FALSE);
+  g_return_val_if_fail (GST_CONTROL_SOURCE_GET_CLASS (self)->bind, FALSE);
+  g_return_val_if_fail (!self->bound, FALSE);
+
+  ret = GST_CONTROL_SOURCE_GET_CLASS (self)->bind (self, pspec);
+
+  if (ret)
+    self->bound = TRUE;
+
+  return ret;
+}
diff --git a/libs/gst/controller/gstcontrolsource.h b/libs/gst/controller/gstcontrolsource.h
new file mode 100644 (file)
index 0000000..68897ab
--- /dev/null
@@ -0,0 +1,161 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstcontrolsource.h: Interface declaration for 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_CONTROL_SOURCE_H__
+#define __GST_CONTROL_SOURCE_H__
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CONTROL_SOURCE \
+  (gst_control_source_get_type())
+#define GST_CONTROL_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONTROL_SOURCE,GstControlSource))
+#define GST_CONTROL_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONTROL_SOURCE,GstControlSourceClass))
+#define GST_IS_CONTROL_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONTROL_SOURCE))
+#define GST_IS_CONTROL_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONTROL_SOURCE))
+#define GST_CONTROL_SOURCE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CONTOL_SOURCE, GstControlSourceClass))
+
+typedef struct _GstControlSource GstControlSource;
+typedef struct _GstControlSourceClass GstControlSourceClass;
+typedef struct _GstTimedValue GstTimedValue;
+typedef struct _GstValueArray GstValueArray;
+
+/**
+ * GstTimedValue:
+ *
+ * Structure for saving a timestamp and a value.
+ */
+struct _GstTimedValue
+{
+  GstClockTime timestamp;       /* timestamp of the value change */
+  GValue value;                 /* the corresponding value */
+};
+
+/**
+ * GstValueArray:
+ * @property_name: the name of the property this array belongs to
+ * @nbsamples: number of samples requested
+ * @sample_interval: interval between each sample
+ * @values: pointer to the array
+ *
+ * Structure to receive multiple values at once.
+ */
+struct _GstValueArray
+{
+  gchar *property_name;
+  gint nbsamples;
+  GstClockTime sample_interval;
+  gpointer *values;
+};
+
+/** 
+ * GstControlSourceGetValue
+ * @self: the #GstControlSource instance
+ * @timestamp: timestamp for which a value should be calculated
+ * @value: a #GValue which will be set to the result. It must be initialized to the correct type.
+ *
+ * Function for returning a value for a given timestamp.
+ *
+ * Returns: %TRUE if the value was successfully calculated.
+ *
+ */
+typedef gboolean (* GstControlSourceGetValue) (GstControlSource *self, GstClockTime timestamp, GValue *value);
+
+/** 
+ * GstControlSourceGetValueArray
+ * @self: the #GstControlSource instance
+ * @timestamp: timestamp for which a value should be calculated
+ * @value_array: array to put control-values in
+ *
+ * Function for returning a #GstValueArray for a given timestamp.
+ *
+ * Returns: %TRUE if the values were successfully calculated.
+ *
+ */
+typedef gboolean (* GstControlSourceGetValueArray) (GstControlSource *self, GstClockTime timestamp, GstValueArray *value_array);
+
+/** 
+ * GstControlSourceBind
+ * @self: the #GstControlSource instance
+ * @pspec: #GParamSpec that should be bound to
+ *
+ * Function for binding a #GstControlSource to a #GParamSpec.
+ *
+ * Returns: %TRUE if the property could be bound to the #GstControlSource, %FALSE otherwise.
+ */
+typedef gboolean (* GstControlSourceBind) (GstControlSource *self, GParamSpec *pspec);
+
+/**
+ * GstControlSource:
+ * @get_value: Function for returning a value for a given timestamp
+ * @get_value_array: Function for returning a #GstValueArray for a given timestamp
+ *
+ * The instance structure of #GstControlSource.
+ */
+struct _GstControlSource {
+  GObject parent;
+
+  /*< public >*/
+  GstControlSourceGetValue get_value;             /* Returns the value for a property at a given timestamp */
+  GstControlSourceGetValueArray get_value_array;  /* Returns values for a property in a given timespan */
+
+  /*< private >*/
+  gboolean bound;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstControlSourceClass:
+ * @parent_class: Parent class
+ * @bind: Class method for binding the #GstControlSource to a specific GParamSpec
+ *
+ * The class structure of #GstControlSource.
+ */
+
+struct _GstControlSourceClass
+{
+  GObjectClass parent_class;
+  
+  GstControlSourceBind bind;  /* Binds the GstControlSource to a specific GParamSpec */
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_control_source_get_type ();
+
+/* Functions */
+
+gboolean gst_control_source_get_value (GstControlSource *self, GstClockTime timestamp, GValue *value);
+gboolean gst_control_source_get_value_array (GstControlSource *self, GstClockTime timestamp, GstValueArray *value_array);
+gboolean gst_control_source_bind (GstControlSource *self, GParamSpec *pspec);
+
+G_END_DECLS
+
+#endif /* __GST_CONTROL_SOURCE_H__ */
index 3320599..9c87f60 100644 (file)
@@ -148,7 +148,6 @@ gst_object_set_controller (GObject * object, GstController * controller)
  /**
  * gst_object_suggest_next_sync:
  * @object: the object that has controlled properties
- * @timestamp: the time that should be processed
  *
  * Convenience function for GObject
  *
@@ -193,6 +192,61 @@ gst_object_sync_values (GObject * object, GstClockTime timestamp)
 }
 
 /**
+ * gst_object_set_control_source:
+ * @object: the controller object
+ * @property_name: name of the property for which the #GstControlSource should be set
+ * @csource: the #GstControlSource that should be used for the property
+ *
+ * Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
+ * for this property it will be unreferenced.
+ *
+ * Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
+ * couldn't be bound to the property, %TRUE if everything worked as expected.
+ *
+ * Since: 0.10.14
+ */
+gboolean
+gst_object_set_control_source (GObject * object, gchar * property_name,
+    GstControlSource * csource)
+{
+  GstController *ctrl = NULL;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
+  g_return_val_if_fail (GST_IS_CONTROL_SOURCE (csource), FALSE);
+
+  if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
+    return gst_controller_set_control_source (ctrl, property_name, csource);
+  }
+  return FALSE;
+}
+
+/**
+ * gst_object_get_control_source:
+ * @object: the object
+ * @property_name: name of the property for which the #GstControlSource should be get
+ *
+ * Gets the corresponding #GstControlSource for the property. This should be unreferenced
+ * again after use.
+ *
+ * Returns: the #GstControlSource for @property_name or NULL if the property is not
+ * controlled by this controller or no #GstControlSource was assigned yet.
+ *
+ * Since: 0.10.14
+ */
+GstControlSource *
+gst_object_get_control_source (GObject * object, gchar * property_name)
+{
+  GstController *ctrl = NULL;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
+
+  if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
+    return gst_controller_get_control_source (ctrl, property_name);
+  }
+  return FALSE;
+}
+
+/**
  * gst_object_get_value_arrays:
  * @object: the object that has controlled properties
  * @timestamp: the time that should be processed
index d0e7584..4a74e6b 100644 (file)
@@ -24,8 +24,9 @@
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
-#include "gstcontrollerprivate.h"
-#include "gstcontroller.h"
+
+#include "gstinterpolationcontrolsource.h"
+#include "gstinterpolationcontrolsourceprivate.h"
 
 #define GST_CAT_DEFAULT gst_controller_debug
 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
@@ -33,28 +34,29 @@ GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
 /* common helper */
 
 /*
- * gst_controlled_property_find_control_point_node:
- * @prop: the controlled property to search in
+ * gst_interpolation_control_source_find_control_point_node:
+ * @self: the interpolation control source to search in
  * @timestamp: the search key
  *
  * Find last value before given timestamp in control point list.
  *
  * Returns: the found #GList node or %NULL
  */
-GList *
-gst_controlled_property_find_control_point_node (GstControlledProperty * prop,
-    GstClockTime timestamp)
+static GList *gst_interpolation_control_source_find_control_point_node
+    (GstInterpolationControlSource * self, GstClockTime timestamp)
 {
-  GList *prev_node = g_list_last (prop->values);
+  GList *prev_node = g_list_last (self->priv->values);
   GList *node;
   GstControlPoint *cp;
 
-  node = prop->values;
-  if (prop->last_requested_value) {
-    GstControlPoint *last_cp = prop->last_requested_value->data;
+  /* Check if we can start from the last requested value
+   * to save some time */
+  node = self->priv->values;
+  if (self->priv->last_requested_value) {
+    GstControlPoint *last_cp = self->priv->last_requested_value->data;
 
     if (timestamp > last_cp->timestamp)
-      node = prop->last_requested_value;
+      node = self->priv->last_requested_value;
   }
 
   /* iterate over timed value list */
@@ -68,286 +70,476 @@ gst_controlled_property_find_control_point_node (GstControlledProperty * prop,
     }
   }
 
+  /* If we have something to return save it as a
+   * potential start position for the next search */
   if (prev_node)
-    prop->last_requested_value = prev_node;
+    self->priv->last_requested_value = prev_node;
 
   return prev_node;
 }
 
-/*  steps-like (no-)interpolation, default */
-/*  just returns the value for the most recent key-frame */
-
-static GValue *
-interpolate_none_get (GstControlledProperty * prop, GstClockTime timestamp)
+/*
+ * gst_interpolation_control_source_get_first_value:
+ * @self: the interpolation control source to search in
+ *
+ * Find the first value and return it.
+ *
+ * Returns: the found #GValue or %NULL if there are none.
+ */
+static inline GValue *
+gst_interpolation_control_source_get_first_value (GstInterpolationControlSource
+    * self)
 {
-  GList *node;
-
-  if ((node =
-          gst_controlled_property_find_control_point_node (prop, timestamp))) {
-    GstControlPoint *cp = node->data;
+  if (self->priv->values && self->priv->nvalues > 0) {
+    GstControlPoint *cp = self->priv->values->data;
 
     return &cp->value;
+  } else {
+    return NULL;
   }
-  return &prop->default_value;
 }
 
-#define interpolate_none_get_boolean interpolate_none_get
+/*  steps-like (no-)interpolation, default */
+/*  just returns the value for the most recent key-frame */
 
 #define DEFINE_NONE_GET(type) \
-static GValue * \
-interpolate_none_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static inline GValue * \
+_interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
 { \
+  GValue *ret; \
   GList *node; \
   \
   if ((node = \
-          gst_controlled_property_find_control_point_node (prop, timestamp))) { \
+          gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
     GstControlPoint *cp = node->data; \
-    g##type ret = g_value_get_##type (&cp->value); \
-    if (g_value_get_##type (&prop->min_value) > ret) \
-      return &prop->min_value; \
-    else if (g_value_get_##type (&prop->max_value) < ret) \
-      return &prop->max_value; \
-    return &cp->value; \
+    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; \
+    else \
+      ret = &cp->value; \
+  } else { \
+    ret = gst_interpolation_control_source_get_first_value (self); \
   } \
-  return &prop->default_value; \
-}
-
-DEFINE_NONE_GET (int);
-DEFINE_NONE_GET (uint);
-DEFINE_NONE_GET (long);
-
-DEFINE_NONE_GET (ulong);
-DEFINE_NONE_GET (float);
-DEFINE_NONE_GET (double);
-
-#define DEFINE_NONE_GET_VALUE_ARRAY(type) \
+  return ret; \
+} \
+\
 static gboolean \
-interpolate_none_get_##type##_value_array (GstControlledProperty * prop, \
+interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
+{ \
+  GValue *ret; \
+  g_mutex_lock (self->lock); \
+  \
+  ret = _interpolate_none_get_##type (self, 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_none_get_##type##_value_array (GstInterpolationControlSource *self, \
     GstClockTime timestamp, GstValueArray * value_array) \
 { \
   gint i; \
   GstClockTime ts = timestamp; \
   g##type *values = (g##type *) value_array->values; \
+  GValue *ret; \
   \
+  g_mutex_lock (self->lock); \
   for(i = 0; i < value_array->nbsamples; i++) { \
-    *values = g_value_get_##type (interpolate_none_get_##type (prop,ts)); \
+    ret = _interpolate_none_get_##type (self, timestamp); \
+    if (!ret) { \
+      g_mutex_unlock (self->lock); \
+      return FALSE; \
+    } \
+    *values = g_value_get_##type (ret); \
     ts += value_array->sample_interval; \
     values++; \
   } \
+  g_mutex_unlock (self->lock); \
   return TRUE; \
 }
 
-DEFINE_NONE_GET_VALUE_ARRAY (int);
 
-DEFINE_NONE_GET_VALUE_ARRAY (uint);
-DEFINE_NONE_GET_VALUE_ARRAY (long);
+DEFINE_NONE_GET (int);
+DEFINE_NONE_GET (uint);
+DEFINE_NONE_GET (long);
+
+DEFINE_NONE_GET (ulong);
+DEFINE_NONE_GET (int64);
+DEFINE_NONE_GET (uint64);
+DEFINE_NONE_GET (float);
+DEFINE_NONE_GET (double);
+
+static inline GValue *
+_interpolate_none_get (GstInterpolationControlSource * self,
+    GstClockTime timestamp)
+{
+  GList *node;
+  GValue *ret;
+
+  if ((node =
+          gst_interpolation_control_source_find_control_point_node (self,
+              timestamp))) {
+    GstControlPoint *cp = node->data;
+
+    ret = &cp->value;
+  } else {
+    ret = gst_interpolation_control_source_get_first_value (self);
+  }
+  return ret;
+}
+
+static gboolean
+interpolate_none_get (GstInterpolationControlSource * self,
+    GstClockTime timestamp, GValue * value)
+{
+  GValue *ret;
+
+  g_mutex_lock (self->lock);
+  ret = _interpolate_none_get (self, timestamp);
 
-DEFINE_NONE_GET_VALUE_ARRAY (ulong);
-DEFINE_NONE_GET_VALUE_ARRAY (float);
-DEFINE_NONE_GET_VALUE_ARRAY (double);
+  if (!ret) {
+    g_mutex_unlock (self->lock);
+    return FALSE;
+  }
 
-DEFINE_NONE_GET_VALUE_ARRAY (boolean);
+  g_value_copy (ret, value);
+  g_mutex_unlock (self->lock);
+  return TRUE;
+}
 
 static gboolean
-interpolate_none_get_enum_value_array (GstControlledProperty * prop,
+interpolate_none_get_boolean_value_array (GstInterpolationControlSource * self,
+    GstClockTime timestamp, GstValueArray * value_array)
+{
+  gint i;
+  GstClockTime ts = timestamp;
+  gboolean *values = (gboolean *) value_array->values;
+  GValue *ret;
+
+  g_mutex_lock (self->lock);
+  for (i = 0; i < value_array->nbsamples; i++) {
+    ret = _interpolate_none_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = g_value_get_boolean (ret);
+    ts += value_array->sample_interval;
+    values++;
+  }
+  g_mutex_unlock (self->lock);
+  return TRUE;
+}
+
+static gboolean
+interpolate_none_get_enum_value_array (GstInterpolationControlSource * self,
     GstClockTime timestamp, GstValueArray * value_array)
 {
   gint i;
   GstClockTime ts = timestamp;
   gint *values = (gint *) value_array->values;
+  GValue *ret;
 
+  g_mutex_lock (self->lock);
   for (i = 0; i < value_array->nbsamples; i++) {
-    *values = g_value_get_enum (interpolate_none_get (prop, ts));
+    ret = _interpolate_none_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = g_value_get_enum (ret);
     ts += value_array->sample_interval;
     values++;
   }
+  g_mutex_unlock (self->lock);
   return TRUE;
 }
 
 static gboolean
-interpolate_none_get_string_value_array (GstControlledProperty * prop,
+interpolate_none_get_string_value_array (GstInterpolationControlSource * self,
     GstClockTime timestamp, GstValueArray * value_array)
 {
   gint i;
   GstClockTime ts = timestamp;
   gchar **values = (gchar **) value_array->values;
+  GValue *ret;
 
+  g_mutex_lock (self->lock);
   for (i = 0; i < value_array->nbsamples; i++) {
-    *values = (gchar *) g_value_get_string (interpolate_none_get (prop, ts));
+    ret = _interpolate_none_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = (gchar *) g_value_get_string (ret);
     ts += value_array->sample_interval;
     values++;
   }
+  g_mutex_unlock (self->lock);
   return TRUE;
 }
 
 static GstInterpolateMethod interpolate_none = {
-  interpolate_none_get_int,
-  interpolate_none_get_int_value_array,
-  interpolate_none_get_uint,
-  interpolate_none_get_uint_value_array,
-  interpolate_none_get_long,
-  interpolate_none_get_long_value_array,
-  interpolate_none_get_ulong,
-  interpolate_none_get_ulong_value_array,
-  interpolate_none_get_float,
-  interpolate_none_get_float_value_array,
-  interpolate_none_get_double,
-  interpolate_none_get_double_value_array,
-  interpolate_none_get,
-  interpolate_none_get_boolean_value_array,
-  interpolate_none_get,
-  interpolate_none_get_enum_value_array,
-  interpolate_none_get,
-  interpolate_none_get_string_value_array
+  (GstControlSourceGetValue) interpolate_none_get_int,
+  (GstControlSourceGetValueArray) interpolate_none_get_int_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_uint,
+  (GstControlSourceGetValueArray) interpolate_none_get_uint_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_long,
+  (GstControlSourceGetValueArray) interpolate_none_get_long_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_ulong,
+  (GstControlSourceGetValueArray) interpolate_none_get_ulong_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_int64,
+  (GstControlSourceGetValueArray) interpolate_none_get_int64_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_uint64,
+  (GstControlSourceGetValueArray) interpolate_none_get_uint64_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_float,
+  (GstControlSourceGetValueArray) interpolate_none_get_float_value_array,
+  (GstControlSourceGetValue) interpolate_none_get_double,
+  (GstControlSourceGetValueArray) interpolate_none_get_double_value_array,
+  (GstControlSourceGetValue) interpolate_none_get,
+  (GstControlSourceGetValueArray) interpolate_none_get_boolean_value_array,
+  (GstControlSourceGetValue) interpolate_none_get,
+  (GstControlSourceGetValueArray) interpolate_none_get_enum_value_array,
+  (GstControlSourceGetValue) interpolate_none_get,
+  (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 GValue *
-interpolate_trigger_get (GstControlledProperty * prop, GstClockTime timestamp)
-{
-  GList *node;
-  GstControlPoint *cp;
-
-  /* check if there is a value at the registered timestamp */
-  if ((node =
-          gst_controlled_property_find_control_point_node (prop, timestamp))) {
-    cp = node->data;
-    if (timestamp == cp->timestamp) {
-      return &cp->value;
-    }
-  }
-
-  return &prop->default_value;
-}
-
-#define interpolate_trigger_get_boolean interpolate_trigger_get
-
 #define DEFINE_TRIGGER_GET(type) \
-static GValue * \
-interpolate_trigger_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static inline GValue * \
+_interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
 { \
   GList *node; \
   GstControlPoint *cp; \
   \
   /* check if there is a value at the registered timestamp */ \
   if ((node = \
-          gst_controlled_property_find_control_point_node (prop, timestamp))) { \
+          gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
     cp = node->data; \
     if (timestamp == cp->timestamp) { \
       g##type ret = g_value_get_##type (&cp->value); \
-      if (g_value_get_##type (&prop->min_value) > ret) \
-        return &prop->min_value; \
-      else if (g_value_get_##type (&prop->max_value) < ret) \
-        return &prop->max_value; \
-      return &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; \
     } \
   } \
   \
-  return &prop->default_value; \
-}
-
-DEFINE_TRIGGER_GET (int);
-DEFINE_TRIGGER_GET (uint);
-DEFINE_TRIGGER_GET (long);
-
-DEFINE_TRIGGER_GET (ulong);
-DEFINE_TRIGGER_GET (float);
-DEFINE_TRIGGER_GET (double);
-
-#define DEFINE_TRIGGER_GET_VALUE_ARRAY(type) \
+  if (self->priv->nvalues > 0) \
+    return &self->priv->default_value; \
+  else \
+    return NULL; \
+} \
+\
 static gboolean \
-interpolate_trigger_get_##type##_value_array (GstControlledProperty * prop, \
+interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
+{ \
+  GValue *ret; \
+  g_mutex_lock (self->lock); \
+  ret = _interpolate_trigger_get_##type (self, 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, GstValueArray * value_array) \
 { \
   gint i; \
   GstClockTime ts = timestamp; \
   g##type *values = (g##type *) value_array->values; \
+  GValue *ret; \
   \
+  g_mutex_lock (self->lock); \
   for(i = 0; i < value_array->nbsamples; i++) { \
-    *values = g_value_get_##type (interpolate_trigger_get_##type (prop,ts)); \
+    ret = _interpolate_trigger_get_##type (self, timestamp); \
+    if (!ret) { \
+      g_mutex_unlock (self->lock); \
+      return FALSE; \
+    } \
+    *values = g_value_get_##type (ret); \
     ts += value_array->sample_interval; \
     values++; \
   } \
+  g_mutex_unlock (self->lock); \
   return TRUE; \
 }
 
-DEFINE_TRIGGER_GET_VALUE_ARRAY (int);
 
-DEFINE_TRIGGER_GET_VALUE_ARRAY (uint);
-DEFINE_TRIGGER_GET_VALUE_ARRAY (long);
+DEFINE_TRIGGER_GET (int);
 
-DEFINE_TRIGGER_GET_VALUE_ARRAY (ulong);
-DEFINE_TRIGGER_GET_VALUE_ARRAY (float);
-DEFINE_TRIGGER_GET_VALUE_ARRAY (double);
+DEFINE_TRIGGER_GET (uint);
+DEFINE_TRIGGER_GET (long);
 
-DEFINE_TRIGGER_GET_VALUE_ARRAY (boolean);
+DEFINE_TRIGGER_GET (ulong);
+DEFINE_TRIGGER_GET (int64);
+DEFINE_TRIGGER_GET (uint64);
+DEFINE_TRIGGER_GET (float);
+DEFINE_TRIGGER_GET (double);
+
+static inline GValue *
+_interpolate_trigger_get (GstInterpolationControlSource * self,
+    GstClockTime timestamp)
+{
+  GList *node;
+  GstControlPoint *cp;
+
+  /* check if there is a value at the registered timestamp */
+  if ((node =
+          gst_interpolation_control_source_find_control_point_node (self,
+              timestamp))) {
+    cp = node->data;
+    if (timestamp == cp->timestamp) {
+      return &cp->value;
+    }
+  }
+  if (self->priv->nvalues > 0)
+    return &self->priv->default_value;
+  else
+    return NULL;
+}
 
 static gboolean
-interpolate_trigger_get_enum_value_array (GstControlledProperty * prop,
-    GstClockTime timestamp, GstValueArray * value_array)
+interpolate_trigger_get (GstInterpolationControlSource * self,
+    GstClockTime timestamp, GValue * value)
+{
+  GValue *ret;
+
+  g_mutex_lock (self->lock);
+  ret = _interpolate_trigger_get (self, 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_boolean_value_array (GstInterpolationControlSource *
+    self, GstClockTime timestamp, GstValueArray * value_array)
 {
   gint i;
   GstClockTime ts = timestamp;
   gint *values = (gint *) value_array->values;
+  GValue *ret;
 
+  g_mutex_lock (self->lock);
   for (i = 0; i < value_array->nbsamples; i++) {
-    *values = g_value_get_enum (interpolate_trigger_get (prop, ts));
+    ret = _interpolate_trigger_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = g_value_get_boolean (ret);
     ts += value_array->sample_interval;
     values++;
   }
+  g_mutex_unlock (self->lock);
   return TRUE;
 }
 
 static gboolean
-interpolate_trigger_get_string_value_array (GstControlledProperty * prop,
+interpolate_trigger_get_enum_value_array (GstInterpolationControlSource * self,
     GstClockTime timestamp, GstValueArray * value_array)
 {
   gint i;
   GstClockTime ts = timestamp;
+  gint *values = (gint *) value_array->values;
+  GValue *ret;
+
+  g_mutex_lock (self->lock);
+  for (i = 0; i < value_array->nbsamples; i++) {
+    ret = _interpolate_trigger_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = g_value_get_enum (ret);
+    ts += value_array->sample_interval;
+    values++;
+  }
+  g_mutex_unlock (self->lock);
+  return TRUE;
+}
+
+static gboolean
+interpolate_trigger_get_string_value_array (GstInterpolationControlSource *
+    self, GstClockTime timestamp, GstValueArray * value_array)
+{
+  gint i;
+  GstClockTime ts = timestamp;
   gchar **values = (gchar **) value_array->values;
+  GValue *ret;
 
+  g_mutex_lock (self->lock);
   for (i = 0; i < value_array->nbsamples; i++) {
-    *values = (gchar *) g_value_get_string (interpolate_trigger_get (prop, ts));
+    ret = _interpolate_trigger_get (self, timestamp);
+    if (!ret) {
+      g_mutex_unlock (self->lock);
+      return FALSE;
+    }
+    *values = (gchar *) g_value_get_string (ret);
     ts += value_array->sample_interval;
     values++;
   }
+  g_mutex_unlock (self->lock);
   return TRUE;
 }
 
 static GstInterpolateMethod interpolate_trigger = {
-  interpolate_trigger_get_int,
-  interpolate_trigger_get_int_value_array,
-  interpolate_trigger_get_uint,
-  interpolate_trigger_get_uint_value_array,
-  interpolate_trigger_get_long,
-  interpolate_trigger_get_long_value_array,
-  interpolate_trigger_get_ulong,
-  interpolate_trigger_get_ulong_value_array,
-  interpolate_trigger_get_float,
-  interpolate_trigger_get_float_value_array,
-  interpolate_trigger_get_double,
-  interpolate_trigger_get_double_value_array,
-  interpolate_trigger_get,
-  interpolate_trigger_get_boolean_value_array,
-  interpolate_trigger_get,
-  interpolate_trigger_get_enum_value_array,
-  interpolate_trigger_get,
-  interpolate_trigger_get_string_value_array
+  (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,
+  (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array,
+  (GstControlSourceGetValue) interpolate_trigger_get,
+  (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array,
+  (GstControlSourceGetValue) interpolate_trigger_get,
+  (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array
 };
 
 /*  linear interpolation */
 /*  smoothes inbetween values */
 
 #define DEFINE_LINEAR_GET(type) \
-static g##type \
-_interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static inline gboolean \
+_interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
 { \
   GList *node; \
-  g##type ret; \
   \
-  if ((node = gst_controlled_property_find_control_point_node (prop, timestamp))) { \
+  if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
     GstControlPoint *cp1, *cp2; \
     \
     cp1 = node->data; \
@@ -361,38 +553,53 @@ _interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime times
       value2 = g_value_get_##type (&cp2->value); \
       slope = (gdouble) (value2 - value1) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
       \
-      ret = (g##type) (value1 + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \
+      *ret = (g##type) (value1 + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \
     } \
     else { \
-      ret = g_value_get_##type (&cp1->value); \
+      *ret = g_value_get_##type (&cp1->value); \
     } \
   } else { \
-    ret = g_value_get_##type (&prop->default_value); \
+    GValue *first = gst_interpolation_control_source_get_first_value (self); \
+    if (!first) \
+      return FALSE; \
+    *ret = g_value_get_##type (first); \
   } \
-  ret = CLAMP (ret, g_value_get_##type (&prop->min_value), g_value_get_##type (&prop->max_value)); \
-  return ret; \
+  *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
+  return TRUE; \
 } \
 \
-static GValue * \
-interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static gboolean \
+interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
 { \
-  g_value_set_##type (&prop->result_value,_interpolate_linear_get_##type (prop,timestamp)); \
-  return &prop->result_value; \
+  g##type ret; \
+  g_mutex_lock (self->lock); \
+  if (_interpolate_linear_get_##type (self, timestamp, &ret)) { \
+    g_value_set_##type (value, ret); \
+    g_mutex_unlock (self->lock); \
+    return TRUE; \
+  } \
+  g_mutex_unlock (self->lock); \
+  return FALSE; \
 } \
 \
 static gboolean \
-interpolate_linear_get_##type##_value_array (GstControlledProperty * prop, \
+interpolate_linear_get_##type##_value_array (GstInterpolationControlSource *self, \
     GstClockTime timestamp, GstValueArray * value_array) \
 { \
   gint i; \
   GstClockTime ts = timestamp; \
   g##type *values = (g##type *) value_array->values; \
   \
+  g_mutex_lock (self->lock); \
   for(i = 0; i < value_array->nbsamples; i++) { \
-    *values = _interpolate_linear_get_##type (prop, ts); \
+    if (! _interpolate_linear_get_##type (self, ts, values)) { \
+      g_mutex_unlock (self->lock); \
+      return FALSE; \
+    } \
     ts += value_array->sample_interval; \
     values++; \
   } \
+  g_mutex_unlock (self->lock); \
   return TRUE; \
 }
 
@@ -402,28 +609,34 @@ DEFINE_LINEAR_GET (uint);
 DEFINE_LINEAR_GET (long);
 
 DEFINE_LINEAR_GET (ulong);
+DEFINE_LINEAR_GET (int64);
+DEFINE_LINEAR_GET (uint64);
 DEFINE_LINEAR_GET (float);
 DEFINE_LINEAR_GET (double);
 
 static GstInterpolateMethod interpolate_linear = {
-  interpolate_linear_get_int,
-  interpolate_linear_get_int_value_array,
-  interpolate_linear_get_uint,
-  interpolate_linear_get_uint_value_array,
-  interpolate_linear_get_long,
-  interpolate_linear_get_long_value_array,
-  interpolate_linear_get_ulong,
-  interpolate_linear_get_ulong_value_array,
-  interpolate_linear_get_float,
-  interpolate_linear_get_float_value_array,
-  interpolate_linear_get_double,
-  interpolate_linear_get_double_value_array,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL
+  (GstControlSourceGetValue) interpolate_linear_get_int,
+  (GstControlSourceGetValueArray) interpolate_linear_get_int_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_uint,
+  (GstControlSourceGetValueArray) interpolate_linear_get_uint_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_long,
+  (GstControlSourceGetValueArray) interpolate_linear_get_long_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_ulong,
+  (GstControlSourceGetValueArray) interpolate_linear_get_ulong_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_int64,
+  (GstControlSourceGetValueArray) interpolate_linear_get_int64_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_uint64,
+  (GstControlSourceGetValueArray) interpolate_linear_get_uint64_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_float,
+  (GstControlSourceGetValueArray) interpolate_linear_get_float_value_array,
+  (GstControlSourceGetValue) interpolate_linear_get_double,
+  (GstControlSourceGetValueArray) interpolate_linear_get_double_value_array,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL
 };
 
 /*  square interpolation */
@@ -445,9 +658,9 @@ static GstInterpolateMethod interpolate_linear = {
 
 #define DEFINE_CUBIC_GET(type) \
 static void \
-_interpolate_cubic_update_cache_##type (GstControlledProperty *prop) \
+_interpolate_cubic_update_cache_##type (GstInterpolationControlSource *self) \
 { \
-  gint i, n = prop->nvalues; \
+  gint i, n = self->priv->nvalues; \
   gdouble *o = g_new0 (gdouble, n); \
   gdouble *p = g_new0 (gdouble, n); \
   gdouble *q = g_new0 (gdouble, n); \
@@ -462,7 +675,7 @@ _interpolate_cubic_update_cache_##type (GstControlledProperty *prop) \
   g##type y_prev, y, y_next; \
   \
   /* Fill linear system of equations */ \
-  node = prop->values; \
+  node = self->priv->values; \
   cp = node->data; \
   x = cp->timestamp; \
   y = g_value_get_##type (&cp->value); \
@@ -508,7 +721,7 @@ _interpolate_cubic_update_cache_##type (GstControlledProperty *prop) \
   \
   /* Save cache next in the GstControlPoint */ \
   \
-  node = prop->values; \
+  node = self->priv->values; \
   for (i = 0; i < n; i++) { \
     cp = node->data; \
     cp->cache.cubic.h = h[i]; \
@@ -525,21 +738,20 @@ _interpolate_cubic_update_cache_##type (GstControlledProperty *prop) \
   g_free (z); \
 } \
 \
-static g##type \
-_interpolate_cubic_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static inline gboolean \
+_interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
 { \
   GList *node; \
-  g##type ret; \
   \
-  if (prop->nvalues <= 2) \
-    return _interpolate_linear_get_##type (prop, timestamp); \
+  if (self->priv->nvalues <= 2) \
+    return _interpolate_linear_get_##type (self, timestamp, ret); \
   \
-  if (!prop->valid_cache) { \
-    _interpolate_cubic_update_cache_##type (prop); \
-    prop->valid_cache = TRUE; \
+  if (!self->priv->valid_cache) { \
+    _interpolate_cubic_update_cache_##type (self); \
+    self->priv->valid_cache = TRUE; \
   } \
   \
-  if ((node = gst_controlled_property_find_control_point_node (prop, timestamp))) { \
+  if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
     GstControlPoint *cp1, *cp2; \
     \
     cp1 = node->data; \
@@ -560,38 +772,53 @@ _interpolate_cubic_get_##type (GstControlledProperty * prop, GstClockTime timest
       out += (value2 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
       out += (value1 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
       \
-      ret = (g##type) out; \
+      *ret = (g##type) out; \
     } \
     else { \
-      ret = g_value_get_##type (&cp1->value); \
+      *ret = g_value_get_##type (&cp1->value); \
     } \
-  } else {\
-    ret = g_value_get_##type (&prop->default_value); \
+  } else { \
+    GValue *first = gst_interpolation_control_source_get_first_value (self); \
+    if (!first) \
+      return FALSE; \
+    *ret = g_value_get_##type (first); \
   } \
-  ret = CLAMP (ret, g_value_get_##type (&prop->min_value), g_value_get_##type (&prop->max_value)); \
-  return ret; \
+  *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
+  return TRUE; \
 } \
 \
-static GValue * \
-interpolate_cubic_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
+static gboolean \
+interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
 { \
-  g_value_set_##type (&prop->result_value,_interpolate_cubic_get_##type (prop,timestamp)); \
-  return &prop->result_value; \
+  g##type ret; \
+  g_mutex_lock (self->lock); \
+  if (_interpolate_cubic_get_##type (self, timestamp, &ret)) { \
+    g_value_set_##type (value, ret); \
+    g_mutex_unlock (self->lock); \
+    return TRUE; \
+  } \
+  g_mutex_unlock (self->lock); \
+  return FALSE; \
 } \
 \
 static gboolean \
-interpolate_cubic_get_##type##_value_array (GstControlledProperty * prop, \
+interpolate_cubic_get_##type##_value_array (GstInterpolationControlSource *self, \
     GstClockTime timestamp, GstValueArray * value_array) \
 { \
   gint i; \
   GstClockTime ts = timestamp; \
   g##type *values = (g##type *) value_array->values; \
   \
+  g_mutex_lock (self->lock); \
   for(i = 0; i < value_array->nbsamples; i++) { \
-    *values = _interpolate_cubic_get_##type (prop, ts); \
+    if (! _interpolate_cubic_get_##type (self, ts, values)) { \
+      g_mutex_unlock (self->lock); \
+      return FALSE; \
+    } \
     ts += value_array->sample_interval; \
     values++; \
   } \
+  g_mutex_unlock (self->lock); \
   return TRUE; \
 }
 
@@ -601,28 +828,34 @@ DEFINE_CUBIC_GET (uint);
 DEFINE_CUBIC_GET (long);
 
 DEFINE_CUBIC_GET (ulong);
+DEFINE_CUBIC_GET (int64);
+DEFINE_CUBIC_GET (uint64);
 DEFINE_CUBIC_GET (float);
 DEFINE_CUBIC_GET (double);
 
 static GstInterpolateMethod interpolate_cubic = {
-  interpolate_cubic_get_int,
-  interpolate_cubic_get_int_value_array,
-  interpolate_cubic_get_uint,
-  interpolate_cubic_get_uint_value_array,
-  interpolate_cubic_get_long,
-  interpolate_cubic_get_long_value_array,
-  interpolate_cubic_get_ulong,
-  interpolate_cubic_get_ulong_value_array,
-  interpolate_cubic_get_float,
-  interpolate_cubic_get_float_value_array,
-  interpolate_cubic_get_double,
-  interpolate_cubic_get_double_value_array,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL
+  (GstControlSourceGetValue) interpolate_cubic_get_int,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_int_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_uint,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_uint_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_long,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_long_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_ulong,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_ulong_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_int64,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_int64_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_uint64,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_uint64_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_float,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_float_value_array,
+  (GstControlSourceGetValue) interpolate_cubic_get_double,
+  (GstControlSourceGetValueArray) interpolate_cubic_get_double_value_array,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL,
+  (GstControlSourceGetValue) NULL,
+  (GstControlSourceGetValueArray) NULL
 };
 
 
diff --git a/libs/gst/controller/gstinterpolationcontrolsource.c b/libs/gst/controller/gstinterpolationcontrolsource.c
new file mode 100644 (file)
index 0000000..30e9866
--- /dev/null
@@ -0,0 +1,667 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstinterpolationcontrolsource.c: Control source that provides several
+ *                                  interpolation methods
+ *
+ * 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:gstinterpolationcontrolsource
+ * @short_description: interpolation control source
+ *
+ * #GstInterpolationControlSource is a #GstControlSource, that interpolates values between user-given
+ * control points. It supports several interpolation modes and property types.
+ *
+ * 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().
+ *
+ * All functions are MT-safe.
+ *
+ */
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "gstcontrolsource.h"
+#include "gstinterpolationcontrolsource.h"
+#include "gstinterpolationcontrolsourceprivate.h"
+
+extern GstInterpolateMethod *interpolation_methods[];
+extern guint num_interpolation_methods;
+
+static void gst_interpolation_control_source_init (GstInterpolationControlSource
+    * self);
+static void
+gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
+    * klass);
+
+G_DEFINE_TYPE (GstInterpolationControlSource, gst_interpolation_control_source,
+    GST_TYPE_CONTROL_SOURCE);
+
+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)
+{
+  g_return_if_fail (cp);
+
+  g_value_unset (&cp->value);
+  g_free (cp);
+}
+
+static void
+gst_interpolation_control_source_reset (GstInterpolationControlSource * self)
+{
+  GstControlSource *csource = GST_CONTROL_SOURCE (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_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL);
+    g_list_free (self->priv->values);
+    self->priv->values = NULL;
+  }
+
+  self->priv->nvalues = 0;
+  self->priv->last_requested_value = NULL;
+  self->priv->valid_cache = FALSE;
+}
+
+/**
+ * gst_interpolation_control_source_new:
+ *
+ * This returns a new, unbound #GstInterpolationControlSource.
+ *
+ * Returns: a new, unbound #GstInterpolationControlSource.
+ */
+GstInterpolationControlSource *
+gst_interpolation_control_source_new ()
+{
+  return g_object_new (GST_TYPE_INTERPOLATION_CONTROL_SOURCE, NULL);
+}
+
+/**
+ * gst_interpolation_control_source_set_interpolation_mode:
+ * @self: the #GstInterpolationControlSource object
+ * @mode: interpolation mode
+ *
+ * Sets the given interpolation mode.
+ *
+ * <note><para>User interpolation is not yet available and quadratic interpolation
+ * is deprecated and maps to cubic interpolation.</para></note>
+ *
+ * Returns: %TRUE if the interpolation mode could be set, %FALSE otherwise
+ */
+gboolean
+    gst_interpolation_control_source_set_interpolation_mode
+    (GstInterpolationControlSource * self, GstInterpolateMode mode) {
+  gboolean ret = TRUE;
+  GstControlSource *csource = GST_CONTROL_SOURCE (self);
+
+  if (mode >= num_interpolation_methods || interpolation_methods[mode] == NULL) {
+    GST_WARNING ("interpolation mode %d invalid or not implemented yet", mode);
+    return FALSE;
+  }
+
+  if (mode == GST_INTERPOLATE_QUADRATIC) {
+    GST_WARNING ("Quadratic interpolation mode is deprecated, using cubic"
+        "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) {
+    case G_TYPE_INT:
+      csource->get_value = interpolation_methods[mode]->get_int;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_int_value_array;
+      break;
+    case G_TYPE_UINT:{
+      csource->get_value = interpolation_methods[mode]->get_uint;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_uint_value_array;
+      break;
+    }
+    case G_TYPE_LONG:{
+      csource->get_value = interpolation_methods[mode]->get_long;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_long_value_array;
+      break;
+    }
+    case G_TYPE_ULONG:{
+      csource->get_value = interpolation_methods[mode]->get_ulong;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_ulong_value_array;
+      break;
+    }
+    case G_TYPE_INT64:{
+      csource->get_value = interpolation_methods[mode]->get_int64;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_int64_value_array;
+      break;
+    }
+    case G_TYPE_UINT64:{
+      csource->get_value = interpolation_methods[mode]->get_uint64;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_uint64_value_array;
+      break;
+    }
+    case G_TYPE_FLOAT:{
+      csource->get_value = interpolation_methods[mode]->get_float;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_float_value_array;
+      break;
+    }
+    case G_TYPE_DOUBLE:{
+      csource->get_value = interpolation_methods[mode]->get_double;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_double_value_array;
+      break;
+    }
+    case G_TYPE_BOOLEAN:{
+      csource->get_value = interpolation_methods[mode]->get_boolean;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_boolean_value_array;
+      break;
+    }
+    case G_TYPE_ENUM:{
+      csource->get_value = interpolation_methods[mode]->get_enum;
+      csource->get_value_array =
+          interpolation_methods[mode]->get_enum_value_array;
+      break;
+    }
+    case G_TYPE_STRING:{
+      csource->get_value = interpolation_methods[mode]->get_string;
+      csource->get_value_array =
+          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);
+    ret = FALSE;
+  }
+
+  self->priv->valid_cache = FALSE;
+  self->priv->interpolation_mode = mode;
+
+  g_mutex_unlock (self->lock);
+
+  return ret;
+}
+
+static gboolean
+gst_interpolation_control_source_bind (GstControlSource * source,
+    GParamSpec * pspec)
+{
+  GType type, base;
+  GstInterpolationControlSource *self =
+      GST_INTERPOLATION_CONTROL_SOURCE (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 void
+gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
+    self, GstClockTime timestamp, GValue * value)
+{
+  GstControlPoint *cp;
+  GList *node;
+
+  /* check if a control point for the timestamp already exists */
+  if ((node = g_list_find_custom (self->priv->values, &timestamp,
+              gst_control_point_find))) {
+    cp = node->data;
+    g_value_reset (&cp->value);
+    g_value_copy (value, &cp->value);
+  } else {
+    /* create a new GstControlPoint */
+    cp = g_new0 (GstControlPoint, 1);
+    cp->timestamp = timestamp;
+    g_value_init (&cp->value, self->priv->type);
+    g_value_copy (value, &cp->value);
+    /* and sort it into the prop->values list */
+    self->priv->values =
+        g_list_insert_sorted (self->priv->values, cp,
+        gst_control_point_compare);
+    self->priv->nvalues++;
+  }
+  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, GValue * value)
+{
+  g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE);
+  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
+  g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+  g_return_val_if_fail (G_VALUE_TYPE (value) == self->priv->type, FALSE);
+
+  g_mutex_lock (self->lock);
+  gst_interpolation_control_source_set_internal (self, timestamp, value);
+  g_mutex_unlock (self->lock);
+
+  return TRUE;
+}
+
+/**
+ * gst_interpolation_control_source_set_from_list:
+ * @self: the #GstInterpolationControlSource object
+ * @timedvalues: 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, GSList * timedvalues)
+{
+  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)
+{
+  GList *node;
+  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 ((node = g_list_find_custom (self->priv->values, &timestamp,
+              gst_control_point_find))) {
+    GstControlPoint *cp = node->data;
+
+    if (cp->timestamp == 0) {
+      /* Restore the default node */
+      g_value_reset (&cp->value);
+      g_value_copy (&self->priv->default_value, &cp->value);
+    } else {
+      if (node == self->priv->last_requested_value)
+        self->priv->last_requested_value = NULL;
+      gst_control_point_free (node->data);      /* free GstControlPoint */
+      self->priv->values = g_list_delete_link (self->priv->values, node);
+      self->priv->nvalues--;
+    }
+    self->priv->valid_cache = FALSE;
+    res = TRUE;
+  }
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_interpolation_control_source_unset_all:
+ * @self: the #GstInterpolationControlSource object
+ *
+ * Used to remove all time-stamped values of given controller-handled property
+ *
+ */
+void
+gst_interpolation_control_source_unset_all (GstInterpolationControlSource *
+    self)
+{
+  g_return_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self));
+
+  g_mutex_lock (self->lock);
+  /* free GstControlPoint structures */
+  g_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL);
+  g_list_free (self->priv->values);
+  self->priv->last_requested_value = NULL;
+  self->priv->values = NULL;
+  self->priv->nvalues = 0;
+  self->priv->valid_cache = FALSE;
+
+  g_mutex_unlock (self->lock);
+}
+
+/**
+ * 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: 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)
+{
+  GList *res = NULL;
+
+  g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), NULL);
+
+  g_mutex_lock (self->lock);
+  if (self->priv->values)
+    res = g_list_copy (self->priv->values);
+  g_mutex_unlock (self->lock);
+
+  return res;
+}
+
+/**
+ * gst_interpolation_control_source_get_count:
+ * @self: the #GstInterpolationControlSource to get the number of values from
+ *
+ * Returns the number of control points that are set.
+ *
+ * Returns: the number of control points that are set.
+ *
+ */
+gint
+gst_interpolation_control_source_get_count (GstInterpolationControlSource *
+    self)
+{
+  g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), 0);
+  return self->priv->nvalues;
+}
+
+static void
+gst_interpolation_control_source_init (GstInterpolationControlSource * self)
+{
+  self->lock = g_mutex_new ();
+  self->priv =
+      G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INTERPOLATION_CONTROL_SOURCE,
+      GstInterpolationControlSourcePrivate);
+  self->priv->interpolation_mode = GST_INTERPOLATE_NONE;
+}
+
+static void
+gst_interpolation_control_source_finalize (GObject * obj)
+{
+  GstInterpolationControlSource *self = GST_INTERPOLATION_CONTROL_SOURCE (obj);
+
+  g_mutex_lock (self->lock);
+  gst_interpolation_control_source_reset (self);
+  g_mutex_unlock (self->lock);
+  g_mutex_free (self->lock);
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_interpolation_control_source_dispose (GObject * obj)
+{
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_interpolation_control_source_class_init (GstInterpolationControlSourceClass
+    * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+  g_type_class_add_private (klass,
+      sizeof (GstInterpolationControlSourcePrivate));
+
+  gobject_class->finalize = gst_interpolation_control_source_finalize;
+  gobject_class->dispose = gst_interpolation_control_source_dispose;
+  csource_class->bind = gst_interpolation_control_source_bind;
+}
diff --git a/libs/gst/controller/gstinterpolationcontrolsource.h b/libs/gst/controller/gstinterpolationcontrolsource.h
new file mode 100644 (file)
index 0000000..233909d
--- /dev/null
@@ -0,0 +1,109 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstinterpolationcontrolsource.h: Control source that provides several
+ *                                  interpolation methods
+ *
+ * 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_INTERPOLATION_CONTROL_SOURCE_H__
+#define __GST_INTERPOLATION_CONTROL_SOURCE_H__
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "gstcontrolsource.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_INTERPOLATION_CONTROL_SOURCE \
+  (gst_interpolation_control_source_get_type ())
+#define GST_INTERPOLATION_CONTROL_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INTERPOLATION_CONTROL_SOURCE, GstInterpolationControlSource))
+#define GST_INTERPOLATION_CONTROL_SOURCE_CLASS(vtable) \
+  (G_TYPE_CHECK_CLASS_CAST ((vtable), GST_TYPE_INTERPOLATION_CONTROL_SOURCE, GstInterpolationControlSourceClass))
+#define GST_IS_INTERPOLATION_CONTROL_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INTERPOLATION_CONTROL_SOURCE))
+#define GST_IS_INTERPOLATION_CONTROL_SOURCE_CLASS(vtable) \
+  (G_TYPE_CHECK_CLASS_TYPE ((vtable), GST_TYPE_INTERPOLATION_CONTROL_SOURCE))
+#define GST_INTERPOLATION_CONTROL_SOURCE_GET_CLASS(inst) \
+  (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_INTERPOLATION_CONTROL_SOURCE, GstInterpolationControlSourceClass))
+
+typedef struct _GstInterpolationControlSource GstInterpolationControlSource;
+typedef struct _GstInterpolationControlSourceClass GstInterpolationControlSourceClass;
+typedef struct _GstInterpolationControlSourcePrivate GstInterpolationControlSourcePrivate;
+
+/**
+ * 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
+} GstInterpolateMode;
+
+/**
+ * GstInterpolationControlSource:
+ *
+ * The instance structure of #GstControlSource.
+ */
+struct _GstInterpolationControlSource {
+  GstControlSource parent;
+
+  /* <private> */
+  GMutex *lock;
+  GstInterpolationControlSourcePrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstInterpolationControlSourceClass {
+  GstControlSourceClass parent_class;
+  
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_interpolation_control_source_get_type ();
+
+/* Functions */
+
+GstInterpolationControlSource *gst_interpolation_control_source_new ();
+gboolean gst_interpolation_control_source_set_interpolation_mode (GstInterpolationControlSource *self, GstInterpolateMode mode);
+gboolean gst_interpolation_control_source_set (GstInterpolationControlSource * self, GstClockTime timestamp, GValue * value);
+gboolean gst_interpolation_control_source_set_from_list (GstInterpolationControlSource * self, 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
+
+#endif /* __GST_INTERPOLATION_CONTROL_SOURCE_H__ */
diff --git a/libs/gst/controller/gstinterpolationcontrolsourceprivate.h b/libs/gst/controller/gstinterpolationcontrolsourceprivate.h
new file mode 100644 (file)
index 0000000..5258d56
--- /dev/null
@@ -0,0 +1,100 @@
+/* GStreamer
+ *
+ * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstinterpolationcontrolsourceprivate.h: Private declarations for the
+ *                                         GstInterpolationControlSource
+ *
+ * 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_INTERPOLATION_CONTROL_SOURCE_PRIVATE_H__
+#define __GST_INTERPOLATION_CONTROL_SOURCE_PRIVATE_H__
+
+/**
+ * GstInterpolateMethod:
+ *
+ * Function pointer structure to do user-defined interpolation methods
+ */
+typedef struct _GstInterpolateMethod
+{
+  GstControlSourceGetValue get_int;
+  GstControlSourceGetValueArray get_int_value_array;
+  GstControlSourceGetValue get_uint;
+  GstControlSourceGetValueArray get_uint_value_array;
+  GstControlSourceGetValue get_long;
+  GstControlSourceGetValueArray get_long_value_array;
+  GstControlSourceGetValue get_ulong;
+  GstControlSourceGetValueArray get_ulong_value_array;
+  GstControlSourceGetValue get_int64;
+  GstControlSourceGetValueArray get_int64_value_array;
+  GstControlSourceGetValue get_uint64;
+  GstControlSourceGetValueArray get_uint64_value_array;
+  GstControlSourceGetValue get_float;
+  GstControlSourceGetValueArray get_float_value_array;
+  GstControlSourceGetValue get_double;
+  GstControlSourceGetValueArray get_double_value_array;
+  GstControlSourceGetValue get_boolean;
+  GstControlSourceGetValueArray get_boolean_value_array;
+  GstControlSourceGetValue get_enum;
+  GstControlSourceGetValueArray get_enum_value_array;
+  GstControlSourceGetValue get_string;
+  GstControlSourceGetValueArray get_string_value_array;
+} GstInterpolateMethod;
+
+/**
+ * GstControlPoint:
+ *
+ * a internal structure for value+time and various temporary
+ * values used for interpolation. This "inherits" from
+ * GstTimedValue.
+ */
+typedef struct _GstControlPoint
+{
+  /* fields from GstTimedValue. DO NOT CHANGE! */
+  GstClockTime timestamp;       /* timestamp of the value change */
+  GValue value;                 /* the new value */
+
+  /* internal fields */
+
+  /* Caches for the interpolators */
+  union {
+    struct {
+      gdouble h;
+      gdouble z;
+    } cubic;
+  } cache;
+
+} 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;
+  
+  GList *values;                /* List of GstControlPoint */
+  gint nvalues;                 /* Number of control points */
+  GList *last_requested_value;  /* last search result, can be used for incremental searches */
+  gboolean valid_cache;
+};
+
+#endif /* __GST_INTERPOLATION_CONTROL_SOURCE_PRIVATE_H__ */
+
index ac9ac17..08e0aa5 100644 (file)
@@ -2,7 +2,8 @@
  *
  * unit test for the controller library
  *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dor net>
+ * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
+ * Copyright (C) <2006> Sebastian Dröge <slomo@circular-chaos.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -26,6 +27,8 @@
 #include <gst/gst.h>
 #include <gst/check/gstcheck.h>
 #include <gst/controller/gstcontroller.h>
+#include <gst/controller/gstcontrolsource.h>
+#include <gst/controller/gstinterpolationcontrolsource.h>
 
 /* LOCAL TEST ELEMENT */
 
@@ -507,10 +510,53 @@ GST_START_TEST (controller_finalize)
 
 GST_END_TEST;
 
+/* tests if we cleanup properly */
+GST_START_TEST (controller_controlsource_refcounts)
+{
+  GstController *ctrl;
+  GstElement *elem;
+  GstControlSource *csource, *test_csource;
+
+  gst_controller_init (NULL, NULL);
+
+  elem = gst_element_factory_make ("testmonosource", "test_source");
+
+  /* that property should exist and should be controllable */
+  ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+  fail_unless (ctrl != NULL, NULL);
+
+  csource = (GstControlSource *) gst_interpolation_control_source_new ();
+  fail_unless (csource != NULL, NULL);
+
+  fail_unless_equals_int (G_OBJECT (csource)->ref_count, 1);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong", csource));
+  fail_unless_equals_int (G_OBJECT (csource)->ref_count, 2);
+
+  g_object_unref (G_OBJECT (csource));
+
+  test_csource = gst_controller_get_control_source (ctrl, "ulong");
+  fail_unless (test_csource != NULL, NULL);
+  fail_unless (test_csource == csource);
+  fail_unless_equals_int (G_OBJECT (csource)->ref_count, 2);
+  g_object_unref (csource);
+
+  /* free the controller */
+  g_object_unref (ctrl);
+
+  /* object shouldn't have a controller anymore */
+  ctrl = gst_object_get_controller (G_OBJECT (elem));
+  fail_unless (ctrl == NULL, NULL);
+
+  gst_object_unref (elem);
+}
+
+GST_END_TEST;
+
 /* test timed value handling without interpolation */
 GST_START_TEST (controller_interpolate_none)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
@@ -523,18 +569,35 @@ GST_START_TEST (controller_interpolate_none)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_NONE));
 
+  fail_unless (gst_interpolation_control_source_get_count (csource) == 0);
+
   /* set control values */
   g_value_init (&val_ulong, G_TYPE_ULONG);
   g_value_set_ulong (&val_ulong, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (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_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
+  fail_unless (gst_interpolation_control_source_get_count (csource) == 2);
+
+  g_object_unref (G_OBJECT (csource));
 
   /* now pull in values for some timestamps */
   gst_controller_sync_values (ctrl, 0 * GST_SECOND);
@@ -555,6 +618,7 @@ GST_END_TEST;
 GST_START_TEST (controller_interpolate_trigger)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
@@ -567,29 +631,50 @@ GST_START_TEST (controller_interpolate_trigger)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_TRIGGER));
 
-  /* set control values */
   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_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  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_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+  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_controller_sync_values (ctrl, 0 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
-  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
+          1 * GST_SECOND, &val_ulong));
   gst_controller_sync_values (ctrl, 1 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (gst_control_source_get_value (GST_CONTROL_SOURCE (csource),
+          2 * GST_SECOND, &val_ulong));
   gst_controller_sync_values (ctrl, 2 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
 
   GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
+  g_object_unref (G_OBJECT (csource));
   g_object_unref (ctrl);
   gst_object_unref (elem);
 }
@@ -600,6 +685,7 @@ GST_END_TEST;
 GST_START_TEST (controller_interpolate_linear)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
@@ -612,19 +698,32 @@ GST_START_TEST (controller_interpolate_linear)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  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, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  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_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
 
+  g_object_unref (G_OBJECT (csource));
+
   /* now pull in values for some timestamps */
   gst_controller_sync_values (ctrl, 0 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
@@ -644,6 +743,7 @@ GST_END_TEST;
 GST_START_TEST (controller_interpolate_cubic)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_double = { 0, };
@@ -656,25 +756,42 @@ GST_START_TEST (controller_interpolate_cubic)
   ctrl = gst_controller_new (G_OBJECT (elem), "double", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "double",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "double",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_CUBIC));
 
   /* set control values */
   g_value_init (&val_double, G_TYPE_DOUBLE);
   g_value_set_double (&val_double, 0.0);
-  res = gst_controller_set (ctrl, "double", 0 * GST_SECOND, &val_double);
+  res =
+      gst_interpolation_control_source_set (csource, 0 * GST_SECOND,
+      &val_double);
   fail_unless (res, NULL);
   g_value_set_double (&val_double, 5.0);
-  res = gst_controller_set (ctrl, "double", 1 * GST_SECOND, &val_double);
+  res =
+      gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
+      &val_double);
   fail_unless (res, NULL);
   g_value_set_double (&val_double, 2.0);
-  res = gst_controller_set (ctrl, "double", 2 * GST_SECOND, &val_double);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_double);
   fail_unless (res, NULL);
   g_value_set_double (&val_double, 8.0);
-  res = gst_controller_set (ctrl, "double", 4 * GST_SECOND, &val_double);
+  res =
+      gst_interpolation_control_source_set (csource, 4 * GST_SECOND,
+      &val_double);
   fail_unless (res, NULL);
 
+  g_object_unref (G_OBJECT (csource));
+
   /* now pull in values for some timestamps */
   gst_controller_sync_values (ctrl, 0 * GST_SECOND);
   fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_double, 0.0);
@@ -702,6 +819,7 @@ GST_END_TEST;
 GST_START_TEST (controller_interpolate_unimplemented)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
 
   gst_controller_init (NULL, NULL);
@@ -712,10 +830,19 @@ GST_START_TEST (controller_interpolate_unimplemented)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set completely bogus interpolation mode */
-  fail_if (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_if (gst_interpolation_control_source_set_interpolation_mode (csource,
           (GstInterpolateMode) 93871));
 
+  g_object_unref (G_OBJECT (csource));
+
   g_object_unref (ctrl);
   gst_object_unref (elem);
 }
@@ -723,9 +850,10 @@ GST_START_TEST (controller_interpolate_unimplemented)
 GST_END_TEST;
 
 /* test _unset() */
-GST_START_TEST (controller_unset)
+GST_START_TEST (controller_interpolation_unset)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
@@ -738,20 +866,33 @@ GST_START_TEST (controller_unset)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_NONE));
 
   /* set control values */
   g_value_init (&val_ulong, G_TYPE_ULONG);
   g_value_set_ulong (&val_ulong, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  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_controller_set (ctrl, "ulong", 1 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
   g_value_set_ulong (&val_ulong, 50);
-  res = gst_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
 
   /* verify values */
@@ -763,9 +904,11 @@ GST_START_TEST (controller_unset)
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
 
   /* unset second */
-  res = gst_controller_unset (ctrl, "ulong", 1 * GST_SECOND);
+  res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND);
   fail_unless (res, NULL);
 
+  g_object_unref (csource);
+
   /* verify value again */
   gst_controller_sync_values (ctrl, 1 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
@@ -780,9 +923,10 @@ GST_START_TEST (controller_unset)
 GST_END_TEST;
 
 /* test _unset_all() */
-GST_START_TEST (controller_unset_all)
+GST_START_TEST (controller_interpolation_unset_all)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
@@ -795,17 +939,28 @@ GST_START_TEST (controller_unset_all)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_NONE));
 
   /* set control values */
   g_value_init (&val_ulong, G_TYPE_ULONG);
   g_value_set_ulong (&val_ulong, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  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_controller_set (ctrl, "ulong", 1 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 1 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
 
   /* verify values */
@@ -815,12 +970,13 @@ GST_START_TEST (controller_unset_all)
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
 
   /* unset second */
-  res = gst_controller_unset_all (ctrl, "ulong");
-  fail_unless (res, NULL);
+  gst_interpolation_control_source_unset_all (csource);
+
+  g_object_unref (csource);
 
   /* verify value again */
   gst_controller_sync_values (ctrl, 1 * GST_SECOND);
-  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
 
   GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
   g_object_unref (ctrl);
@@ -829,13 +985,15 @@ GST_START_TEST (controller_unset_all)
 
 GST_END_TEST;
 
-/* test live value handling */
-GST_START_TEST (controller_live)
+/* test retrieval of an array of values with get_value_array() */
+GST_START_TEST (controller_interpolation_linear_value_array)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstElement *elem;
   gboolean res;
   GValue val_ulong = { 0, };
+  GstValueArray values = { 0, };
 
   gst_controller_init (NULL, NULL);
 
@@ -845,38 +1003,205 @@ GST_START_TEST (controller_live)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  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, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
+  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_controller_set (ctrl, "ulong", 4 * GST_SECOND, &val_ulong);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_ulong);
   fail_unless (res, NULL);
-  g_value_set_ulong (&val_ulong, 200);
-  res = gst_controller_set (ctrl, "ulong", 8 * GST_SECOND, &val_ulong);
+
+  /* now pull in values for some timestamps */
+  values.property_name = "ulong";
+  values.nbsamples = 3;
+  values.sample_interval = GST_SECOND;
+  values.values = (gpointer) g_new (gulong, 3);
+
+  fail_unless (gst_control_source_get_value_array (GST_CONTROL_SOURCE (csource),
+          0, &values));
+  fail_unless_equals_int (((gulong *) values.values)[0], 0);
+  fail_unless_equals_int (((gulong *) values.values)[1], 50);
+  fail_unless_equals_int (((gulong *) values.values)[2], 100);
+
+  g_object_unref (csource);
+
+  GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
+  g_free (values.values);
+  g_object_unref (ctrl);
+  gst_object_unref (elem);
+}
+
+GST_END_TEST;
+
+/* test if values below minimum and above maximum are clipped */
+GST_START_TEST (controller_interpolation_linear_invalid_values)
+{
+  GstController *ctrl;
+  GstInterpolationControlSource *csource;
+  GstElement *elem;
+  gboolean res;
+  GValue val_float = { 0, };
+
+  gst_controller_init (NULL, NULL);
+
+  elem = gst_element_factory_make ("testmonosource", "test_source");
+
+  /* that property should exist and should be controllable */
+  ctrl = gst_controller_new (G_OBJECT (elem), "float", NULL);
+  fail_unless (ctrl != NULL, NULL);
+
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "float",
+          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_float, G_TYPE_FLOAT);
+  g_value_set_float (&val_float, 200.0);
+  res =
+      gst_interpolation_control_source_set (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);
   fail_unless (res, NULL);
 
-  /* verify value */
+  g_object_unref (csource);
+
+  /* now pull in values for some timestamps and see if clipping works */
+  /* 200.0 */
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 100.0);
+  /* 100.0 */
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 100.0);
+  /* 50.0 */
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND + 500 * GST_MSECOND);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 50.0);
+  /* 0.0 */
   gst_controller_sync_values (ctrl, 2 * GST_SECOND);
-  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
+  /* -100.0 */
+  gst_controller_sync_values (ctrl, 3 * GST_SECOND);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
+  /* -200.0 */
+  gst_controller_sync_values (ctrl, 4 * GST_SECOND);
+  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
+
+  GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
+  g_object_unref (ctrl);
+  gst_object_unref (elem);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (controller_interpolation_linear_default_values)
+{
+  GstController *ctrl;
+  GstInterpolationControlSource *csource;
+  GstElement *elem;
+  gboolean res;
+  GValue val_ulong = { 0, };
+
+  gst_controller_init (NULL, NULL);
+
+  elem = gst_element_factory_make ("testmonosource", "test_source");
+
+  /* that property should exist and should be controllable */
+  ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
+  fail_unless (ctrl != NULL, NULL);
+
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
+  /* set interpolation mode */
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
+          GST_INTERPOLATE_LINEAR));
+
+  /* Should fail if no value was set yet */
+  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 live value */
-  g_object_set (elem, "ulong", 500, NULL);
+  /* set control values */
+  g_value_set_ulong (&val_ulong, 0);
+  res =
+      gst_interpolation_control_source_set (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);
+  fail_unless (res, NULL);
 
-  /* we should still get the live value */
+  /* now pull in values for some timestamps */
+  /* should give the value of the first control point for timestamps before it */
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
   gst_controller_sync_values (ctrl, 3 * GST_SECOND);
-  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 500, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
 
-  /* we should not get the live value anymore */
-  gst_controller_sync_values (ctrl, 4 * GST_SECOND);
+  /* set control values */
+  g_value_set_ulong (&val_ulong, 0);
+  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);
+
+  /* unset the old ones */
+  res = gst_interpolation_control_source_unset (csource, 1 * GST_SECOND);
+  fail_unless (res, NULL);
+  res = gst_interpolation_control_source_unset (csource, 3 * GST_SECOND);
+  fail_unless (res, NULL);
+
+  /* now pull in values for some timestamps */
+  /* should now give our value for timestamp 0 */
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
   fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
-  gst_controller_sync_values (ctrl, 6 * GST_SECOND);
-  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 150, NULL);
+
+  g_object_unref (G_OBJECT (csource));
 
   GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
   g_object_unref (ctrl);
@@ -885,28 +1210,165 @@ GST_START_TEST (controller_live)
 
 GST_END_TEST;
 
-/* tests if we can run helper methods against any GObject */
-GST_START_TEST (controller_helper_any_gobject)
+/* test gst_controller_set_disabled() with linear interpolation */
+GST_START_TEST (controller_interpolate_linear_disabled)
 {
+  GstController *ctrl;
+  GstInterpolationControlSource *csource, *csource2;
   GstElement *elem;
   gboolean res;
+  GValue val_ulong = { 0, }
+  , val_double = {
+  0,};
 
   gst_controller_init (NULL, NULL);
 
-  elem = gst_element_factory_make ("bin", "test_elem");
+  elem = gst_element_factory_make ("testmonosource", "test_source");
 
-  /* that element is not controllable */
-  res = gst_object_sync_values (G_OBJECT (elem), 0LL);
-  fail_unless (res == FALSE, NULL);
+  /* that property should exist and should be controllable */
+  ctrl = gst_controller_new (G_OBJECT (elem), "ulong", "double", NULL);
+  fail_unless (ctrl != NULL, NULL);
+
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+  csource2 = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+  fail_unless (csource2 != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "double",
+          GST_CONTROL_SOURCE (csource2)));
+
+  /* set interpolation mode */
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
+          GST_INTERPOLATE_LINEAR));
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode
+      (csource2, GST_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);
+  fail_unless (res, NULL);
+  g_value_set_ulong (&val_ulong, 100);
+  res =
+      gst_interpolation_control_source_set (csource, 2 * GST_SECOND,
+      &val_ulong);
+  fail_unless (res, NULL);
+
+  g_object_unref (G_OBJECT (csource));
+
+/* 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);
+  fail_unless (res, NULL);
+  g_value_set_double (&val_double, 4.0);
+  res =
+      gst_interpolation_control_source_set (csource2, 2 * GST_SECOND,
+      &val_double);
+  fail_unless (res, NULL);
+
+  g_object_unref (G_OBJECT (csource2));
+
+  /* now pull in values for some timestamps */
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 2.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 3.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 4.0, NULL);
+
+  /* now pull in values for some timestamps, prop double disabled */
+  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  GST_TEST_MONO_SOURCE (elem)->val_double = 0.0;
+  gst_controller_set_property_disabled (ctrl, "double", TRUE);
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+
+  /* now pull in values for some timestamps, after enabling double again */
+  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  GST_TEST_MONO_SOURCE (elem)->val_double = 0.0;
+  gst_controller_set_property_disabled (ctrl, "double", FALSE);
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 2.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 3.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 4.0, NULL);
+
+  /* now pull in values for some timestamps, after disabling all props */
+  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  GST_TEST_MONO_SOURCE (elem)->val_double = 0.0;
+  gst_controller_set_disabled (ctrl, TRUE);
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 0.0, NULL);
+
+  /* now pull in values for some timestamps, enabling double again */
+  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  GST_TEST_MONO_SOURCE (elem)->val_double = 0.0;
+  gst_controller_set_property_disabled (ctrl, "double", FALSE);
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 2.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 3.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 4.0, NULL);
+
+  /* now pull in values for some timestamps, enabling all */
+  GST_TEST_MONO_SOURCE (elem)->val_ulong = 0;
+  GST_TEST_MONO_SOURCE (elem)->val_double = 0.0;
+  gst_controller_set_disabled (ctrl, FALSE);
+  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 0, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 2.0, NULL);
+  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 50, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 3.0, NULL);
+  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_ulong == 100, NULL);
+  fail_unless (GST_TEST_MONO_SOURCE (elem)->val_double == 4.0, NULL);
 
+  GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
+  g_object_unref (ctrl);
   gst_object_unref (elem);
 }
 
 GST_END_TEST;
 
-GST_START_TEST (controller_misc)
+
+GST_START_TEST (controller_interpolation_set_from_list)
 {
   GstController *ctrl;
+  GstInterpolationControlSource *csource;
   GstTimedValue *tval;
   GstElement *elem;
   GSList *list = NULL;
@@ -920,8 +1382,15 @@ GST_START_TEST (controller_misc)
   ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
   fail_unless (ctrl != NULL, NULL);
 
+  /* Get interpolation control source */
+  csource = gst_interpolation_control_source_new ();
+
+  fail_unless (csource != NULL);
+  fail_unless (gst_controller_set_control_source (ctrl, "ulong",
+          GST_CONTROL_SOURCE (csource)));
+
   /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
+  fail_unless (gst_interpolation_control_source_set_interpolation_mode (csource,
           GST_INTERPOLATE_LINEAR));
 
   /* set control value */
@@ -932,11 +1401,13 @@ GST_START_TEST (controller_misc)
 
   list = g_slist_append (list, tval);
 
-  fail_if (gst_controller_set_from_list (ctrl, "ulong", list));
+  fail_if (gst_interpolation_control_source_set_from_list (csource, list));
 
   /* try again with a valid stamp, should work now */
   tval->timestamp = 0;
-  fail_unless (gst_controller_set_from_list (ctrl, "ulong", list));
+  fail_unless (gst_interpolation_control_source_set_from_list (csource, list));
+
+  g_object_unref (csource);
 
   /* allocated GstTimedValue now belongs to the controller, but list not */
   g_value_unset (&tval->value);
@@ -948,6 +1419,25 @@ GST_START_TEST (controller_misc)
 
 GST_END_TEST;
 
+/* tests if we can run helper methods against any GObject */
+GST_START_TEST (controller_helper_any_gobject)
+{
+  GstElement *elem;
+  gboolean res;
+
+  gst_controller_init (NULL, NULL);
+
+  elem = gst_element_factory_make ("bin", "test_elem");
+
+  /* that element is not controllable */
+  res = gst_object_sync_values (G_OBJECT (elem), 0LL);
+  fail_unless (res == FALSE, NULL);
+
+  gst_object_unref (elem);
+}
+
+GST_END_TEST;
+
 GST_START_TEST (controller_refcount_new_list)
 {
   GstController *ctrl, *ctrl2;
@@ -1026,113 +1516,6 @@ GST_START_TEST (controller_refcount_new_list)
 
 GST_END_TEST;
 
-
-/* test retrieval of an array of values with get_value_array() */
-GST_START_TEST (controller_interpolate_linear_value_array)
-{
-  GstController *ctrl;
-  GstElement *elem;
-  gboolean res;
-  GValue val_ulong = { 0, };
-  GstValueArray values = { 0, };
-
-  gst_controller_init (NULL, NULL);
-
-  elem = gst_element_factory_make ("testmonosource", "test_source");
-
-  /* that property should exist and should be controllable */
-  ctrl = gst_controller_new (G_OBJECT (elem), "ulong", NULL);
-  fail_unless (ctrl != NULL, NULL);
-
-  /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "ulong",
-          GST_INTERPOLATE_LINEAR));
-
-  /* set control values */
-  g_value_init (&val_ulong, G_TYPE_ULONG);
-  g_value_set_ulong (&val_ulong, 0);
-  res = gst_controller_set (ctrl, "ulong", 0 * GST_SECOND, &val_ulong);
-  fail_unless (res, NULL);
-  g_value_set_ulong (&val_ulong, 100);
-  res = gst_controller_set (ctrl, "ulong", 2 * GST_SECOND, &val_ulong);
-  fail_unless (res, NULL);
-
-  /* now pull in values for some timestamps */
-  values.property_name = "ulong";
-  values.nbsamples = 3;
-  values.sample_interval = GST_SECOND;
-  values.values = (gpointer) g_new (gulong, 3);
-
-  fail_unless (gst_controller_get_value_array (ctrl, 0, &values));
-  fail_unless_equals_int (((gulong *) values.values)[0], 0);
-  fail_unless_equals_int (((gulong *) values.values)[1], 50);
-  fail_unless_equals_int (((gulong *) values.values)[2], 100);
-
-  GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
-  g_free (values.values);
-  g_object_unref (ctrl);
-  gst_object_unref (elem);
-}
-
-GST_END_TEST;
-
-
-/* test if values below minimum and above maximum are clipped */
-GST_START_TEST (controller_linear_invalid_values)
-{
-  GstController *ctrl;
-  GstElement *elem;
-  gboolean res;
-  GValue val_float = { 0, };
-
-  gst_controller_init (NULL, NULL);
-
-  elem = gst_element_factory_make ("testmonosource", "test_source");
-
-  /* that property should exist and should be controllable */
-  ctrl = gst_controller_new (G_OBJECT (elem), "float", NULL);
-  fail_unless (ctrl != NULL, NULL);
-
-  /* set interpolation mode */
-  fail_unless (gst_controller_set_interpolation_mode (ctrl, "float",
-          GST_INTERPOLATE_LINEAR));
-
-  /* set control values */
-  g_value_init (&val_float, G_TYPE_FLOAT);
-  g_value_set_float (&val_float, 200.0);
-  res = gst_controller_set (ctrl, "float", 0 * GST_SECOND, &val_float);
-  fail_unless (res, NULL);
-  g_value_set_float (&val_float, -200.0);
-  res = gst_controller_set (ctrl, "float", 4 * GST_SECOND, &val_float);
-  fail_unless (res, NULL);
-
-  /* now pull in values for some timestamps and see if clipping works */
-  /* 200.0 */
-  gst_controller_sync_values (ctrl, 0 * GST_SECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 100.0);
-  /* 100.0 */
-  gst_controller_sync_values (ctrl, 1 * GST_SECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 100.0);
-  /* 50.0 */
-  gst_controller_sync_values (ctrl, 1 * GST_SECOND + 500 * GST_MSECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 50.0);
-  /* 0.0 */
-  gst_controller_sync_values (ctrl, 2 * GST_SECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
-  /* -100.0 */
-  gst_controller_sync_values (ctrl, 3 * GST_SECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
-  /* -200.0 */
-  gst_controller_sync_values (ctrl, 4 * GST_SECOND);
-  fail_unless_equals_float (GST_TEST_MONO_SOURCE (elem)->val_float, 0.0);
-
-  GST_INFO ("controller->ref_count=%d", G_OBJECT (ctrl)->ref_count);
-  g_object_unref (ctrl);
-  gst_object_unref (elem);
-}
-
-GST_END_TEST;
-
 static Suite *
 gst_controller_suite (void)
 {
@@ -1152,18 +1535,20 @@ gst_controller_suite (void)
   tcase_add_test (tc, controller_new_okay3);
   tcase_add_test (tc, controller_param_twice);
   tcase_add_test (tc, controller_finalize);
+  tcase_add_test (tc, controller_controlsource_refcounts);
   tcase_add_test (tc, controller_interpolate_none);
   tcase_add_test (tc, controller_interpolate_trigger);
   tcase_add_test (tc, controller_interpolate_linear);
   tcase_add_test (tc, controller_interpolate_cubic);
   tcase_add_test (tc, controller_interpolate_unimplemented);
-  tcase_add_test (tc, controller_unset);
-  tcase_add_test (tc, controller_unset_all);
-  tcase_add_test (tc, controller_live);
+  tcase_add_test (tc, controller_interpolation_unset);
+  tcase_add_test (tc, controller_interpolation_unset_all);
+  tcase_add_test (tc, controller_interpolation_linear_value_array);
+  tcase_add_test (tc, controller_interpolation_linear_invalid_values);
+  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_helper_any_gobject);
-  tcase_add_test (tc, controller_misc);
-  tcase_add_test (tc, controller_interpolate_linear_value_array);
-  tcase_add_test (tc, controller_linear_invalid_values);
 
   return s;
 }
index 81d3958..2045fd8 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <gst/gst.h>
 #include <gst/controller/gstcontroller.h>
+#include <gst/controller/gstinterpolationcontrolsource.h>
 
 gint
 main (gint argc, gchar ** argv)
@@ -17,6 +18,7 @@ main (gint argc, gchar ** argv)
   GstElement *src, *sink;
   GstElement *bin;
   GstController *ctrl;
+  GstInterpolationControlSource *csource1, *csource2;
   GstClock *clock;
   GstClockID clock_id;
   GstClockReturn wait_ret;
@@ -46,23 +48,38 @@ main (gint argc, gchar ** argv)
     goto Error;
   }
 
-  /* set interpolation */
-  gst_controller_set_interpolation_mode (ctrl, "volume",
+  csource1 = gst_interpolation_control_source_new ();
+  csource2 = gst_interpolation_control_source_new ();
+
+  gst_controller_set_control_source (ctrl, "volume",
+      GST_CONTROL_SOURCE (csource1));
+  gst_controller_set_control_source (ctrl, "freq",
+      GST_CONTROL_SOURCE (csource2));
+
+  /* Set interpolation mode */
+
+  gst_interpolation_control_source_set_interpolation_mode (csource1,
+      GST_INTERPOLATE_LINEAR);
+  gst_interpolation_control_source_set_interpolation_mode (csource2,
       GST_INTERPOLATE_LINEAR);
-  gst_controller_set_interpolation_mode (ctrl, "freq", GST_INTERPOLATE_LINEAR);
 
   /* set control values */
   g_value_init (&vol, G_TYPE_DOUBLE);
   g_value_set_double (&vol, 0.0);
-  gst_controller_set (ctrl, "volume", 0 * GST_SECOND, &vol);
+  gst_interpolation_control_source_set (csource1, 0 * GST_SECOND, &vol);
   g_value_set_double (&vol, 1.0);
-  gst_controller_set (ctrl, "volume", 5 * GST_SECOND, &vol);
+  gst_interpolation_control_source_set (csource1, 5 * GST_SECOND, &vol);
+
+  g_object_unref (csource1);
+
   g_value_set_double (&vol, 220.0);
-  gst_controller_set (ctrl, "freq", 0 * GST_SECOND, &vol);
+  gst_interpolation_control_source_set (csource2, 0 * GST_SECOND, &vol);
   g_value_set_double (&vol, 3520.0);
-  gst_controller_set (ctrl, "freq", 3 * GST_SECOND, &vol);
+  gst_interpolation_control_source_set (csource2, 3 * GST_SECOND, &vol);
   g_value_set_double (&vol, 440.0);
-  gst_controller_set (ctrl, "freq", 6 * GST_SECOND, &vol);
+  gst_interpolation_control_source_set (csource2, 6 * GST_SECOND, &vol);
+
+  g_object_unref (csource2);
 
   clock_id =
       gst_clock_new_single_shot_id (clock,