--- a/gstreamer_core/libs/gst/controller/gstcontroller.c Fri Mar 19 09:35:09 2010 +0200
+++ b/gstreamer_core/libs/gst/controller/gstcontroller.c Fri Apr 16 15:15:52 2010 +0300
@@ -81,7 +81,6 @@
#ifdef __SYMBIAN32__
#include <glib_global.h>
#include <gobject_global.h>
-
#endif
#define GST_CAT_DEFAULT controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
@@ -151,6 +150,8 @@
prop->pspec = pspec;
prop->name = pspec->name;
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),
@@ -171,6 +172,7 @@
{
if (prop->csource)
g_object_unref (prop->csource);
+ g_value_unset (&prop->last_value);
g_free (prop);
}
@@ -203,6 +205,58 @@
return NULL;
}
+/*
+ * gst_controller_add_property:
+ * @self: the controller object or %NULL if none yet exists
+ * @object: object to bind the property
+ * @name: name of projecty in @object
+ * @ref_existing: pointer to flag that tracks if we need to ref an existng
+ * 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.
+ */
+static GstController *
+gst_controller_add_property (GstController * self, GObject * object,
+ gchar * name, gboolean * ref_existing)
+{
+ /* test if this property isn't yet controlled */
+ if (!self || !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_new (GST_TYPE_CONTROLLER, 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");
+ }
+ }
+ self->properties = g_list_prepend (self->properties, prop);
+ }
+ } else {
+ GST_WARNING ("trying to control property again");
+ if (*ref_existing) {
+ g_object_ref (self);
+ *ref_existing = FALSE;
+ }
+ }
+ return self;
+}
+
/* methods */
/**
@@ -222,7 +276,6 @@
gst_controller_new_valist (GObject * object, va_list var_args)
{
GstController *self;
- GstControlledProperty *prop;
gboolean ref_existing = TRUE;
gchar *name;
@@ -233,34 +286,7 @@
self = g_object_get_qdata (object, priv_gst_controller_key);
/* create GstControlledProperty for each property */
while ((name = va_arg (var_args, gchar *))) {
- /* test if this property isn't yet controlled */
- if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
- /* create GstControlledProperty and add to self->propeties List */
- if ((prop = gst_controlled_property_new (object, name))) {
- /* if we don't have a controller object yet, now is the time to create one */
- if (!self) {
- self = g_object_new (GST_TYPE_CONTROLLER, NULL);
- self->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");
- }
- }
- self->properties = g_list_prepend (self->properties, prop);
- }
- } else {
- GST_WARNING ("trying to control property again");
- if (ref_existing) {
- g_object_ref (self);
- ref_existing = FALSE;
- }
- }
+ self = gst_controller_add_property (self, object, name, &ref_existing);
}
va_end (var_args);
@@ -286,7 +312,6 @@
gst_controller_new_list (GObject * object, GList * list)
{
GstController *self;
- GstControlledProperty *prop;
gboolean ref_existing = TRUE;
gchar *name;
GList *node;
@@ -299,34 +324,7 @@
/* create GstControlledProperty for each property */
for (node = list; node; node = g_list_next (node)) {
name = (gchar *) node->data;
- /* test if this property isn't yet controlled */
- if (!self || !(prop = gst_controller_find_controlled_property (self, name))) {
- /* create GstControlledProperty and add to self->propeties List */
- if ((prop = gst_controlled_property_new (object, name))) {
- /* if we don't have a controller object yet, now is the time to create one */
- if (!self) {
- self = g_object_new (GST_TYPE_CONTROLLER, NULL);
- self->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");
- }
- }
- self->properties = g_list_prepend (self->properties, prop);
- }
- } else {
- GST_WARNING ("trying to control property again");
- if (ref_existing) {
- g_object_ref (self);
- ref_existing = FALSE;
- }
- }
+ self = gst_controller_add_property (self, object, name, &ref_existing);
}
if (self)
@@ -604,6 +602,9 @@
GstControlledProperty *prop;
GstControlSource *ret = NULL;
+ g_return_val_if_fail (GST_IS_CONTROLLER (self), NULL);
+ g_return_val_if_fail (property_name, NULL);
+
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
ret = prop->csource;
@@ -625,7 +626,8 @@
* Gets the value for the given controller-handled property at the requested
* time.
*
- * Returns: the GValue of the property at the given time, or %NULL if the property isn't handled by the controller
+ * Returns: the GValue of the property at the given time, or %NULL if the
+ * property isn't handled by the controller
*/
#ifdef __SYMBIAN32__
EXPORT_C
@@ -692,7 +694,9 @@
g_mutex_lock (self->lock);
/* TODO: Implement more logic, depending on interpolation mode
- * and control points */
+ * and control points
+ * FIXME: we need playback direction
+ */
ret = self->priv->last_sync + self->priv->control_rate;
g_mutex_unlock (self->lock);
@@ -708,6 +712,9 @@
* Sets the properties of the element, according to the controller that (maybe)
* handles them and for the given timestamp.
*
+ * 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
*/
@@ -720,7 +727,8 @@
{
GstControlledProperty *prop;
GList *node;
- gboolean ret = FALSE;
+ gboolean ret = TRUE, val_ret;
+ GValue value = { 0, };
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
@@ -728,25 +736,39 @@
GST_LOG ("sync_values");
g_mutex_lock (self->lock);
+ g_object_freeze_notify (self->object);
/* go over the controlled properties of the controller */
for (node = self->properties; node; node = g_list_next (node)) {
- GValue value = { 0, };
prop = node->data;
- GST_DEBUG (" property '%s' at ts=%" G_GUINT64_FORMAT, prop->name,
- timestamp);
-
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));
- ret = gst_control_source_get_value (prop->csource, timestamp, &value);
- if (ret) {
- g_object_set_property (self->object, prop->name, &value);
- g_value_unset (&value);
+ 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 < self->priv->last_sync) ||
+ gst_value_compare (&value, &prop->last_value) != GST_VALUE_EQUAL) {
+ g_object_set_property (self->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;
}
self->priv->last_sync = timestamp;
+ g_object_thaw_notify (self->object);
g_mutex_unlock (self->lock);
@@ -982,7 +1004,8 @@
g_param_spec_uint64 ("control-rate",
"control rate",
"Controlled properties will be updated at least every control-rate nanoseconds",
- 1, G_MAXUINT, 100 * GST_MSECOND, G_PARAM_READWRITE));
+ 1, G_MAXUINT, 100 * GST_MSECOND,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* register signals */
/* set defaults for overridable methods */
@@ -995,9 +1018,10 @@
GType
gst_controller_get_type (void)
{
- static GType type = 0;
+ static volatile gsize type = 0;
- if (type == 0) {
+ if (g_once_init_enter (&type)) {
+ GType _type;
static const GTypeInfo info = {
sizeof (GstControllerClass),
NULL, /* base_init */
@@ -1010,7 +1034,8 @@
(GInstanceInitFunc) _gst_controller_init, /* instance_init */
NULL /* value_table */
};
- type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
+ _type = g_type_register_static (G_TYPE_OBJECT, "GstController", &info, 0);
+ g_once_init_leave (&type, _type);
}
return type;
}