controller: move to core/gstobject

Move the controller to gstobject as a simple delegate. The controller and
controlsource are not classes in core. The controlsources stay separate as a lib
for now. This way we can avoid the qdata lookups.

Also remove controller_init(). There is no more need to link to controller for
elements.

Also sanitize the API. We now have functions to add properties like we had
methods to remove that. That avoids then ref count hacks we had in _new.
This commit is contained in:
Stefan Sauer 2011-11-04 11:34:11 +01:00
parent 0f123cba23
commit 9a27b9c056
17 changed files with 512 additions and 612 deletions

View file

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

View file

@ -44,6 +44,8 @@
#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>
#include <gst/gstelement.h>

View file

@ -24,8 +24,6 @@
#ifndef __GST_CLOCK_H__
#define __GST_CLOCK_H__
#include <gst/gstobject.h>
G_BEGIN_DECLS
/* --- standard type macros --- */
@ -375,6 +373,8 @@ struct _GstClockEntry {
gboolean woken_up;
};
#include <gst/gstobject.h>
/**
* GstClockFlags:
* @GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC: clock can do a single sync timeout request

View file

@ -1,7 +1,8 @@
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
* Copyright (C) 2005 Stefan Kost <ensonic at users dot sf dot net>
* 2007 Sebastian Dröge <slomo@circular-chaos.org>
* 2011 Stefan Sauer <ensonic at users dot sf dot net>
*
* gstcontroller.c: dynamic parameter control subsystem
*
@ -72,20 +73,19 @@
* </orderedlist>
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gst_private.h"
#include "gstobject.h"
#include "gstclock.h"
#include "gstinfo.h"
#include "gstcontroller.h"
#include "gstcontrollerprivate.h"
#include "gstcontrolsource.h"
#include "gstinterpolationcontrolsource.h"
#include "gstparamspecs.h"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
static GObjectClass *parent_class = NULL;
GQuark priv_gst_controller_key;
/* property ids */
enum
@ -101,6 +101,20 @@ struct _GstControllerPrivate
/* helper */
/*
* 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;
#define GST_CONTROLLED_PROPERTY(obj) ((GstControlledProperty *)(obj))
/*
* gst_controlled_property_new:
* @object: for which object the controlled property should be set up
@ -112,7 +126,7 @@ struct _GstControllerPrivate
* Returns: a freshly allocated structure or %NULL
*/
static GstControlledProperty *
gst_controlled_property_new (GObject * object, const gchar * name)
gst_controlled_property_new (GstObject * object, const gchar * name)
{
GstControlledProperty *prop = NULL;
GParamSpec *pspec;
@ -191,54 +205,56 @@ gst_controller_find_controlled_property (GstController * self,
/*
* gst_controller_add_property:
* @self: the controller object or %NULL if none yet exists
* @object: object to bind the property
* @self: the controller object
* @name: name of projecty in @object
* @ref_existing: pointer to flag that tracks if we need to ref an existing
* controller still
*
* Creates a new #GstControlledProperty if there is none for property @name yet.
* In case this is the first controlled propery, it creates the controller as
* well.
*
* Returns: a newly created controller object or reffed existing one with the
* given property bound.
* Returns: %TRUE if the property has been added to the controller
*/
static GstController *
gst_controller_add_property (GstController * self, GObject * object,
const gchar * name, gboolean * ref_existing)
static gboolean
gst_controller_add_property (GstController * self, const gchar * name)
{
gboolean res = TRUE;
/* test if this property isn't yet controlled */
if (!self || !gst_controller_find_controlled_property (self, name)) {
if (!gst_controller_find_controlled_property (self, name)) {
GstControlledProperty *prop;
/* 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_newv (GST_TYPE_CONTROLLER, 0, NULL);
self->object = g_object_ref (object);
/* store the controller */
g_object_set_qdata (object, priv_gst_controller_key, self);
*ref_existing = FALSE;
} else {
/* only want one single _ref(), even for multiple properties */
if (*ref_existing) {
g_object_ref (self);
*ref_existing = FALSE;
GST_INFO ("returning existing controller");
}
}
/* create GstControlledProperty and add to self->properties list */
if ((prop = gst_controlled_property_new (self->object, name)))
self->properties = g_list_prepend (self->properties, prop);
}
else
res = FALSE;
} else {
GST_WARNING ("trying to control property %s again", name);
if (*ref_existing) {
g_object_ref (self);
*ref_existing = FALSE;
}
}
return self;
return res;
}
/*
* gst_controller_remove_property:
* @self: the controller 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_controller_remove_property (GstController * self, const gchar * name)
{
gboolean res = TRUE;
GstControlledProperty *prop;
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;
}
return res;
}
/* methods */
@ -253,25 +269,24 @@ gst_controller_add_property (GstController * self, GObject * object,
* Returns: the new controller.
*/
GstController *
gst_controller_new_valist (GObject * object, va_list var_args)
gst_controller_new_valist (GstObject * object, va_list var_args)
{
GstController *self;
gboolean ref_existing = TRUE;
gchar *name;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
GST_INFO ("setting up a new controller");
self = g_object_get_qdata (object, priv_gst_controller_key);
self = g_object_newv (GST_TYPE_CONTROLLER, 0, NULL);
self->object = g_object_ref (object);
/* create GstControlledProperty for each property */
while ((name = va_arg (var_args, gchar *))) {
self = gst_controller_add_property (self, object, name, &ref_existing);
gst_controller_add_property (self, name);
}
va_end (var_args);
if (self)
GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
return self;
}
@ -288,10 +303,9 @@ gst_controller_new_valist (GObject * object, va_list var_args)
* Returns: the new controller.
*/
GstController *
gst_controller_new_list (GObject * object, GList * list)
gst_controller_new_list (GstObject * object, GList * list)
{
GstController *self;
gboolean ref_existing = TRUE;
gchar *name;
GList *node;
@ -299,15 +313,15 @@ gst_controller_new_list (GObject * object, GList * list)
GST_INFO ("setting up a new controller");
self = g_object_get_qdata (object, priv_gst_controller_key);
self = g_object_newv (GST_TYPE_CONTROLLER, 0, NULL);
self->object = g_object_ref (object);
/* create GstControlledProperty for each property */
for (node = list; node; node = g_list_next (node)) {
name = (gchar *) node->data;
self = gst_controller_add_property (self, object, name, &ref_existing);
gst_controller_add_property (self, name);
}
if (self)
GST_INFO ("controller->ref_count=%d", G_OBJECT (self)->ref_count);
return self;
}
@ -321,7 +335,7 @@ gst_controller_new_list (GObject * object, GList * list)
* Returns: the new controller.
*/
GstController *
gst_controller_new (GObject * object, ...)
gst_controller_new (GstObject * object, ...)
{
GstController *self;
va_list var_args;
@ -335,6 +349,63 @@ gst_controller_new (GObject * object, ...)
return self;
}
// FIXME: docs
gboolean
gst_controller_add_properties_valist (GstController * self, va_list var_args)
{
gboolean res = TRUE;
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);
res &= gst_controller_add_property (self, name);
g_mutex_unlock (self->lock);
}
return res;
}
// FIXME: docs
gboolean
gst_controller_add_properties_list (GstController * self, GList * list)
{
gboolean res = TRUE;
gchar *name;
GList *tmp;
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
for (tmp = list; tmp; tmp = g_list_next (tmp)) {
name = (gchar *) tmp->data;
/* find the property in the properties list of the controller, remove and free it */
g_mutex_lock (self->lock);
res &= gst_controller_add_property (self, name);
g_mutex_unlock (self->lock);
}
return res;
}
// FIXME: docs
gboolean
gst_controller_add_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_add_properties_valist (self, var_args);
va_end (var_args);
return res;
}
/**
* gst_controller_remove_properties_valist:
* @self: the controller object from which some properties should be removed
@ -348,7 +419,6 @@ 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);
@ -356,13 +426,7 @@ gst_controller_remove_properties_valist (GstController * self, va_list var_args)
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;
}
res &= gst_controller_remove_property (self, name);
g_mutex_unlock (self->lock);
}
@ -385,7 +449,6 @@ gboolean
gst_controller_remove_properties_list (GstController * self, GList * list)
{
gboolean res = TRUE;
GstControlledProperty *prop;
gchar *name;
GList *tmp;
@ -396,13 +459,7 @@ gst_controller_remove_properties_list (GstController * self, GList * list)
/* 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;
}
res &= gst_controller_remove_property (self, name);
g_mutex_unlock (self->lock);
}
@ -598,7 +655,7 @@ gst_controller_get (GstController * self, const gchar * property_name,
val = NULL;
}
} else {
g_object_get_property (self->object, prop->name, val);
g_object_get_property ((GObject *) self->object, prop->name, val);
}
}
g_mutex_unlock (self->lock);
@ -666,7 +723,7 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
GST_LOG ("sync_values");
g_mutex_lock (self->lock);
g_object_freeze_notify (self->object);
g_object_freeze_notify ((GObject *) self->object);
/* go over the controlled properties of the controller */
for (node = self->properties; node; node = g_list_next (node)) {
prop = node->data;
@ -688,7 +745,7 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
*/
if ((timestamp < self->priv->last_sync) ||
gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
g_object_set_property (self->object, prop->name, &value);
g_object_set_property ((GObject *) self->object, prop->name, &value);
g_value_copy (&value, &prop->last_value);
}
} else {
@ -698,7 +755,7 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
ret &= val_ret;
}
self->priv->last_sync = timestamp;
g_object_thaw_notify (self->object);
g_object_thaw_notify ((GObject *) self->object);
g_mutex_unlock (self->lock);
@ -871,8 +928,6 @@ _gst_controller_dispose (GObject * object)
self->properties = NULL;
}
/* remove controller from object's qdata list */
g_object_set_qdata (self->object, priv_gst_controller_key, NULL);
g_object_unref (self->object);
self->object = NULL;
g_mutex_unlock (self->lock);
@ -919,8 +974,6 @@ _gst_controller_class_init (GstControllerClass * klass)
gobject_class->dispose = _gst_controller_dispose;
gobject_class->finalize = _gst_controller_finalize;
priv_gst_controller_key = g_quark_from_static_string ("gst::controller");
/* register properties */
g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
g_param_spec_uint64 ("control-rate",
@ -929,8 +982,8 @@ _gst_controller_class_init (GstControllerClass * klass)
1, G_MAXUINT, 100 * GST_MSECOND,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* register signals */
/* set defaults for overridable methods */
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontroller", 0,
"dynamic parameter control for gstreamer elements");
}
GType

