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/gstclock.xml" />
<xi:include href="xml/gstconfig.xml" />
<xi:include href="xml/gstcontroller.xml" />
<xi:include href="xml/gstcontrolsource.xml" />
<xi:include href="xml/gstdatetime.xml" />
<xi:include href="xml/gstelement.xml" />

View file

@ -556,41 +556,6 @@ GST_PADDING_INIT
GST_USING_PRINTF_EXTENSION
</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>
<FILE>gstcontrolsource</FILE>
@ -1568,9 +1533,9 @@ gst_object_control_properties
gst_object_uncontrol_properties
gst_object_suggest_next_sync
gst_object_sync_values
gst_object_has_active_automation
gst_object_set_automation_disabled
gst_object_set_property_automation_disabled
gst_object_has_active_controlled_properties
gst_object_set_controlled_properties_disabled
gst_object_set_controlled_property_disabled
gst_object_get_control_source
gst_object_set_control_source
gst_object_get_value

View file

@ -12,7 +12,6 @@ gst_bin_get_type
gst_bus_get_type
gst_child_proxy_get_type
gst_clock_get_type
gst_controller_get_type
gst_control_source_get_type
gst_element_factory_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_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 \
gstchildproxy.c \
gstclock.c \
gstcontroller.c \
gstcontrolsource.c \
gstdatetime.c \
gstdebugutils.c \
@ -150,7 +149,6 @@ gst_headers = \
gstchildproxy.h \
gstclock.h \
gstcompat.h \
gstcontroller.h \
gstcontrolsource.h \
gstdatetime.h \
gstdebugutils.h \

View file

@ -44,7 +44,6 @@
#include <gst/gstcaps.h>
#include <gst/gstchildproxy.h>
#include <gst/gstclock.h>
#include <gst/gstcontroller.h>
#include <gst/gstcontrolsource.h>
#include <gst/gstdatetime.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"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
#define GST_CAT_DEFAULT control_source_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
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 */
klass->bind = NULL;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontrolsource", 0,
"dynamic parameter control sources");
}
static void

View file

