controller: merge controller into gstobject

This make the controller even more lightweight (no extra object, no extra lock,
less indirections). For object that don't use the controller the only 'overhead'
is a 3 unused fields in the gst_object structure.
This commit is contained in:
Stefan Sauer 2011-11-10 19:37:28 +02:00
parent 08d9f54044
commit a1599f5f7e
14 changed files with 762 additions and 1712 deletions

View file

@ -67,7 +67,6 @@ Windows. It is released under the GNU Library General Public License
<xi:include href="xml/gstchildproxy.xml" /> <xi:include href="xml/gstchildproxy.xml" />
<xi:include href="xml/gstclock.xml" /> <xi:include href="xml/gstclock.xml" />
<xi:include href="xml/gstconfig.xml" /> <xi:include href="xml/gstconfig.xml" />
<xi:include href="xml/gstcontroller.xml" />
<xi:include href="xml/gstcontrolsource.xml" /> <xi:include href="xml/gstcontrolsource.xml" />
<xi:include href="xml/gstdatetime.xml" /> <xi:include href="xml/gstdatetime.xml" />
<xi:include href="xml/gstelement.xml" /> <xi:include href="xml/gstelement.xml" />

View file

@ -556,41 +556,6 @@ GST_PADDING_INIT
GST_USING_PRINTF_EXTENSION GST_USING_PRINTF_EXTENSION
</SECTION> </SECTION>
<SECTION>
<FILE>gstcontroller</FILE>
<TITLE>GstController</TITLE>
GstController
gst_controller_new
gst_controller_new_list
gst_controller_new_valist
gst_controller_add_properties
gst_controller_add_properties_list
gst_controller_add_properties_valist
gst_controller_remove_properties
gst_controller_remove_properties_list
gst_controller_remove_properties_valist
gst_controller_is_active
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
<SUBSECTION Standard>
GstControllerClass
GstControllerPrivate
GST_CONTROLLER
GST_IS_CONTROLLER
GST_CONTROLLER_CLASS
GST_IS_CONTROLLER_CLASS
GST_CONTROLLER_GET_CLASS
GST_TYPE_CONTROLLER
<SUBSECTION Private>
gst_controller_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>gstcontrolsource</FILE> <FILE>gstcontrolsource</FILE>
@ -1568,9 +1533,9 @@ gst_object_control_properties
gst_object_uncontrol_properties gst_object_uncontrol_properties
gst_object_suggest_next_sync gst_object_suggest_next_sync
gst_object_sync_values gst_object_sync_values
gst_object_has_active_automation gst_object_has_active_controlled_properties
gst_object_set_automation_disabled gst_object_set_controlled_properties_disabled
gst_object_set_property_automation_disabled gst_object_set_controlled_property_disabled
gst_object_get_control_source gst_object_get_control_source
gst_object_set_control_source gst_object_set_control_source
gst_object_get_value gst_object_get_value

View file

@ -12,7 +12,6 @@ gst_bin_get_type
gst_bus_get_type gst_bus_get_type
gst_child_proxy_get_type gst_child_proxy_get_type
gst_clock_get_type gst_clock_get_type
gst_controller_get_type
gst_control_source_get_type gst_control_source_get_type
gst_element_factory_get_type gst_element_factory_get_type
gst_element_get_type gst_element_get_type

View file

@ -399,3 +399,18 @@ The 0.11 porting guide
gst_tag_list_new() has been renamed to gst_tag_list_new_empty(). gst_tag_list_new() has been renamed to gst_tag_list_new_empty().
gst_tag_list_new_full*() have been renamed to gst_tag_list_new*(). gst_tag_list_new_full*() have been renamed to gst_tag_list_new*().
* GstController:
has now been merged into GstObject. The control sources are in the
controller library still.
For plugins the effect is that gst_controller_init() is gone and
gst_object_sync_values() is taking a GstObject * instead of GObject *.
For applications the effect is larger. The whole gst_controller_* API is
gone and now available in simplified form under gst_object_*.
gst_controller_new* -> gst_object_control_properties
gst_controller_add_properties -> gst_object_control_properties
gst_controller_set_control_source -> gst_object_set_control_source
gst_controller_get_control_source -> gst_object_get_control_source
gst_controller_set_property_disabled -> gst_object_set_controlled_property_disabled

View file