View file

@ -1,8 +1,9 @@
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
* Copyright (C) 2005 Stefan Kost <ensonic at users dot sf dot net>
* 2011 Stefan Sauer <ensonic at users dot sf dot net>
*
* gst-controller.h: dynamic parameter control subsystem
* 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
@ -23,15 +24,16 @@
#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/gst.h>
#include <gst/controller/gstcontrolsource.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/gstobject.h>
#include <gst/gstcontrolsource.h>
G_BEGIN_DECLS
@ -60,7 +62,7 @@ struct _GstController
GList *properties; /* List of GstControlledProperty */
GMutex *lock; /* Secure property access, elements will access from threads */
GObject *object; /* the object we control */
GstObject *object; /* the object we control */
/*< private >*/
GstControllerPrivate *priv;
@ -79,14 +81,16 @@ GType gst_controller_get_type (void);
/* GstController functions */
GstController *gst_controller_new_valist (GObject * object, va_list var_args);
GstController *gst_controller_new_list (GObject * object, GList *list);
GstController *gst_controller_new (GObject * object, ...) G_GNUC_NULL_TERMINATED;
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_remove_properties_valist (GstController * self,
va_list var_args);
gboolean gst_controller_remove_properties_list (GstController * self,
GList *list);
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;
void gst_controller_set_disabled (GstController *self, gboolean disabled);
@ -105,32 +109,6 @@ gboolean gst_controller_get_value_arrays (GstController * self,
gboolean gst_controller_get_value_array (GstController * self,
GstClockTime timestamp, GstValueArray * value_array);
/* GObject convenience functions */
GstController *gst_object_control_properties (GObject * object, ...) G_GNUC_NULL_TERMINATED;
gboolean gst_object_uncontrol_properties (GObject * object, ...) G_GNUC_NULL_TERMINATED;
GstController *gst_object_get_controller (GObject * object);
gboolean gst_object_set_controller (GObject * object, GstController * controller);
GstClockTime gst_object_suggest_next_sync (GObject * object);
gboolean gst_object_sync_values (GObject * object, GstClockTime timestamp);
gboolean gst_object_set_control_source (GObject *object, const gchar * property_name, GstControlSource *csource);
GstControlSource * gst_object_get_control_source (GObject *object, const gchar * property_name);
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);
GstClockTime gst_object_get_control_rate (GObject * object);
void gst_object_set_control_rate (GObject * object, GstClockTime control_rate);
/* lib init/done */
gboolean gst_controller_init (int * argc, char ***argv);
G_END_DECLS