@ -80,6 +80,56 @@
* gst_object_set_name() and gst_object_get_name() are used to set/get the name
* 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)
*/
@ -88,8 +138,10 @@
#include "gstobject.h"
#include "gstmarshal.h"
#include "gstcontroller.h"
#include "gstclock.h"
#include "gstcontrolsource.h"
#include "gstinfo.h"
#include "gstparamspecs.h"
#include "gstutils.h"
#ifndef GST_DISABLE_TRACE
@ -142,6 +194,21 @@ static guint gst_object_signals[LAST_SIGNAL] = { 0 };
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);
static void
@ -208,6 +275,9 @@ gst_object_init (GstObject * object)
#endif
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_UNLOCK (object);
if (self->ctrl) {
g_object_unref (self->ctrl);
self->ctrl = NULL;
if (self->properties) {
GList *node;
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);
@ -958,6 +1033,151 @@ gst_object_get_path_string (GstObject * object)
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 */
/**
@ -975,24 +1195,18 @@ gst_object_get_path_string (GstObject * object)
gboolean
gst_object_control_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);
va_start (var_args, object);
if (object->ctrl) {
GstController *ctrl = gst_controller_new_valist (object, var_args);
/* 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_LOCK (object);
while ((name = va_arg (var_args, gchar *))) {
res &= gst_object_add_controlled_property (object, name);
}
GST_OBJECT_UNLOCK (object);
va_end (var_args);
return res;
}
@ -1010,17 +1224,19 @@ gst_object_control_properties (GstObject * object, ...)
gboolean
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);
if (object->ctrl) {
va_list var_args;
va_start (var_args, object);
res = gst_controller_remove_properties_valist (
(GstController *) object->ctrl, var_args);
va_end (var_args);
va_start (var_args, object);
GST_OBJECT_LOCK (object);
while ((name = va_arg (var_args, gchar *))) {
res &= gst_object_remove_controlled_property (object, name);
}
GST_OBJECT_UNLOCK (object);
va_end (var_args);
return (res);
}
@ -1028,18 +1244,32 @@ gst_object_uncontrol_properties (GstObject * object, ...)
* gst_object_suggest_next_sync:
* @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
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)
return gst_controller_suggest_next_sync ((GstController *) object->ctrl);
return (GST_CLOCK_TIME_NONE);
g_return_val_if_fail (GST_IS_OBJECT (object), GST_CLOCK_TIME_NONE);
g_return_val_if_fail (object->control_rate != 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
* @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
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)
return gst_controller_sync_values ((GstController *) object->ctrl,
timestamp);
/* this is no failure, its called by elements regardless if there is a
* controller assigned or not */
return (TRUE);
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
GST_LOG ("sync_values");
/* 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
*
* Check if the object has an active controller. It has one if it has at least
* one controlled property that is not disabled.
* Check if the @object has an active controlled properties.
*
* Returns: %TRUE if the controller is active
* Returns: %TRUE if the object has active controlled properties
*/
gboolean
gst_object_has_active_automation (GstObject * object)
gst_object_has_active_controlled_properties (GstObject * object)
{
gboolean res = FALSE;
GList *node;
GstControlledProperty *prop;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
if (object->ctrl)
res = gst_controller_is_active ((GstController *) object->ctrl);
GST_OBJECT_LOCK (object);
for (node = object->properties; node; node = node->next) {
prop = node->data;
res |= !prop->disabled;
}
GST_OBJECT_UNLOCK (object);
return res;
}
/**
* gst_object_set_automation_disabled:
* gst_object_set_controlled_properties_disabled:
* @object: the object that has controlled properties
* @disabled: boolean that specifies whether to disable the controller
* or not.
*
* This function is used to disable all properties of the #GstController
* for some time, i.e. gst_object_sync_values() will do nothing..
* This function is used to disable all controlled properties of the @object for
* some time, i.e. gst_object_sync_values() will do nothing..
*/
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));
if (object->ctrl)
gst_controller_set_disabled (object->ctrl, disabled);
GST_OBJECT_LOCK (object);
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
* @property_name: property to disable
* @disabled: boolean that specifies whether to disable the controller
@ -1115,15 +1403,19 @@ gst_object_set_automation_disabled (GstObject * object, gboolean disabled)
* property.
*/
void
gst_object_set_property_automation_disabled (GstObject * object,
gst_object_set_controlled_property_disabled (GstObject * object,
const gchar * property_name, gboolean disabled)
{
GstControlledProperty *prop;
g_return_if_fail (GST_IS_OBJECT (object));
g_return_if_fail (property_name);
if (object->ctrl)
gst_controller_set_property_disabled ((GstController *) object->ctrl,
property_name, disabled);
GST_OBJECT_LOCK (object);
if ((prop = gst_object_find_controlled_property (object, property_name))) {
prop->disabled = disabled;
}
GST_OBJECT_UNLOCK (object);
}
/**
@ -1142,14 +1434,30 @@ gboolean
gst_object_set_control_source (GstObject * object, const gchar * property_name,
GstControlSource * csource)
{
GstControlledProperty *prop;
gboolean ret = FALSE;
g_return_val_if_fail (GST_IS_OBJECT (object), 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)
return gst_controller_set_control_source ((GstController *) object->ctrl,
property_name, csource);
return FALSE;
GST_OBJECT_LOCK (object);
if ((prop = gst_object_find_controlled_property (object, property_name))) {
GstControlSource *old = prop->csource;
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 *
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 (property_name, NULL);
if (object->ctrl)
return gst_controller_get_control_source ((GstController *) object->ctrl,
property_name);
return NULL;
GST_OBJECT_LOCK (object);
if ((prop = gst_object_find_controlled_property (object, property_name))) {
if ((ret = prop->csource))
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 *
gst_object_get_value (GstObject * object, const gchar * property_name,
GstClockTime timestamp)
{
GstControlledProperty *prop;
GValue *val = NULL;
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
g_return_val_if_fail (property_name, NULL);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL);
if (object->ctrl)
return gst_controller_get (object->ctrl, property_name, timestamp);
return NULL;
GST_OBJECT_LOCK (object);
if ((prop = gst_object_find_controlled_property (object, property_name))) {
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,
GSList * value_arrays)
{
gboolean res = TRUE;
GSList *node;
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 (value_arrays, FALSE);
if (object->ctrl)
return gst_controller_get_value_arrays ((GstController *) object->ctrl,
timestamp, value_arrays);
return (FALSE);
for (node = value_arrays; (res && node); node = g_slist_next (node)) {
res = gst_object_get_value_array (object, timestamp, node->data);
}
return res;
}
/**
@ -1238,13 +1588,30 @@ gboolean
gst_object_get_value_array (GstObject * object, GstClockTime timestamp,
GstValueArray * value_array)
{
gboolean res = FALSE;
GstControlledProperty *prop;
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 (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)
return gst_controller_get_value_array ((GstController *) object->ctrl,
timestamp, value_array);
return (FALSE);
GST_OBJECT_LOCK (object);
if ((prop = gst_object_find_controlled_property (object,
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
gst_object_get_control_rate (GstObject * object)
{
GstClockTime control_rate = GST_CLOCK_TIME_NONE;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
if (object->ctrl)
g_object_get (object->ctrl, "control-rate", &control_rate, NULL);
return (control_rate);
return object->control_rate;
}
/**
@ -1294,6 +1657,5 @@ gst_object_set_control_rate (GstObject * object, GstClockTime control_rate)
{
g_return_if_fail (GST_IS_OBJECT (object));
if (object->ctrl)
g_object_set (object->ctrl, "control-rate", control_rate, NULL);
object->control_rate = control_rate;
}

View file

@ -171,7 +171,10 @@ struct _GstObject {
guint32 flags;
/*< private >*/
gpointer ctrl; /* time controlled properties */
GList *properties; /* List of GstControlledProperty */
guint64 control_rate;
guint64 last_sync;
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);
/* controller functions */
#include <gst/gstclock.h>
#include <gst/gstcontrolsource.h>
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);
gboolean gst_object_sync_values (GstObject * object, GstClockTime timestamp);
gboolean gst_object_has_active_automation (GstObject *object);
void gst_object_set_automation_disabled (GstObject *object, gboolean disabled);
void gst_object_set_property_automation_disabled (GstObject *object, const gchar * property_name, gboolean disabled);
gboolean gst_object_has_active_controlled_properties (GstObject *object);
void gst_object_set_controlled_properties_disabled (GstObject *object, 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);
GstControlSource * gst_object_get_control_source (GstObject *object, const gchar * property_name);