@ -56,7 +56,6 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstcaps.c \ gstcaps.c \
gstchildproxy.c \ gstchildproxy.c \
gstclock.c \ gstclock.c \
gstcontroller.c \
gstcontrolsource.c \ gstcontrolsource.c \
gstdatetime.c \ gstdatetime.c \
gstdebugutils.c \ gstdebugutils.c \
@ -150,7 +149,6 @@ gst_headers = \
gstchildproxy.h \ gstchildproxy.h \
gstclock.h \ gstclock.h \
gstcompat.h \ gstcompat.h \
gstcontroller.h \
gstcontrolsource.h \ gstcontrolsource.h \
gstdatetime.h \ gstdatetime.h \
gstdebugutils.h \ gstdebugutils.h \

View file

@ -44,7 +44,6 @@
#include <gst/gstcaps.h> #include <gst/gstcaps.h>
#include <gst/gstchildproxy.h> #include <gst/gstchildproxy.h>
#include <gst/gstclock.h> #include <gst/gstclock.h>
#include <gst/gstcontroller.h>
#include <gst/gstcontrolsource.h> #include <gst/gstcontrolsource.h>
#include <gst/gstdatetime.h> #include <gst/gstdatetime.h>
#include <gst/gstdebugutils.h> #include <gst/gstdebugutils.h>

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
/* GStreamer
*
* Copyright (C) 2005 Stefan Kost <ensonic at users dot sf dot net>
* 2011 Stefan Sauer <ensonic at users dot sf dot net>
*
* gstcontroller.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 <gst/gstconfig.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gprintf.h>
#include <gst/gstobject.h>
#include <gst/gstcontrolsource.h>
G_BEGIN_DECLS
/* 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 */
GstObject *object; /* the object we control */
/*< private >*/
GstControllerPrivate *priv;
gpointer _gst_reserved[GST_PADDING - 1];
};
struct _GstControllerClass
{
GObjectClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_controller_get_type (void);
/* GstController functions */
GstController *gst_controller_new_valist (GstObject * object, va_list var_args);
GstController *gst_controller_new_list (GstObject * object, GList *list);
GstController *gst_controller_new (GstObject * object, ...) G_GNUC_NULL_TERMINATED;
gboolean gst_controller_add_properties_valist (GstController * self, va_list var_args);
gboolean gst_controller_add_properties_list (GstController * self, GList *list);
gboolean gst_controller_add_properties (GstController * self, ...) G_GNUC_NULL_TERMINATED;
gboolean gst_controller_remove_properties_valist (GstController * self, va_list var_args);
gboolean gst_controller_remove_properties_list (GstController * self, GList *list);
gboolean gst_controller_remove_properties (GstController * self, ...) G_GNUC_NULL_TERMINATED;
gboolean gst_controller_is_active (GstController * self);
void gst_controller_set_disabled (GstController *self, gboolean disabled);
void gst_controller_set_property_disabled (GstController *self, const gchar * property_name, gboolean disabled);
gboolean gst_controller_set_control_source (GstController *self, const gchar * property_name, GstControlSource *csource);
GstControlSource * gst_controller_get_control_source (GstController *self, const 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, const 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);
G_END_DECLS
#endif /* __GST_CONTROLLER_H__ */

View file

@ -48,8 +48,8 @@
#include "gstcontrolsource.h" #include "gstcontrolsource.h"
#define GST_CAT_DEFAULT controller_debug #define GST_CAT_DEFAULT control_source_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
G_DEFINE_ABSTRACT_TYPE (GstControlSource, gst_control_source, G_TYPE_OBJECT); G_DEFINE_ABSTRACT_TYPE (GstControlSource, gst_control_source, G_TYPE_OBJECT);
@ -64,6 +64,9 @@ gst_control_source_class_init (GstControlSourceClass * klass)
/* Has to be implemented by children */ /* Has to be implemented by children */
klass->bind = NULL; klass->bind = NULL;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolsource", 0,
"dynamic parameter control sources");
} }
static void static void

View file