View file

@ -41,6 +41,8 @@
*
*/
#include "gst_private.h"
#include <glib-object.h>
#include <gst/gst.h>

View file

@ -23,8 +23,11 @@
#ifndef __GST_CONTROL_SOURCE_H__
#define __GST_CONTROL_SOURCE_H__
#include <gst/gstconfig.h>
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/gstclock.h>
G_BEGIN_DECLS

View file

@ -88,6 +88,7 @@
#include "gstobject.h"
#include "gstmarshal.h"
#include "gstcontroller.h"
#include "gstinfo.h"
#include "gstutils.h"
@ -342,6 +343,7 @@ gst_object_replace (GstObject ** oldobj, GstObject * newobj)
static void
gst_object_dispose (GObject * object)
{
GstObject *self = (GstObject *) object;
GstObject *parent;
GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
@ -352,6 +354,11 @@ 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;
}
((GObjectClass *) gst_object_parent_class)->dispose (object);
return;
@ -950,3 +957,299 @@ gst_object_get_path_string (GstObject * object)
return path;
}
/* controller functions */
/**
* gst_object_control_properties:
* @object: the object of which some properties should be controlled
* @...: %NULL terminated list of property names that should be controlled
*
* Creates a GstController that allows you to dynamically control one, or more,
* GObject properties. If the given GstObject already has a GstController,
* it adds the given properties to the existing
* controller and returns that controller.
*
* Returns: %TRUE if the properties have been made controllable.
*/
gboolean
gst_object_control_properties (GstObject * object, ...)
{
gboolean res = FALSE;
va_list var_args;
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
va_start (var_args, object);
if (object->ctrl) {
object->ctrl = gst_controller_new_valist (object, var_args);
res = (object->ctrl != NULL);
} else {
res = gst_controller_add_properties_valist ((GstController *) object->ctrl,
var_args);
}
va_end (var_args);
return res;
}
/**
* 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
*
* 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
*/
gboolean
gst_object_uncontrol_properties (GstObject * object, ...)
{
gboolean res = FALSE;
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);
}
return (res);
}
/**
* gst_object_suggest_next_sync:
* @object: the object that has controlled properties
*
* Convenience function for GObject
*
* Returns: same thing as gst_controller_suggest_next_sync()
*/
GstClockTime
gst_object_suggest_next_sync (GstObject * object)
{
g_return_val_if_fail (GST_IS_OBJECT (object), GST_CLOCK_TIME_NONE);
if (object->ctrl)
return gst_controller_suggest_next_sync ((GstController *) object->ctrl);
return (GST_CLOCK_TIME_NONE);
}
/**
* gst_object_sync_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_sync_values()
*/
gboolean
gst_object_sync_values (GstObject * object, GstClockTime timestamp)
{
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
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);
}
// FIXME: docs
void
gst_object_set_automation_disabled (GstObject * object, gboolean disabled)
{
g_return_if_fail (GST_IS_OBJECT (object));
if (object->ctrl)
gst_controller_set_disabled (object->ctrl, disabled);
}
// FIXME: docs
void
gst_object_set_property_automation_disabled (GstObject * object,
const gchar * property_name, gboolean disabled)
{
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_set_control_source:
* @object: the controller object
* @property_name: name of the property for which the #GstControlSource should be set
* @csource: the #GstControlSource that should be used for the property
*
* Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
* for this property it will be unreferenced.
*
* Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
* couldn't be bound to the property, %TRUE if everything worked as expected.
*/
gboolean
gst_object_set_control_source (GstObject * object, const gchar * property_name,
GstControlSource * csource)
{
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);
if (object->ctrl)
return gst_controller_set_control_source ((GstController *) object->ctrl,
property_name, csource);
return FALSE;
}
/**
* gst_object_get_control_source:
* @object: the object
* @property_name: name of the property for which the #GstControlSource should be get
*
* Gets the corresponding #GstControlSource for the property. This should be unreferenced
* again after use.
*
* Returns: (transfer full): the #GstControlSource for @property_name or NULL if
* the property is not controlled by this controller or no #GstControlSource was
* assigned yet.
*/
GstControlSource *
gst_object_get_control_source (GstObject * object, const gchar * property_name)
{
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;
}
// FIXME: docs
GValue *
gst_object_get_value (GstObject * object, const gchar * property_name,
GstClockTime timestamp)
{
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 (object->ctrl, property_name, timestamp);
return NULL;
}
/**
* 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
*/
gboolean
gst_object_get_value_arrays (GstObject * object, GstClockTime timestamp,
GSList * value_arrays)
{
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if (object->ctrl)
return gst_controller_get_value_arrays ((GstController *) object->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
*/
gboolean
gst_object_get_value_array (GstObject * object, GstClockTime timestamp,
GstValueArray * value_array)
{
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if (object->ctrl)
return gst_controller_get_value_array ((GstController *) object->ctrl,
timestamp, value_array);
return (FALSE);
}
/**
* gst_object_get_control_rate:
* @object: the object that has controlled properties
*
* Obtain the control-rate for this @object. Audio processing #GstElement
* objects will use this rate to sub-divide their processing loop and call
* gst_object_sync_values() inbetween. The length of the processing segment
* should be up to @control-rate nanoseconds.
*
* If the @object is not under property control, this will return
* %GST_CLOCK_TIME_NONE. This allows the element to avoid the sub-dividing.
*
* The control-rate is not expected to change if the element is in
* %GST_STATE_PAUSED or %GST_STATE_PLAYING.
*
* Returns: the control rate in nanoseconds
*/
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);
}
/**
* gst_object_set_control_rate:
* @object: the object that has controlled properties
* @control_rate: the new control-rate in nanoseconds.
*
* Change the control-rate for this @object. Audio processing #GstElement
* objects will use this rate to sub-divide their processing loop and call
* gst_object_sync_values() inbetween. The length of the processing segment
* should be up to @control-rate nanoseconds.
*
* The control-rate should not change if the element is in %GST_STATE_PAUSED or
* %GST_STATE_PLAYING.
*/
void
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);
}

