+++ /dev/null
-/* GStreamer
- *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
- *
- * gst-controller.c: dynamic parameter control subsystem
- *
- * 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:gstcontroller
- * @short_description: dynamic parameter control subsystem
- *
- * The controller subsystem offers a lightweight way to adjust gobject
- * properties over stream-time. It works by using time-stampled value pairs that
- * are queued for element-properties. At run-time the elements continously pulls
- * values changes for the current stream-time.
- *
- * What needs to be changed in a #GstElement?
- * Very little - it is just two steps to make a plugin controllable!
- * <orderedlist>
- * <listitem><para>
- * mark gobject-properties paramspecs that make sense to be controlled,
- * by GST_PARAM_CONTROLLABLE.
- * </para></listitem>
- * <listitem><para>
- * when processing data (get, chain, loop function) at the beginning call
- * gst_object_sink_values(element,timestamp).
- * This will made the controller to update all gobject properties that are under
- * control with the current values based on timestamp.
- * </para></listitem>
- * </orderedlist>
- *
- * What needs to be done in applications?
- * Again its not a lot to change.
- * <orderedlist>
- * <listitem><para>
- * first put some properties under control, by calling
- * 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);
- * </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);
- * </para></listitem>
- * <listitem><para>
- * start your pipeline
- * </para></listitem>
- * </orderedlist>
- */
-
-#include "config.h"
-#include "gst-controller.h"
-
-#define GST_CAT_DEFAULT gst_controller_debug
-GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
-
-static GObjectClass *parent_class = NULL;
-GQuark controller_key;
-
-
-/* imports from gst-interpolation.c */
-
-extern GList
- * gst_controlled_property_find_timed_value_node (GstControlledProperty *
- prop, GstClockTime timestamp);
-extern GstInterpolateMethod *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_INFO ("notify for '%s'", prop->name);
-
- ctrl = g_object_get_qdata (G_OBJECT (object), controller_key);
- g_return_if_fail (ctrl);
-
- if (g_mutex_trylock (ctrl->lock)) {
- if (!G_IS_VALUE (&prop->live_value.value)) {
- //g_value_unset (&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);
- }
- //else {
- //GST_DEBUG ("-> is control change");
- //}
-}
-
-/* helper */
-
-/*
- * gst_timed_value_compare:
- * @p1: a pointer to a #GstTimedValue
- * @p2: a pointer to a #GstTimedValue
- *
- * Compare function for g_list operations that operates on two #GstTimedValue
- * parameters.
- */
-static gint
-gst_timed_value_compare (gconstpointer p1, gconstpointer p2)
-{
- GstClockTime ct1 = ((GstTimedValue *) p1)->timestamp;
- GstClockTime ct2 = ((GstTimedValue *) p2)->timestamp;
-
- return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
-/* this does not produce an gint :(
- return ((ct1 - ct2));
-*/
-}
-
-/*
- * gst_timed_value_find:
- * @p1: a pointer to a #GstTimedValue
- * @p2: a pointer to a #GstClockTime
- *
- * Compare function for g_list operations that operates on a #GstTimedValue and
- * a #GstClockTime.
- */
-static gint
-gst_timed_value_find (gconstpointer p1, gconstpointer p2)
-{
- GstClockTime ct1 = ((GstTimedValue *) 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;
-
- self->interpolation = mode;
- if (mode != GST_INTERPOLATE_USER) {
- switch (self->type) {
- case G_TYPE_INT:
- case G_TYPE_UINT:
- self->get = interpolation_methods[mode]->get_int;
- self->get_value_array =
- interpolation_methods[mode]->get_int_value_array;
- break;
- case G_TYPE_LONG:
- case G_TYPE_ULONG:
- self->get = interpolation_methods[mode]->get_long;
- self->get_value_array =
- interpolation_methods[mode]->get_long_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;
- break;
- default:
- self->get = NULL;
- self->get_value_array = NULL;
- }
- if (!self->get) { /* || !self->get_value_array) */
- GST_WARNING ("incomplete implementation for type '%d'", self->type);
- res = FALSE;
- }
- } else {
- /* TODO shouldn't this also get a GstInterpolateMethod *user_method
- for the case mode==GST_INTERPOLATE_USER
- */
- res = FALSE;
- }
- return (res);
-}
-
-/*
- * gst_controlled_property_new:
- * @object: for which object the controlled property should be set up
- * @name: the name of the property to be controlled
- *
- * Private method which initializes the fields of a new controlled property
- * structure.
- *
- * Returns: a freshly allocated structure or %NULL
- */
-static GstControlledProperty *
-gst_controlled_property_new (GObject * object, const gchar * name)
-{
- GstControlledProperty *prop = NULL;
- GParamSpec *pspec;
-
- GST_INFO ("trying to put property '%s' under control", name);
-
- // check if the object has a property of that name
- if ((pspec =
- g_object_class_find_property (G_OBJECT_GET_CLASS (object), name))) {
- GST_DEBUG (" psec->flags : 0x%08x", pspec->flags);
-
- // check if this param is witable
- g_return_val_if_fail ((pspec->flags & G_PARAM_WRITABLE), NULL);
- // check if property is controlable
- g_return_val_if_fail ((pspec->flags & GST_PARAM_CONTROLLABLE), NULL);
- // 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;
-
- prop->name = pspec->name; // so we don't use the same mem twice
- prop->type = G_PARAM_SPEC_VALUE_TYPE (pspec);
- gst_controlled_property_set_interpolation_mode (prop,
- GST_INTERPOLATE_NONE);
- /* 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->type) {
- case G_TYPE_INT:{
- GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
-
- g_value_set_int (&prop->default_value, tpspec->default_value);
- }
- break;
- case G_TYPE_UINT:{
- GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
-
- g_value_set_uint (&prop->default_value, tpspec->default_value);
- }
- break;
- case G_TYPE_LONG:{
- GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
-
- g_value_set_long (&prop->default_value, tpspec->default_value);
- }
- break;
- case G_TYPE_ULONG:{
- GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
-
- g_value_set_ulong (&prop->default_value, tpspec->default_value);
- }
- break;
- case G_TYPE_FLOAT:{
- GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
-
- g_value_set_float (&prop->default_value, tpspec->default_value);
- }
- case G_TYPE_DOUBLE:{
- GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
-
- g_value_set_double (&prop->default_value, tpspec->default_value);
- }
- break;
- case G_TYPE_BOOLEAN:{
- GParamSpecBoolean *tpspec = G_PARAM_SPEC_BOOLEAN (pspec);
-
- g_value_set_boolean (&prop->default_value, tpspec->default_value);
- }
- break;
- default:
- GST_WARNING ("incomplete implementation for paramspec type '%s'",
- G_PARAM_SPEC_TYPE_NAME (pspec));
- }
- /* TODO what about adding a timedval with timestamp=0 and value=default
- * a bit easier for interpolators, example:
- * first timestamp is at 5
- * requested value if for timestamp=3
- * LINEAR and Co. would need to interpolate from default value to value
- * at timestamp 5
- */
- 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);
- }
- } else {
- GST_WARNING ("class '%s' has no property '%s'", G_OBJECT_TYPE_NAME (object),
- name);
- }
-
- return (prop);
-}
-
-/*
- * gst_controlled_property_free:
- * @prop: the object to free
- *
- * Private method which frees all data allocated by a #GstControlledProperty
- * instance.
- */
-static void
-gst_controlled_property_free (GstControlledProperty * prop)
-{
- GList *node;
-
- for (node = prop->values; node; node = g_list_next (node)) {
- g_free (node->data);
- }
- g_list_free (prop->values);
- g_free (prop);
-}
-
-/*
- * gst_controller_find_controlled_property:
- * @self: the controller object to search for a property in
- * @name: the gobject property name to look for
- *
- * Searches the list of properties under control.
- *
- * Returns: a #GstControlledProperty object of %NULL if the property is not
- * being controlled.
- */
-static GstControlledProperty *
-gst_controller_find_controlled_property (GstController * self,
- const gchar * name)
-{
- GstControlledProperty *prop;
- GList *node;
-
- for (node = self->properties; node; node = g_list_next (node)) {
- prop = node->data;
- if (!strcmp (prop->name, name)) {
- return (prop);
- }
- }
- GST_DEBUG ("controller does not (yet) manage property '%s'", name);
-
- return (NULL);
-}
-
-/* methods */
-
-/**
- * gst_controller_new_valist:
- * @object: the object of which some properties should be controlled
- * @var_args: %NULL terminated list of property names that should be controlled
- *
- * Creates a new GstController for the given object's properties
- *
- * Returns: the new controller.
- * Since: 0.9
- */
-GstController *
-gst_controller_new_valist (GObject * object, va_list var_args)
-{
- GstController *self;
- GstControlledProperty *prop;
- gchar *name;
-
- g_return_val_if_fail (G_IS_OBJECT (object), NULL);
-
- 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, controller_key);
- // create GstControlledProperty for each property
- while ((name = va_arg (var_args, gchar *))) {
- // test if this property isn't yet controlled
- if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
- // create GstControlledProperty and add to self->propeties List
- if ((prop = gst_controlled_property_new (object, name))) {
- // if we don't have a controller object yet, now is the time to create one
- if (!self) {
- self = g_object_new (GST_TYPE_CONTROLLER, NULL);
- self->lock = g_mutex_new ();
- self->object = object;
- // store the controller
- g_object_set_qdata (object, controller_key, self);
- } else {
- // increment ref-count
- self = g_object_ref (self);
- }
- self->properties = g_list_prepend (self->properties, prop);
- }
- } else {
- GST_WARNING ("trying to control property again");
- }
- }
- va_end (var_args);
-
- return (self);
-}
-
-/**
- * gst_controller_new:
- * @object: the object of which some properties should be controlled
- * @...: %NULL terminated list of property names that should be controlled
- *
- * Creates a new GstController for the given object's properties
- *
- * Returns: the new controller.
- * Since: 0.9
- */
-GstController *
-gst_controller_new (GObject * object, ...)
-{
- GstController *self;
- va_list var_args;
-
- g_return_val_if_fail (G_IS_OBJECT (object), NULL);
-
- va_start (var_args, object);
- self = gst_controller_new_valist (object, var_args);
- va_end (var_args);
-
- return (self);
-}
-
-/**
- * gst_controller_remove_properties_valist:
- * @self: the controller object from which some properties should be removed
- * @var_args: %NULL terminated list of property names that should be removed
- *
- * Removes the given object properties from the controller
- *
- * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
- * Since: 0.9
- */
-gboolean
-gst_controller_remove_properties_valist (GstController * self, va_list var_args)
-{
- gboolean res = TRUE;
- GstControlledProperty *prop;
- gchar *name;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-
- while ((name = va_arg (var_args, gchar *))) {
- // find the property in the properties list of the controller, remove and free it
- 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);
- gst_controlled_property_free (prop);
- } else {
- res = FALSE;
- }
- g_mutex_unlock (self->lock);
- }
-
- return (res);
-}
-
-/**
- * gst_controller_remove_properties:
- * @self: the controller object from which some properties should be removed
- * @...: %NULL terminated list of property names that should be removed
- *
- * Removes the given object properties from the controller
- *
- * Returns: %FALSE if one of the given property isn't handled by the controller, %TRUE otherwise
- * Since: 0.9
- */
-gboolean
-gst_controller_remove_properties (GstController * self, ...)
-{
- gboolean res;
- va_list var_args;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
-
- va_start (var_args, self);
- res = gst_controller_remove_properties_valist (self, var_args);
- va_end (var_args);
-
- 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
- *
- * Set the value of given controller-handled property at a certain time.
- *
- * Returns: FALSE if the values couldn't be set (ex : properties not handled by controller), TRUE otherwise
- * Since: 0.9
- */
-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_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
- g_return_val_if_fail (G_IS_VALUE (value), FALSE);
-
- g_mutex_lock (self->lock);
- if ((prop = gst_controller_find_controlled_property (self, property_name))) {
- if (G_VALUE_TYPE (value) == prop->type) {
- GstTimedValue *tv;
- GList *node;
-
- // check if a timed_value for the timestamp already exists
- if ((node = g_list_find_custom (prop->values, ×tamp,
- gst_timed_value_find))) {
- tv = node->data;
- memcpy (&tv->value, value, sizeof (GValue));
- } else {
- // create a new GstTimedValue
- tv = g_new (GstTimedValue, 1);
- tv->timestamp = timestamp;
- memcpy (&tv->value, value, sizeof (GValue));
- // and sort it into the prop->values list
- prop->values =
- g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
- }
- res = TRUE;
- } else {
- GST_WARNING ("incompatible value type for property '%s'", prop->name);
- }
- }
- 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.
- *
- * Returns: %FALSE if the values couldn't be set (ex : properties not handled by controller), %TRUE otherwise
- * Since: 0.9
- */
-
-gboolean
-gst_controller_set_from_list (GstController * self, gchar * property_name,
- GSList * timedvalues)
-{
- gboolean res = FALSE;
- 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_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 (G_VALUE_TYPE (&tv->value) == prop->type) {
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (tv->timestamp), FALSE);
- /* TODO copy the timed value or just link in? */
- prop->values =
- g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
- res = TRUE;
- } else {
- GST_WARNING ("incompatible value type for property '%s'", prop->name);
- }
- }
- }
- 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.
- *
- * Returns: %FALSE if the values couldn't be unset (ex : properties not handled by controller), %TRUE otherwise
- * Since: 0.9
- */
-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))) {
- prop->values = g_list_remove (prop->values, prop);
- res = TRUE;
- }
- g_mutex_unlock (self->lock);
-
- return (res);
-}
-
-/**
- * gst_controller_get:
- * @self: the controller object which handles the properties
- * @property_name: the name of the property to get
- * @timestamp: the time the control-change should be read from
- *
- * Gets the value for the given controller-handled property at the requested
- * time.
- *
- * Returns: the GValue of the property at the given time, or %NULL if the property isn't handled by the controller
- * Since: 0.9
- */
-GValue *
-gst_controller_get (GstController * self, gchar * property_name,
- GstClockTime timestamp)
-{
- GstControlledProperty *prop;
- GValue *val = NULL;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
- g_return_val_if_fail (property_name, NULL);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
-
- 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.
- *
- * Returns: a copy of the list, or %NULL if the property isn't handled by the controller
- * Since: 0.9
- */
-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);
- }
- g_mutex_unlock (self->lock);
-
- return (res);
-}
-
-/**
- * gst_controller_sink_values:
- * @self: the controller that handles the values
- * @timestamp: the time that should be processed
- *
- * Sets the properties of the element, according to the controller that (maybe)
- * handles them and for the given timestamp.
- *
- * Returns: %TRUE if the controller values could be applied to the object
- * properties, %FALSE otherwise
- * Since: 0.9
- */
-gboolean
-gst_controller_sink_values (GstController * self, GstClockTime timestamp)
-{
- GstControlledProperty *prop;
- GList *node;
- GValue *value;
- gboolean live;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
-
- GST_INFO ("sink_values");
-
- g_mutex_lock (self->lock);
- // go over the controlled properties of the controller
- for (node = self->properties; node; node = g_list_next (node)) {
- prop = node->data;
- GST_DEBUG (" property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
- timestamp);
-
- live = FALSE;
- if (G_IS_VALUE (&prop->live_value.value)) {
- GList *lnode =
- gst_controlled_property_find_timed_value_node (prop, timestamp);
- if (!lnode) {
- GST_DEBUG (" no control changes in the queue");
- live = TRUE;
- } else {
- GstTimedValue *tv = lnode->data;
-
- //GST_DEBUG ("live.ts %"G_UINT64_FORMAT" <-> now %"G_UINT64_FORMAT, prop->live_value.timestamp, tv->timestamp);
- if (prop->live_value.timestamp < tv->timestamp) {
- g_value_unset (&prop->live_value.value);
- GST_DEBUG (" live value resetted");
- } else if (prop->live_value.timestamp < timestamp) {
- live = TRUE;
- }
- }
- }
- if (!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);
- }
- }
- 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);
-}
-
-/**
- * gst_controller_get_value_arrays:
- * @self: the controller that handles the values
- * @timestamp: the time that should be processed
- * @value_arrays: list to return the control-values in
- *
- * Function to be able to get an array of values for one or more given element
- * properties.
- *
- * If the GstValueArray->values array in list nodes is NULL, it will be created
- * by the function.
- * The type of the values in the array are the same as the property's type.
- *
- * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
- * Since: 0.9
- */
-gboolean
-gst_controller_get_value_arrays (GstController * self,
- GstClockTime timestamp, GSList * value_arrays)
-{
- gboolean res = TRUE;
- GSList *node;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
- g_return_val_if_fail (value_arrays, FALSE);
-
- for (node = value_arrays; (res && node); node = g_slist_next (node)) {
- res = gst_controller_get_value_array (self, timestamp, node->data);
- }
-
- return (res);
-}
-
-/**
- * gst_controller_get_value_array:
- * @self: the controller that handles the values
- * @timestamp: the time that should be processed
- * @value_array: array to put control-values in
- *
- * Function to be able to get an array of values for one element properties
- *
- * If the GstValueArray->values array is NULL, it will be created by the function.
- * The type of the values in the array are the same as the property's type.
- *
- * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
- * Since: 0.9
- */
-gboolean
-gst_controller_get_value_array (GstController * self, GstClockTime timestamp,
- GstValueArray * value_array)
-{
- gboolean res = FALSE;
- GstControlledProperty *prop;
-
- g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
- g_return_val_if_fail (value_array, FALSE);
- g_return_val_if_fail (value_array->property_name, FALSE);
-
- /* TODO and if GstValueArray->values is not NULL, the caller is resposible that
- is is big enough for nbsamples values, right?
- */
-
- g_mutex_lock (self->lock);
- if ((prop =
- gst_controller_find_controlled_property (self,
- value_array->property_name))) {
- if (!value_array->values) {
- /* TODO from where to get the base size
- value_array->values=g_new(sizeof(???),nbsamples);
- */
- }
- //get current value_array via interpolator
- res = prop->get_value_array (prop, timestamp, value_array);
- }
- 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.
- *
- * Returns: %TRUE if the property is handled by the controller, %FALSE otherwise
- * Since: 0.9
- */
-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
- */
- gst_controlled_property_set_interpolation_mode (prop, mode);
- res = TRUE;
- }
- g_mutex_unlock (self->lock);
-
- return (res);
-}
-
-/*
-void
-gst_controller_set_live_value(GstController * self, gchar *property_name,
- GstClockTime timestamp, GValue *value)
-{
- GstControlledProperty *prop;
-
- 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))) {
- g_value_unset (&prop->live_value.value);
- g_value_init (&prop->live_value.value, prop->type);
- g_value_copy (value, &prop->live_value.value);
- prop->live_value.timestamp = timestamp;
- }
- g_mutex_unlock (self->lock);
-}
-
-*/
-
-/* gobject handling */
-
-static void
-_gst_controller_finalize (GObject * object)
-{
- GstController *self = GST_CONTROLLER (object);
- GList *node;
- GstControlledProperty *prop;
-
- /* free list of properties */
- if (self->properties) {
- for (node = self->properties; node; node = g_list_next (node)) {
- prop = node->data;
- g_signal_handler_disconnect (self->object, prop->notify_handler_id);
- gst_controlled_property_free (prop);
- }
- g_list_free (self->properties);
- self->properties = NULL;
- }
- g_mutex_free (self->lock);
- /* remove controller from objects qdata list */
- g_object_set_qdata (self->object, controller_key, NULL);
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-static void
-_gst_controller_init (GTypeInstance * instance, gpointer g_class)
-{
- GstController *self = GST_CONTROLLER (instance);
-
- self->lock = g_mutex_new ();
-
-}
-
-static void
-_gst_controller_class_init (GstControllerClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
- gobject_class->finalize = _gst_controller_finalize;
-
- controller_key = g_quark_from_string ("gst::controller");
-
- // register properties
- // register signals
- // set defaults for overridable methods
- /* TODO which of theses do we need ?
- BilboEd : none :)
- */
-}
-
-GType
-gst_controller_get_type (void)
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info = {
- sizeof (GstControllerClass),
- NULL, // base_init
- NULL, // base_finalize
- (GClassInitFunc) _gst_controller_class_init, // class_init
- NULL, // class_finalize
- NULL, // class_data
- sizeof (GstController),
- 0, // n_preallocs
- (GInstanceInitFunc) _gst_controller_init, // instance_init
- NULL // value_table
- };
- type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
- }
- return type;
-}
+++ /dev/null
-/* GStreamer
- *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
- *
- * gst-controller.h: dynamic parameter control subsystem
- *
- * 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_CONTROLLER_H__
-#define __GST_CONTROLLER_H__
-
-#include <string.h>
-
-#include <glib.h>
-#include <glib-object.h>
-#include <glib/gprintf.h>
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-/**
- * GST_PARAM_CONTROLLABLE:
- *
- * Use this flag on GstElement properties you wish to be (eventually) handled
- * by a GstController.
- * TODO: needs to go to gstelemnt.h (to avoid clashes on G_PARAM_USER_SHIFT)
- */
-#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
- /* TODO what about storing the difference to next timestamp and value here
- + make calculations slightly easier and faster
- - determining the GType for the value_dif is not simple
- e.g. if value is G_TYPE_UCHAR value_diff needs to be G_TYPE_INT
- */
-} 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.
- * If the pointer to the values array is NULL, it will be allocated (CHECKME).
- */
-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
- * @GST_INTERPOLATE_CUBIC: cubic interpolation
- * @GST_INTERPOLATE_USER: user-provided interpolation
- *
- * 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;
-
-
-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_long;
- InterpolateGetValueArray get_long_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;
-} GstInterpolateMethod;
-
-/**
- * GstControlledProperty:
- */
-typedef struct _GstControlledProperty
-{
- gchar *name; // name of the property
- GType type; // type of the handled property
- GValue default_value; // default value for the handled property
- GValue result_value; // result value location for the interpolation method
- GstTimedValue last_value; // the last value a _sink call wrote
- GstTimedValue 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 GstTimedValue
- /* TODO keep the last search result to be able to continue
- GList *last_value; // last search result, can be used for incremental searches
- */
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-} GstControlledProperty;
-
-#define GST_CONTROLLED_PROPERTY(obj) ((GstControlledProperty *)(obj))
-
-/* type macros */
-
-#define GST_TYPE_CONTROLLER (gst_controller_get_type ())
-#define GST_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CONTROLLER, GstController))
-#define GST_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CONTROLLER, GstControllerClass))
-#define GST_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CONTROLLER))
-#define GST_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CONTROLLERE))
-#define GST_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CONTROLLER, GstControllerClass))
-
-typedef struct _GstController GstController;
-typedef struct _GstControllerClass GstControllerClass;
-
-//typedef struct _GstControllerPrivate GstControllerPrivate;
-
-/**
- * GstController:
- *
- * The instance structure of GstController
- */
-
-struct _GstController
-{
- GObject parent;
-
- GList *properties; // List of GstControlledProperty
- GMutex *lock; // Secure property access, elements will access from threads
- GObject *object; // the object we control
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstControllerClass
-{
- GObjectClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_controller_get_type (void);
-
-/* GstController functions */
-
-GstController *gst_controller_new_valist (GObject * object, va_list var_args);
-GstController *gst_controller_new (GObject * object, ...);
-
-gboolean gst_controller_remove_properties_valist (GstController * self,
- va_list var_args);
-gboolean gst_controller_remove_properties (GstController * self, ...);
-
-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);
-
-
-GValue *gst_controller_get (GstController * self, gchar * property_name,
- GstClockTime timestamp);
-const GList *gst_controller_get_all (GstController * self,
- gchar * property_name);
-
-
-gboolean gst_controller_sink_values (GstController * self,
- 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, ...);
-gboolean gst_object_uncontrol_properties (GObject * object, ...);
-
-GstController *gst_object_get_controller (GObject * object);
-gboolean gst_object_set_controller (GObject * object, GstController * controller);
-
-gboolean gst_object_sink_values (GObject * object, GstClockTime timestamp);
-
-gboolean gst_object_get_value_arrays (GObject * object,
- GstClockTime timestamp, GSList * value_arrays);
-gboolean gst_object_get_value_array (GObject * object,
- GstClockTime timestamp, GstValueArray * value_array);
-
-/* lib init/done */
-
-gboolean gst_controller_init (int * argc, char ***argv);
-
-G_END_DECLS
-#endif /* __GST_CONTROLLER_H__ */
+++ /dev/null
-/* GStreamer
- *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
- *
- * gst-helper.c: GObject convinience methods for using dynamic properties
- *
- * 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:gstcontrollergobject
- * @short_description: #GObject convinience methods for using dynamic properties
- * @see_also: #GstController
- *
- * These methods allow to use some #GstController functionallity directly from
- * the #GObject class.
- */
-
-#include "config.h"
-#include "gst-controller.h"
-
-#define GST_CAT_DEFAULT gst_controller_debug
-GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
-
-extern GQuark controller_key;
-
-/**
- * gst_object_control_properties:
- * @object: the object of which some properties should be controlled
- * @...: %NULL terminated list of property names that should be controlled
- *
- * Convenience function for GObject
- *
- * Creates a GstController that allows you to dynamically control one, or more, GObject properties.
- * If the given GObject already has a GstController, it adds the given properties to the existing
- * controller and returns that controller.
- *
- * Returns: The GstController with which the user can control the given properties dynamically or NULL if
- * one or more of the given properties aren't available, or cannot be controlled, for the given element.
- * Since: 0.9
- */
-GstController *
-gst_object_control_properties (GObject * object, ...)
-{
- GstController *ctrl;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-
- va_list var_args;
-
- va_start (var_args, object);
- ctrl = gst_controller_new_valist (object, var_args);
- va_end (var_args);
- return (ctrl);
-}
-
-/**
- * gst_object_uncontrol_properties:
- * @object: the object of which some properties should not be controlled anymore
- * @...: %NULL terminated list of property names that should be controlled
- *
- * Convenience function for GObject
- *
- * Removes the given element's properties from it's controller
- *
- * Returns: %FALSE if one of the given property names isn't handled by the
- * controller, %TRUE otherwise
- * Since: 0.9
- */
-gboolean
-gst_object_uncontrol_properties (GObject * object, ...)
-{
- gboolean res = FALSE;
- GstController *ctrl;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-
- if ((ctrl = g_object_get_qdata (object, controller_key))) {
- va_list var_args;
-
- va_start (var_args, object);
- res = gst_controller_remove_properties_valist (ctrl, var_args);
- va_end (var_args);
- }
- return (res);
-}
-
-/**
- * gst_object_get_controller:
- * @object: the object that has controlled properties
- *
- * Returns: the controller handling some of the given element's properties, %NULL if no controller
- * Since: 0.9
- */
-GstController *
-gst_object_get_controller (GObject * object)
-{
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-
- return (g_object_get_qdata (object, controller_key));
-}
-
-/**
- * gst_object_set_controller:
- * @object: the object that should get the controller
- * @controller: the controller object to plug in
- *
- * Sets the controller on the given GObject
- *
- * Returns: %FALSE if the GObject already has an controller, %TRUE otherwise
- * Since: 0.9
- */
-gboolean
-gst_object_set_controller (GObject * object, GstController * controller)
-{
- GstController *ctrl;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
- g_return_val_if_fail (controller, FALSE);
-
- if (!(ctrl = g_object_get_qdata (object, controller_key))) {
- g_object_set_qdata (object, controller_key, controller);
- return (TRUE);
- }
- return (FALSE);
-}
-
-/**
- * gst_object_sink_values:
- * @object: the object that has controlled properties
- * @timestamp: the time that should be processed
- *
- * Convenience function for GObject
- *
- * Returns: same thing as gst_controller_sink_values()
- * Since: 0.9
- */
-gboolean
-gst_object_sink_values (GObject * object, GstClockTime timestamp)
-{
- GstController *ctrl = NULL;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
-
- if ((ctrl = g_object_get_qdata (object, controller_key))) {
- return gst_controller_sink_values (ctrl, timestamp);
- }
- return (FALSE);
-}
-
-/**
- * gst_object_get_value_arrays:
- * @object: the object that has controlled properties
- * @timestamp: the time that should be processed
- * @value_arrays: list to return the control-values in
- *
- * Function to be able to get an array of values for one or more given element
- * properties.
- *
- * If the GstValueArray->values array in list nodes is NULL, it will be created
- * by the function.
- * The type of the values in the array are the same as the property's type.
- *
- * The g_object_* functions are just convenience functions for GObject
- *
- * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
- * Since: 0.9
- */
-gboolean
-gst_object_get_value_arrays (GObject * object, GstClockTime timestamp,
- GSList * value_arrays)
-{
- GstController *ctrl;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
-
- if ((ctrl = g_object_get_qdata (object, controller_key))) {
- return gst_controller_get_value_arrays (ctrl, timestamp, value_arrays);
- }
- return (FALSE);
-}
-
-/**
- * gst_object_get_value_array:
- * @object: the object that has controlled properties
- * @timestamp: the time that should be processed
- * @value_array: array to put control-values in
- *
- * Function to be able to get an array of values for one element properties
- *
- * If the GstValueArray->values array is NULL, it will be created by the function.
- * The type of the values in the array are the same as the property's type.
- *
- * The g_object_* functions are just convenience functions for GObject
- *
- * Returns: %TRUE if the given array(s) could be filled, %FALSE otherwise
- * Since: 0.9
- */
-gboolean
-gst_object_get_value_array (GObject * object, GstClockTime timestamp,
- GstValueArray * value_array)
-{
- GstController *ctrl;
-
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
- g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
-
- if ((ctrl = g_object_get_qdata (object, controller_key))) {
- return gst_controller_get_value_array (ctrl, timestamp, value_array);
- }
- return (FALSE);
-}
+++ /dev/null
-/* GStreamer
- *
- * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
- *
- * gst-interpolation.c: Interpolation methodws for dynamic properties
- *
- * 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.
- */
-
-#include "config.h"
-#include "gst-controller.h"
-
-#define GST_CAT_DEFAULT gst_controller_debug
-GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
-
-// common helper
-
-/*
- * gst_controlled_property_find_timed_value_node:
- * @prop: the controlled property to search in
- * @timestamp: the search key
- *
- * Find last value before given timestamp in timed value list.
- *
- * Returns: the found #GList node or %NULL
- */
-GList *
-gst_controlled_property_find_timed_value_node (GstControlledProperty * prop,
- GstClockTime timestamp)
-{
- //GList *prev_node = NULL;
- GList *prev_node = g_list_last (prop->values);
- GList *node;
- GstTimedValue *tv;
-
- /*
- if((prop->last_value) &&
- (timestamp>((GstTimedValue *)(prop->last_value->data))->timestamp)) {
- node=prop->last_value;
- }
- else {
- node=prop->values;
- }
- */
-
- /* iterate over timed value list */
- for (node = prop->values; node; node = g_list_next (node)) {
- tv = node->data;
- /* this timestamp is newer that the one we look for */
- if (timestamp < tv->timestamp) {
- /* get previous one again */
- prev_node = g_list_previous (node);
- break;
- }
- }
- /*
- if(node) {
- prop->last_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)
-{
- GList *node;
-
- if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) {
- GstTimedValue *tv = node->data;
-
- return (&tv->value);
- }
- return (&prop->default_value);
-}
-
-#define DEFINE_NONE_GET(type) \
-static gboolean \
-interpolate_none_get_##type##_value_array (GstControlledProperty * prop, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts=timestamp; \
- g##type *values=(g##type *)value_array->values; \
- \
- for(i=0;i<value_array->nbsamples;i++) { \
- *values=g_value_get_##type (interpolate_none_get (prop,ts)); \
- ts+=value_array->sample_interval; \
- values++; \
- } \
- return (TRUE); \
-}
-
-DEFINE_NONE_GET (int)
- DEFINE_NONE_GET (long)
-DEFINE_NONE_GET (float)
-DEFINE_NONE_GET (double)
-DEFINE_NONE_GET (boolean)
-
- static GstInterpolateMethod interpolate_none = {
- interpolate_none_get,
- interpolate_none_get_int_value_array,
- interpolate_none_get,
- interpolate_none_get_long_value_array,
- interpolate_none_get,
- interpolate_none_get_float_value_array,
- interpolate_none_get,
- interpolate_none_get_double_value_array,
- interpolate_none_get,
- interpolate_none_get_boolean_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;
- GstTimedValue *tv;
-
- /* check if there is a value at the registered timestamp */
- for (node = prop->values; node; node = g_list_next (node)) {
- tv = node->data;
- if (timestamp == tv->timestamp) {
- return (&tv->value);
- }
- }
-
- return (&prop->default_value);
-}
-
-static gboolean
-interpolate_trigger_get_value_array (GstControlledProperty * prop,
- GstClockTime timestamp, GstValueArray * value_array)
-{
- return (FALSE);
-}
-
-static GstInterpolateMethod interpolate_trigger = {
- interpolate_trigger_get,
- interpolate_trigger_get_value_array,
- interpolate_trigger_get,
- NULL,
- interpolate_trigger_get,
- NULL,
- interpolate_trigger_get,
- NULL,
- interpolate_trigger_get,
- NULL
-};
-
-// linear interpolation
-// smoothes inbetween values
-
-#define DEFINE_LINEAR_GET(type) \
-static g##type \
-_interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
-{ \
- GList *node; \
- \
- if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) { \
- GstTimedValue *tv1, *tv2; \
- \
- tv1 = node->data; \
- if ((node = g_list_next (node))) { \
- gdouble timediff,valuediff; \
- g##type value1,value2; \
- \
- tv2 = node->data; \
- \
- timediff = (gdouble)(tv2->timestamp - tv1->timestamp); \
- value1 = g_value_get_##type (&tv1->value); \
- value2 = g_value_get_##type (&tv2->value); \
- valuediff = (gdouble)(value2-value1); \
- \
- return((g##type)(value1+valuediff*((timestamp-tv1->timestamp)/timediff))); \
- } \
- else { \
- return (g_value_get_##type (&tv1->value)); \
- } \
- } \
- return (g_value_get_##type (&prop->default_value)); \
-} \
-\
-static GValue * \
-interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
-{ \
- g_value_set_##type (&prop->result_value,_interpolate_linear_get_##type (prop,timestamp)); \
- return (&prop->result_value); \
-} \
-\
-static gboolean \
-interpolate_linear_get_##type##_value_array (GstControlledProperty * prop, \
- GstClockTime timestamp, GstValueArray * value_array) \
-{ \
- gint i; \
- GstClockTime ts=timestamp; \
- gint *values=(gint *)value_array->values; \
- \
- for(i=0;i<value_array->nbsamples;i++) { \
- *values=_interpolate_linear_get_##type (prop,ts); \
- ts+=value_array->sample_interval; \
- values++; \
- } \
- return (TRUE); \
-}
-
-DEFINE_LINEAR_GET (int)
-DEFINE_LINEAR_GET (long)
-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_long,
- interpolate_linear_get_long_value_array,
- interpolate_linear_get_float,
- interpolate_linear_get_float_value_array,
- interpolate_linear_get_double,
- interpolate_linear_get_double_value_array,
- NULL,
- NULL
- };
-
-// square interpolation
-
-// cubic interpolation
-
-// register all interpolation methods
-GstInterpolateMethod *interpolation_methods[] = {
- &interpolate_none,
- &interpolate_trigger,
- &interpolate_linear,
- NULL,
- NULL
-};