@ -80,6 +80,56 @@
* gst_object_set_name() and gst_object_get_name() are used to set/get the name * gst_object_set_name() and gst_object_get_name() are used to set/get the name
* of the object. * of the object.
* *
*
* <refsect2>
* <title>controlled properties</title>
* Controlled properties offers a lightweight way to adjust gobject
* properties over stream-time. It works by using time-stamped value pairs that
* are queued for element-properties. At run-time the elements continously pull
* 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_sync_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
* gst_object_control_properties (object, "prop1", "prop2",...);
* </para></listitem>
* <listitem><para>
* create a #GstControlSource.
* csource = gst_interpolation_control_source_new ();
* gst_interpolation_control_source_set_interpolation_mode(csource, mode);
* </para></listitem>
* <listitem><para>
* Attach the #GstControlSource on the controller to a property.
* gst_object_set_control_source (object, "prop1", csource);
* </para></listitem>
* <listitem><para>
* Set the control values
* gst_interpolation_control_source_set (csource,0 * GST_SECOND, value1);
* gst_interpolation_control_source_set (csource,1 * GST_SECOND, value2);
* </para></listitem>
* <listitem><para>
* start your pipeline
* </para></listitem>
* </orderedlist>
* </refsect2>
*
* Last reviewed on 2005-11-09 (0.9.4) * Last reviewed on 2005-11-09 (0.9.4)
*/ */
@ -88,8 +138,10 @@
#include "gstobject.h" #include "gstobject.h"
#include "gstmarshal.h" #include "gstmarshal.h"
#include "gstcontroller.h" #include "gstclock.h"
#include "gstcontrolsource.h"
#include "gstinfo.h" #include "gstinfo.h"
#include "gstparamspecs.h"
#include "gstutils.h" #include "gstutils.h"
#ifndef GST_DISABLE_TRACE #ifndef GST_DISABLE_TRACE
@ -142,6 +194,21 @@ static guint gst_object_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *properties[PROP_LAST]; static GParamSpec *properties[PROP_LAST];
/*
* GstControlledProperty:
*/
typedef struct _GstControlledProperty
{
GParamSpec *pspec; /* GParamSpec for this property */
const gchar *name; /* name of the property */
GstControlSource *csource; /* GstControlSource for this property */
gboolean disabled;
GValue last_value;
} GstControlledProperty;
static void gst_controlled_property_free (GstControlledProperty * prop);
G_DEFINE_ABSTRACT_TYPE (GstObject, gst_object, G_TYPE_INITIALLY_UNOWNED); G_DEFINE_ABSTRACT_TYPE (GstObject, gst_object, G_TYPE_INITIALLY_UNOWNED);
static void static void
@ -208,6 +275,9 @@ gst_object_init (GstObject * object)
#endif #endif
object->flags = 0; object->flags = 0;
object->control_rate = 100 * GST_MSECOND;
object->last_sync = GST_CLOCK_TIME_NONE;
} }
/** /**
@ -354,9 +424,14 @@ gst_object_dispose (GObject * object)
GST_OBJECT_PARENT (object) = NULL; GST_OBJECT_PARENT (object) = NULL;
GST_OBJECT_UNLOCK (object); GST_OBJECT_UNLOCK (object);
if (self->ctrl) { if (self->properties) {
g_object_unref (self->ctrl); GList *node;
self->ctrl = NULL;
for (node = self->properties; node; node = g_list_next (node)) {
gst_controlled_property_free ((GstControlledProperty *) node->data);
}
g_list_free (self->properties);
self->properties = NULL;
} }
((GObjectClass *) gst_object_parent_class)->dispose (object); ((GObjectClass *) gst_object_parent_class)->dispose (object);
@ -958,6 +1033,151 @@ gst_object_get_path_string (GstObject * object)
return path; return path;
} }
/* controller helper functions */
/*
* 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 (GstObject * 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 && controlable && !construct-only */
g_return_val_if_fail ((pspec->flags & (G_PARAM_WRITABLE |
GST_PARAM_CONTROLLABLE | G_PARAM_CONSTRUCT_ONLY)) ==
(G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE), NULL);
if ((prop = g_slice_new (GstControlledProperty))) {
prop->pspec = pspec;
prop->name = pspec->name;
prop->csource = NULL;
prop->disabled = FALSE;
memset (&prop->last_value, 0, sizeof (GValue));
g_value_init (&prop->last_value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
}
} 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)
{
if (prop->csource)
g_object_unref (prop->csource);
g_value_unset (&prop->last_value);
g_slice_free (GstControlledProperty, prop);
}
/*
* gst_object_find_controlled_property:
* @self: the gobject to search for a property in
* @name: the gobject property name to look for
*
* Searches the list of properties under control.
*
* Returns: a #GstControlledProperty or %NULL if the property is not being
* controlled.
*/
static GstControlledProperty *
gst_object_find_controlled_property (GstObject * self, const gchar * name)
{
GstControlledProperty *prop;
GList *node;
for (node = self->properties; node; node = g_list_next (node)) {
prop = node->data;
/* FIXME: eventually use GQuark to speed it up */
if (!strcmp (prop->name, name)) {
return prop;
}
}
GST_DEBUG ("controller does not (yet) manage property '%s'", name);
return NULL;
}
/*
* gst_object_add_controlled_property:
* @self: the object
* @name: name of projecty in @object
*
* Creates a new #GstControlledProperty if there is none for property @name yet.
*
* Returns: %TRUE if the property has been added to the controller
*/
static gboolean
gst_object_add_controlled_property (GstObject * self, const gchar * name)
{
gboolean res = TRUE;
/* test if this property isn't yet controlled */
if (!gst_object_find_controlled_property (self, name)) {
GstControlledProperty *prop;
/* create GstControlledProperty and add to self->properties list */
if ((prop = gst_controlled_property_new (self, name))) {
self->properties = g_list_prepend (self->properties, prop);
GST_DEBUG_OBJECT (self, "property %s added", name);
} else
res = FALSE;
} else {
GST_WARNING_OBJECT (self, "trying to control property %s again", name);
}
return res;
}
/*
* gst_object_remove_controlled_property:
* @self: the object
* @name: name of projecty in @object
*
* Removes a #GstControlledProperty for property @name.
*
* Returns: %TRUE if the property has been removed from the controller
*/
static gboolean
gst_object_remove_controlled_property (GstObject * self, const gchar * name)
{
gboolean res = TRUE;
GstControlledProperty *prop;
if ((prop = gst_object_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);
GST_DEBUG_OBJECT (self, "property %s removed", name);
} else {
res = FALSE;
}
return res;
}
/* controller functions */ /* controller functions */
/** /**
@ -975,24 +1195,18 @@ gst_object_get_path_string (GstObject * object)
gboolean gboolean
gst_object_control_properties (GstObject * object, ...) gst_object_control_properties (GstObject * object, ...)
{ {
gboolean res = FALSE; gboolean res = TRUE;
va_list var_args; va_list var_args;
gchar *name;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
va_start (var_args, object); va_start (var_args, object);
if (object->ctrl) { GST_OBJECT_LOCK (object);
GstController *ctrl = gst_controller_new_valist (object, var_args); while ((name = va_arg (var_args, gchar *))) {
res &= gst_object_add_controlled_property (object, name);
/* FIXME: see gst_controller_new_*() */
g_object_unref (object->ctrl);
object->ctrl = ctrl;
res = (object->ctrl != NULL);
} else {
res = gst_controller_add_properties_valist ((GstController *) object->ctrl,
var_args);
} }
GST_OBJECT_UNLOCK (object);
va_end (var_args); va_end (var_args);
return res; return res;
} }
@ -1010,17 +1224,19 @@ gst_object_control_properties (GstObject * object, ...)
gboolean gboolean
gst_object_uncontrol_properties (GstObject * object, ...) gst_object_uncontrol_properties (GstObject * object, ...)
{ {
gboolean res = FALSE; gboolean res = TRUE;
va_list var_args;
gchar *name;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
if (object->ctrl) { va_start (var_args, object);
va_list var_args; GST_OBJECT_LOCK (object);
while ((name = va_arg (var_args, gchar *))) {
va_start (var_args, object); res &= gst_object_remove_controlled_property (object, name);
res = gst_controller_remove_properties_valist (
(GstController *) object->ctrl, var_args);
va_end (var_args);
} }
GST_OBJECT_UNLOCK (object);
va_end (var_args);
return (res); return (res);
} }
@ -1028,18 +1244,32 @@ gst_object_uncontrol_properties (GstObject * object, ...)
* gst_object_suggest_next_sync: * gst_object_suggest_next_sync:
* @object: the object that has controlled properties * @object: the object that has controlled properties
* *
* Convenience function for GObject * Returns a suggestion for timestamps where buffers should be split
* to get best controller results.
* *
* Returns: same thing as gst_controller_suggest_next_sync() * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
* if no control-rate was set.
*/ */
GstClockTime GstClockTime
gst_object_suggest_next_sync (GstObject * object) gst_object_suggest_next_sync (GstObject * object)
{ {
g_return_val_if_fail (GST_IS_OBJECT (object), GST_CLOCK_TIME_NONE); GstClockTime ret;
if (object->ctrl) g_return_val_if_fail (GST_IS_OBJECT (object), GST_CLOCK_TIME_NONE);
return gst_controller_suggest_next_sync ((GstController *) object->ctrl); g_return_val_if_fail (object->control_rate != GST_CLOCK_TIME_NONE,
return (GST_CLOCK_TIME_NONE); GST_CLOCK_TIME_NONE);
GST_OBJECT_LOCK (object);
/* TODO: Implement more logic, depending on interpolation mode and control
* points
* FIXME: we need playback direction
*/
ret = object->last_sync + object->control_rate;
GST_OBJECT_UNLOCK (object);
return ret;
} }
/** /**
@ -1047,64 +1277,122 @@ gst_object_suggest_next_sync (GstObject * object)
* @object: the object that has controlled properties * @object: the object that has controlled properties
* @timestamp: the time that should be processed * @timestamp: the time that should be processed
* *
* Convenience function for GObject * Sets the properties of the object, according to the #GstControlSources that
* (maybe) handle them and for the given timestamp.
* *
* Returns: same thing as gst_controller_sync_values() * If this function fails, it is most likely the application developers fault.
* Most probably the control sources are not setup correctly.
*
* Returns: %TRUE if the controller values could be applied to the object
* properties, %FALSE otherwise
*/ */
gboolean gboolean
gst_object_sync_values (GstObject * object, GstClockTime timestamp) gst_object_sync_values (GstObject * object, GstClockTime timestamp)
{ {
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); GstControlledProperty *prop;
GList *node;
gboolean ret = TRUE, val_ret;
GValue value = { 0, };
if (object->ctrl) g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
return gst_controller_sync_values ((GstController *) object->ctrl, g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
timestamp);
/* this is no failure, its called by elements regardless if there is a GST_LOG ("sync_values");
* controller assigned or not */
return (TRUE); /* FIXME: this deadlocks */
/* GST_OBJECT_LOCK (object); */
g_object_freeze_notify ((GObject *) object);
/* go over the controlled properties of the controller */
for (node = object->properties; node; node = g_list_next (node)) {
prop = node->data;
if (!prop->csource || prop->disabled)
continue;
GST_LOG ("property '%s' at ts=%" G_GUINT64_FORMAT, prop->name, timestamp);
/* we can make this faster
* http://bugzilla.gnome.org/show_bug.cgi?id=536939
*/
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop->pspec));
val_ret = gst_control_source_get_value (prop->csource, timestamp, &value);
if (G_LIKELY (val_ret)) {
/* always set the value for first time, but then only if it changed
* this should limit g_object_notify invocations.
* FIXME: can we detect negative playback rates?
*/
if ((timestamp < object->last_sync) ||
gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
g_object_set_property ((GObject *) object, prop->name, &value);
g_value_copy (&value, &prop->last_value);
}
} else {
GST_DEBUG ("no control value for param %s", prop->name);
}
g_value_unset (&value);
ret &= val_ret;
}
object->last_sync = timestamp;
g_object_thaw_notify ((GObject *) object);
/* GST_OBJECT_UNLOCK (object); */
return ret;
} }
/** /**
* gst_object_has_active_automation: * gst_object_has_active_controlled_properties:
* @object: the object that has controlled properties * @object: the object that has controlled properties
* *
* Check if the object has an active controller. It has one if it has at least * Check if the @object has an active controlled properties.
* one controlled property that is not disabled.
* *
* Returns: %TRUE if the controller is active * Returns: %TRUE if the object has active controlled properties
*/ */
gboolean gboolean
gst_object_has_active_automation (GstObject * object) gst_object_has_active_controlled_properties (GstObject * object)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GList *node;
GstControlledProperty *prop;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
if (object->ctrl) GST_OBJECT_LOCK (object);
res = gst_controller_is_active ((GstController *) object->ctrl); for (node = object->properties; node; node = node->next) {
prop = node->data;
res |= !prop->disabled;
}
GST_OBJECT_UNLOCK (object);
return res; return res;
} }
/** /**
* gst_object_set_automation_disabled: * gst_object_set_controlled_properties_disabled:
* @object: the object that has controlled properties * @object: the object that has controlled properties
* @disabled: boolean that specifies whether to disable the controller * @disabled: boolean that specifies whether to disable the controller
* or not. * or not.
* *
* This function is used to disable all properties of the #GstController * This function is used to disable all controlled properties of the @object for
* for some time, i.e. gst_object_sync_values() will do nothing.. * some time, i.e. gst_object_sync_values() will do nothing..
*/ */
void void
gst_object_set_automation_disabled (GstObject * object, gboolean disabled) gst_object_set_controlled_properties_disabled (GstObject * object,
gboolean disabled)
{ {
GList *node;
GstControlledProperty *prop;
g_return_if_fail (GST_IS_OBJECT (object)); g_return_if_fail (GST_IS_OBJECT (object));
if (object->ctrl) GST_OBJECT_LOCK (object);
gst_controller_set_disabled (object->ctrl, disabled); for (node = object->properties; node; node = node->next) {
prop = node->data;
prop->disabled = disabled;
}
GST_OBJECT_UNLOCK (object);
} }
/** /**
* gst_object_set_property_automation_disabled: * gst_object_set_controlled_property_disabled:
* @object: the object that has controlled properties * @object: the object that has controlled properties
* @property_name: property to disable * @property_name: property to disable
* @disabled: boolean that specifies whether to disable the controller * @disabled: boolean that specifies whether to disable the controller
@ -1115,15 +1403,19 @@ gst_object_set_automation_disabled (GstObject * object, gboolean disabled)
* property. * property.
*/ */
void void
gst_object_set_property_automation_disabled (GstObject * object, gst_object_set_controlled_property_disabled (GstObject * object,
const gchar * property_name, gboolean disabled) const gchar * property_name, gboolean disabled)
{ {
GstControlledProperty *prop;
g_return_if_fail (GST_IS_OBJECT (object)); g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (property_name); g_return_if_fail (property_name);
if (object->ctrl) GST_OBJECT_LOCK (object);
gst_controller_set_property_disabled ((GstController *) object->ctrl, if ((prop = gst_object_find_controlled_property (object, property_name))) {
property_name, disabled); prop->disabled = disabled;
}
GST_OBJECT_UNLOCK (object);
} }
/** /**
@ -1142,14 +1434,30 @@ gboolean
gst_object_set_control_source (GstObject * object, const gchar * property_name, gst_object_set_control_source (GstObject * object, const gchar * property_name,
GstControlSource * csource) GstControlSource * csource)
{ {
GstControlledProperty *prop;
gboolean ret = FALSE;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (property_name, FALSE); g_return_val_if_fail (property_name, FALSE);
g_return_val_if_fail (GST_IS_CONTROL_SOURCE (csource), FALSE); g_return_val_if_fail ((!csource || GST_IS_CONTROL_SOURCE (csource)), FALSE);
if (object->ctrl) GST_OBJECT_LOCK (object);
return gst_controller_set_control_source ((GstController *) object->ctrl, if ((prop = gst_object_find_controlled_property (object, property_name))) {
property_name, csource); GstControlSource *old = prop->csource;
return FALSE;
if (csource && (ret = gst_control_source_bind (csource, prop->pspec))) {
prop->csource = g_object_ref (csource);
} else if (!csource) {
ret = TRUE;
prop->csource = NULL;
}
if (ret && old)
g_object_unref (old);
}
GST_OBJECT_UNLOCK (object);
return ret;
} }
/** /**
@ -1167,26 +1475,64 @@ gst_object_set_control_source (GstObject * object, const gchar * property_name,
GstControlSource * GstControlSource *
gst_object_get_control_source (GstObject * object, const gchar * property_name) gst_object_get_control_source (GstObject * object, const gchar * property_name)
{ {
GstControlledProperty *prop;
GstControlSource *ret = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL); g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
g_return_val_if_fail (property_name, NULL); g_return_val_if_fail (property_name, NULL);
if (object->ctrl) GST_OBJECT_LOCK (object);
return gst_controller_get_control_source ((GstController *) object->ctrl, if ((prop = gst_object_find_controlled_property (object, property_name))) {
property_name); if ((ret = prop->csource))
return NULL; g_object_ref (ret);
}
GST_OBJECT_UNLOCK (object);
return ret;
} }
// FIXME: docs /**
* gst_object_get_value:
* @object: the object that has controlled 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 controllered property at the requested time.
*
* Returns: the GValue of the property at the given time, or %NULL if the
* property isn't controlled.
*/
GValue * GValue *
gst_object_get_value (GstObject * object, const gchar * property_name, gst_object_get_value (GstObject * object, const gchar * property_name,
GstClockTime timestamp) GstClockTime timestamp)
{ {
GstControlledProperty *prop;
GValue *val = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL); g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
g_return_val_if_fail (property_name, NULL); g_return_val_if_fail (property_name, NULL);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
if (object->ctrl) GST_OBJECT_LOCK (object);
return gst_controller_get (object->ctrl, property_name, timestamp); if ((prop = gst_object_find_controlled_property (object, property_name))) {
return NULL; 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 = NULL;
}
} else {
g_object_get_property ((GObject *) object, prop->name, val);
}
}
GST_OBJECT_UNLOCK (object);
return val;
} }
/** /**
@ -1210,13 +1556,17 @@ gboolean
gst_object_get_value_arrays (GstObject * object, GstClockTime timestamp, gst_object_get_value_arrays (GstObject * object, GstClockTime timestamp,
GSList * value_arrays) GSList * value_arrays)
{ {
gboolean res = TRUE;
GSList *node;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_return_val_if_fail (value_arrays, FALSE);
if (object->ctrl) for (node = value_arrays; (res && node); node = g_slist_next (node)) {
return gst_controller_get_value_arrays ((GstController *) object->ctrl, res = gst_object_get_value_array (object, timestamp, node->data);
timestamp, value_arrays); }
return (FALSE); return res;
} }
/** /**
@ -1238,13 +1588,30 @@ gboolean
gst_object_get_value_array (GstObject * object, GstClockTime timestamp, gst_object_get_value_array (GstObject * object, GstClockTime timestamp,
GstValueArray * value_array) GstValueArray * value_array)
{ {
gboolean res = FALSE;
GstControlledProperty *prop;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), 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);
g_return_val_if_fail (value_array->values, FALSE);
if (object->ctrl) GST_OBJECT_LOCK (object);
return gst_controller_get_value_array ((GstController *) object->ctrl,
timestamp, value_array); if ((prop = gst_object_find_controlled_property (object,
return (FALSE); value_array->property_name))) {
/* get current value_array via control source */
if (!prop->csource)
goto out;
res = gst_control_source_get_value_array (prop->csource, timestamp,
value_array);
}
out:
GST_OBJECT_UNLOCK (object);
return res;
} }
/** /**
@ -1267,13 +1634,9 @@ gst_object_get_value_array (GstObject * object, GstClockTime timestamp,
GstClockTime GstClockTime
gst_object_get_control_rate (GstObject * object) gst_object_get_control_rate (GstObject * object)
{ {
GstClockTime control_rate = GST_CLOCK_TIME_NONE;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
if (object->ctrl) return object->control_rate;
g_object_get (object->ctrl, "control-rate", &control_rate, NULL);
return (control_rate);
} }
/** /**
@ -1294,6 +1657,5 @@ gst_object_set_control_rate (GstObject * object, GstClockTime control_rate)
{ {
g_return_if_fail (GST_IS_OBJECT (object)); g_return_if_fail (GST_IS_OBJECT (object));
if (object->ctrl) object->control_rate = control_rate;
g_object_set (object->ctrl, "control-rate", control_rate, NULL);
} }

View file

@ -171,7 +171,10 @@ struct _GstObject {
guint32 flags; guint32 flags;
/*< private >*/ /*< private >*/
gpointer ctrl; /* time controlled properties */ GList *properties; /* List of GstControlledProperty */
guint64 control_rate;
guint64 last_sync;
gpointer _gst_reserved; gpointer _gst_reserved;
}; };
@ -229,7 +232,6 @@ gchar * gst_object_get_path_string (GstObject *object);
gboolean gst_object_check_uniqueness (GList *list, const gchar *name); gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
/* controller functions */ /* controller functions */
#include <gst/gstclock.h>
#include <gst/gstcontrolsource.h> #include <gst/gstcontrolsource.h>
gboolean gst_object_control_properties (GstObject * object, ...) G_GNUC_NULL_TERMINATED; gboolean gst_object_control_properties (GstObject * object, ...) G_GNUC_NULL_TERMINATED;
@ -238,9 +240,9 @@ gboolean gst_object_uncontrol_properties (GstObject * object, ...) G_GNUC_NULL_T
GstClockTime gst_object_suggest_next_sync (GstObject * object); GstClockTime gst_object_suggest_next_sync (GstObject * object);
gboolean gst_object_sync_values (GstObject * object, GstClockTime timestamp); gboolean gst_object_sync_values (GstObject * object, GstClockTime timestamp);
gboolean gst_object_has_active_automation (GstObject *object); gboolean gst_object_has_active_controlled_properties (GstObject *object);
void gst_object_set_automation_disabled (GstObject *object, gboolean disabled); void gst_object_set_controlled_properties_disabled (GstObject *object, gboolean disabled);
void gst_object_set_property_automation_disabled (GstObject *object, const gchar * property_name, gboolean disabled); void gst_object_set_controlled_property_disabled (GstObject *object, const gchar * property_name, gboolean disabled);
gboolean gst_object_set_control_source (GstObject *object, const gchar * property_name, GstControlSource *csource); gboolean gst_object_set_control_source (GstObject *object, const gchar * property_name, GstControlSource *csource);
GstControlSource * gst_object_get_control_source (GstObject *object, const gchar * property_name); GstControlSource * gst_object_get_control_source (GstObject *object, const gchar * property_name);