View file

@ -149,7 +149,6 @@ typedef enum
*/
#define GST_OBJECT_FLAG_UNSET(obj,flag) (GST_OBJECT_FLAGS (obj) &= ~(flag))
typedef struct _GstObject GstObject;
typedef struct _GstObjectClass GstObjectClass;
@ -172,6 +171,7 @@ struct _GstObject {
guint32 flags;
/*< private >*/
gpointer ctrl; /* time controlled properties */
gpointer _gst_reserved;
};
@ -228,6 +228,29 @@ gchar * gst_object_get_path_string (GstObject *object);
/* misc utils */
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;
gboolean gst_object_uncontrol_properties (GstObject * object, ...) G_GNUC_NULL_TERMINATED;
GstClockTime gst_object_suggest_next_sync (GstObject * object);
gboolean gst_object_sync_values (GstObject * object, GstClockTime timestamp);
void gst_object_set_automation_disabled (GstObject *object, gboolean disabled); // NEW was gst_controller_set_disabled
void gst_object_set_property_automation_disabled (GstObject *object, const gchar * property_name, gboolean disabled); // NEW was gst_controller_set_property_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);
GValue *gst_object_get_value (GstObject * object, const gchar * property_name, GstClockTime timestamp); // NEW was gst_controller_get
gboolean gst_object_get_value_arrays (GstObject * object, GstClockTime timestamp, GSList * value_arrays);
gboolean gst_object_get_value_array (GstObject * object, GstClockTime timestamp, GstValueArray * value_array);
GstClockTime gst_object_get_control_rate (GstObject * object);
void gst_object_set_control_rate (GstObject * object, GstClockTime control_rate);
G_END_DECLS
#endif /* __GST_OBJECT_H__ */