View file

@ -19,6 +19,8 @@
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <gst/gst.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
@ -80,7 +82,6 @@ main (gint argc, gchar * argv[])
gint i, j;
GstElement *src, *sink;
GstElement *bin;
GstController *ctrl;
GstInterpolationControlSource *csource;
GValue freq = { 0, };
GstClockTime bt, ct;
@ -109,15 +110,15 @@ main (gint argc, gchar * argv[])
tick = BLOCK_SIZE * GST_SECOND / 44100;
/* add a controller to the source */
if (!(ctrl = gst_controller_new (GST_OBJECT (src), "freq", NULL))) {
/* select parameters to control */
if (!gst_object_control_properties (GST_OBJECT (src), "freq", NULL)) {
GST_WARNING ("can't control source element");
goto Error;
}
/* create and configure control source */
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_interpolation_control_source_set_interpolation_mode (csource,
GST_INTERPOLATE_LINEAR);
@ -194,7 +195,6 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (elapsed));
/* cleanup */
g_object_unref (G_OBJECT (ctrl));
gst_object_unref (G_OBJECT (bin));
res = 0;
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;
GstElement *src, *sink;
GstElement *bin;
GstController *ctrl;
GstInterpolationControlSource *csource1, *csource2;
GstClock *clock;
GstClockID clock_id;
@ -50,7 +49,7 @@ main (gint argc, gchar ** argv)
*/
/* 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");
goto Error;
}
@ -58,9 +57,9 @@ main (gint argc, gchar ** argv)
csource1 = 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_controller_set_control_source (ctrl, "freq",
gst_object_set_control_source (GST_OBJECT (src), "freq",
GST_CONTROL_SOURCE (csource2));
/* Set interpolation mode */
@ -101,7 +100,6 @@ main (gint argc, gchar ** argv)
}
/* cleanup */
g_object_unref (G_OBJECT (ctrl));
gst_clock_id_unref (clock_id);
gst_object_unref (G_OBJECT (clock));
gst_object_unref (G_OBJECT (bin));