View file

@ -19,6 +19,8 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/controller/gstinterpolationcontrolsource.h> #include <gst/controller/gstinterpolationcontrolsource.h>
@ -80,7 +82,6 @@ main (gint argc, gchar * argv[])
gint i, j; gint i, j;
GstElement *src, *sink; GstElement *src, *sink;
GstElement *bin; GstElement *bin;
GstController *ctrl;
GstInterpolationControlSource *csource; GstInterpolationControlSource *csource;
GValue freq = { 0, }; GValue freq = { 0, };
GstClockTime bt, ct; GstClockTime bt, ct;
@ -109,15 +110,15 @@ main (gint argc, gchar * argv[])
tick = BLOCK_SIZE * GST_SECOND / 44100; tick = BLOCK_SIZE * GST_SECOND / 44100;
/* add a controller to the source */ /* select parameters to control */
if (!(ctrl = gst_controller_new (GST_OBJECT (src), "freq", NULL))) { if (!gst_object_control_properties (GST_OBJECT (src), "freq", NULL)) {
GST_WARNING ("can't control source element"); GST_WARNING ("can't control source element");
goto Error; goto Error;
} }
/* create and configure control source */ /* create and configure control source */
csource = gst_interpolation_control_source_new (); csource = gst_interpolation_control_source_new ();
gst_controller_set_control_source (ctrl, "freq", gst_object_set_control_source (GST_OBJECT (src), "freq",
GST_CONTROL_SOURCE (csource)); GST_CONTROL_SOURCE (csource));
gst_interpolation_control_source_set_interpolation_mode (csource, gst_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_LINEAR); GST_INTERPOLATE_LINEAR);
@ -194,7 +195,6 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (elapsed)); GST_TIME_ARGS (elapsed));
/* cleanup */ /* cleanup */
g_object_unref (G_OBJECT (ctrl));
gst_object_unref (G_OBJECT (bin)); gst_object_unref (G_OBJECT (bin));
res = 0; res = 0;
Error: Error:

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,6 @@ main (gint argc, gchar ** argv)
gint res = 1; gint res = 1;
GstElement *src, *sink; GstElement *src, *sink;
GstElement *bin; GstElement *bin;
GstController *ctrl;
GstInterpolationControlSource *csource1, *csource2; GstInterpolationControlSource *csource1, *csource2;
GstClock *clock; GstClock *clock;
GstClockID clock_id; GstClockID clock_id;
@ -50,7 +49,7 @@ main (gint argc, gchar ** argv)
*/ */
/* add a controller to the source */ /* add a controller to the source */
if (!(ctrl = gst_controller_new (GST_OBJECT (src), "freq", "volume", NULL))) { if (!gst_object_control_properties (GST_OBJECT (src), "freq", "volume", NULL)) {
GST_WARNING ("can't control source element"); GST_WARNING ("can't control source element");
goto Error; goto Error;
} }
@ -58,9 +57,9 @@ main (gint argc, gchar ** argv)
csource1 = gst_interpolation_control_source_new (); csource1 = gst_interpolation_control_source_new ();
csource2 = gst_interpolation_control_source_new (); csource2 = gst_interpolation_control_source_new ();
gst_controller_set_control_source (ctrl, "volume", gst_object_set_control_source (GST_OBJECT (src), "volume",
GST_CONTROL_SOURCE (csource1)); GST_CONTROL_SOURCE (csource1));
gst_controller_set_control_source (ctrl, "freq", gst_object_set_control_source (GST_OBJECT (src), "freq",
GST_CONTROL_SOURCE (csource2)); GST_CONTROL_SOURCE (csource2));
/* Set interpolation mode */ /* Set interpolation mode */
@ -101,7 +100,6 @@ main (gint argc, gchar ** argv)
} }
/* cleanup */ /* cleanup */
g_object_unref (G_OBJECT (ctrl));
gst_clock_id_unref (clock_id); gst_clock_id_unref (clock_id);
gst_object_unref (G_OBJECT (clock)); gst_object_unref (G_OBJECT (clock));
gst_object_unref (G_OBJECT (bin)); gst_object_unref (G_OBJECT (bin));