View file

@ -2,22 +2,15 @@ lib_LTLIBRARIES = libgstcontroller-@GST_MAJORMINOR@.la
libgstcontroller_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/controller
libgstcontroller_@GST_MAJORMINOR@_include_HEADERS = \
gstcontroller.h \
gstcontrolsource.h \
gstinterpolationcontrolsource.h \
gstlfocontrolsource.h
noinst_HEADERS = \
gstcontrollerprivate.h \
gstinterpolationcontrolsourceprivate.h \
gstlfocontrolsourceprivate.h
libgstcontroller_@GST_MAJORMINOR@_la_SOURCES = \
lib.c \
gstcontroller.c \
gstinterpolation.c \
gsthelper.c \
gstcontrolsource.c \
gstinterpolationcontrolsource.c \
gstlfocontrolsource.c

View file

@ -1,53 +0,0 @@
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
*
* gstcontrollerprivate.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_PRIVATE_H__
#define __GST_CONTROLLER_PRIVATE_H__
#include <glib.h>
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/controller/gstcontroller.h>
#include <gst/controller/gstcontrolsource.h>
G_BEGIN_DECLS
/**
* 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;
#define GST_CONTROLLED_PROPERTY(obj) ((GstControlledProperty *)(obj))
extern GQuark priv_gst_controller_key;
G_END_DECLS
#endif /* __GST_CONTROLLER_PRIVATE_H__ */

View file

@ -1,357 +0,0 @@
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
*
* gsthelper.c: GObject convenience 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 convenience methods for using dynamic properties
* @see_also: #GstController
*
* These methods allow to use some #GstController functionality directly from
* the #GObject class.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdarg.h>
#include "gstcontrollerprivate.h"
#include "gstcontroller.h"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
/**
* 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: (transfer full): 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.
*/
GstController *
gst_object_control_properties (GObject * object, ...)
{
GstController *ctrl;
va_list var_args;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
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
*/
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, priv_gst_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
*
* Gets the controller for the given GObject
*
* Returns: (transfer full): the controller handling some of the given element's
* properties, %NULL if no controller
*/
/* FIXME 0.11: This should return a new reference */
GstController *
gst_object_get_controller (GObject * object)
{
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
return (g_object_get_qdata (object, priv_gst_controller_key));
}
/**
* gst_object_set_controller:
* @object: the object that should get the controller
* @controller: (transfer none): the controller object to plug in
*
* Sets the controller on the given GObject
*
* Returns: %FALSE if the GObject already has an controller, %TRUE otherwise
*/
/* FIXME 0.11: This should increase the refcount before storing */
gboolean
gst_object_set_controller (GObject * object, GstController * controller)
{
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (controller, FALSE);
if (!g_object_get_qdata (object, priv_gst_controller_key)) {
g_object_set_qdata (object, priv_gst_controller_key, controller);
return (TRUE);
}
return (FALSE);
}
/**
* gst_object_suggest_next_sync:
* @object: the object that has controlled properties
*
* Convenience function for GObject
*
* Returns: same thing as gst_controller_suggest_next_sync()
*/
GstClockTime
gst_object_suggest_next_sync (GObject * object)
{
GstController *ctrl = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), GST_CLOCK_TIME_NONE);
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
return gst_controller_suggest_next_sync (ctrl);
}
return (GST_CLOCK_TIME_NONE);
}
/**
* gst_object_sync_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_sync_values()
*/
gboolean
gst_object_sync_values (GObject * object, GstClockTime timestamp)
{
GstController *ctrl = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
return gst_controller_sync_values (ctrl, timestamp);
}
/* this is no failure, its called by elements regardless if there is a
* controller assigned or not
*/
return (TRUE);
}
/**
* gst_object_set_control_source:
* @object: the controller object
* @property_name: name of the property for which the #GstControlSource should be set
* @csource: the #GstControlSource that should be used for the property
*
* Sets the #GstControlSource for @property_name. If there already was a #GstControlSource
* for this property it will be unreferenced.
*
* Returns: %FALSE if the given property isn't handled by the controller or the new #GstControlSource
* couldn't be bound to the property, %TRUE if everything worked as expected.
*/
gboolean
gst_object_set_control_source (GObject * object, const gchar * property_name,
GstControlSource * csource)
{
GstController *ctrl = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_IS_CONTROL_SOURCE (csource), FALSE);
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
return gst_controller_set_control_source (ctrl, property_name, csource);
}
return FALSE;
}
/**
* gst_object_get_control_source:
* @object: the object
* @property_name: name of the property for which the #GstControlSource should be get
*
* Gets the corresponding #GstControlSource for the property. This should be unreferenced
* again after use.
*
* Returns: (transfer full): the #GstControlSource for @property_name or NULL if
* the property is not controlled by this controller or no #GstControlSource was
* assigned yet.
*/
GstControlSource *
gst_object_get_control_source (GObject * object, const gchar * property_name)
{
GstController *ctrl = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
return gst_controller_get_control_source (ctrl, property_name);
}
return NULL;
}
/**
* 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
*/
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, priv_gst_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
*/
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, priv_gst_controller_key))) {
return gst_controller_get_value_array (ctrl, timestamp, value_array);
}
return (FALSE);
}
/**
* gst_object_get_control_rate:
* @object: the object that has controlled properties
*
* Obtain the control-rate for this @object. Audio processing #GstElement
* objects will use this rate to sub-divide their processing loop and call
* gst_object_sync_values() inbetween. The length of the processing segment
* should be up to @control-rate nanoseconds.
*
* If the @object is not under property control, this will return
* %GST_CLOCK_TIME_NONE. This allows the element to avoid the sub-dividing.
*
* The control-rate is not expected to change if the element is in
* %GST_STATE_PAUSED or %GST_STATE_PLAYING.
*
* Returns: the control rate in nanoseconds
*/
GstClockTime
gst_object_get_control_rate (GObject * object)
{
GstController *ctrl;
GstClockTime control_rate = GST_CLOCK_TIME_NONE;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
g_object_get (ctrl, "control-rate", &control_rate, NULL);
}
return (control_rate);
}
/**
* gst_object_set_control_rate:
* @object: the object that has controlled properties
* @control_rate: the new control-rate in nanoseconds.
*
* Change the control-rate for this @object. Audio processing #GstElement
* objects will use this rate to sub-divide their processing loop and call
* gst_object_sync_values() inbetween. The length of the processing segment
* should be up to @control-rate nanoseconds.
*
* The control-rate should not change if the element is in %GST_STATE_PAUSED or
* %GST_STATE_PLAYING.
*/
void
gst_object_set_control_rate (GObject * object, GstClockTime control_rate)
{
GstController *ctrl;
g_return_if_fail (G_IS_OBJECT (object));
if ((ctrl = g_object_get_qdata (object, priv_gst_controller_key))) {
g_object_set (ctrl, "control-rate", control_rate, NULL);
}
}

View file

@ -40,15 +40,17 @@
#include <glib-object.h>
#include <gst/gst.h>
#include "gstcontrolsource.h"
#include "gstinterpolationcontrolsource.h"
#include "gstinterpolationcontrolsourceprivate.h"
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
G_DEFINE_TYPE (GstInterpolationControlSource, gst_interpolation_control_source,
GST_TYPE_CONTROL_SOURCE);
#define _do_init \
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "interpolation control source", 0, "timeline value interpolating control source")
G_DEFINE_TYPE_WITH_CODE (GstInterpolationControlSource,
gst_interpolation_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
static GObjectClass *parent_class = NULL;

View file

@ -27,7 +27,7 @@
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/controller/gstcontrolsource.h>
#include <gst/gstcontrolsource.h>
G_BEGIN_DECLS

View file

@ -38,13 +38,17 @@
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/gstcontrolsource.h>
#include "gstcontrolsource.h"
#include "gstlfocontrolsource.h"
#include "gstlfocontrolsourceprivate.h"
#include <gst/math-compat.h>
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define EMPTY(x) (x)
/* FIXME: as % in C is not the modulo operator we need here for
@ -603,8 +607,11 @@ gst_lfo_waveform_get_type (void)
return (GType) gtype;
}
G_DEFINE_TYPE (GstLFOControlSource, gst_lfo_control_source,
GST_TYPE_CONTROL_SOURCE);
#define _do_init \
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "lfo control source", 0, "low frequency oscillator control source")
G_DEFINE_TYPE_WITH_CODE (GstLFOControlSource, gst_lfo_control_source,
GST_TYPE_CONTROL_SOURCE, _do_init);
static GObjectClass *parent_class = NULL;

View file

@ -27,8 +27,6 @@
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/controller/gstcontrolsource.h>
G_BEGIN_DECLS
#define GST_TYPE_LFO_CONTROL_SOURCE \

View file

@ -1,58 +0,0 @@
/* GStreamer
*
* Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
*
* lib.c: controller subsystem init
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/gst.h>
#include <gst/controller/gstcontroller.h>
/* library initialisation */
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
/**
* gst_controller_init:
* @argc: pointer to the commandline argument count
* @argv: pointer to the commandline argument values
*
* Initializes the use of the controller library. Suggested to be called right
* after gst_init().
*
* Returns: the %TRUE for success.
*/
gboolean
gst_controller_init (int *argc, char ***argv)
{
static gboolean _gst_controller_initialized = FALSE;
if (_gst_controller_initialized)
return TRUE;
_gst_controller_initialized = TRUE;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstcontroller", 0,
"dynamic parameter control for gstreamer elements");
return TRUE;
}