reviewed by: Stefan Kost <ensonic@users.sf.net>
+ * libs/gst/controller/gstcontroller.c:
+ (gst_controller_suggest_next_sync), (gst_controller_sync_values),
+ (_gst_controller_get_property), (_gst_controller_set_property),
+ (_gst_controller_init), (_gst_controller_class_init):
+ * libs/gst/controller/gstcontroller.h:
+ * libs/gst/controller/gsthelper.c: (gst_object_suggest_next_sync),
+ (gst_object_get_control_rate), (gst_object_set_control_rate):
+ API: gst_controller_suggest_next_sync(), gst_object_suggest_next_sync()
+ Add API that provides sync suggestion timestamps for elements that
+ call gst_object_sync_values() from which those elements can subdivide
+ their processing loop to get the best results for the controlled
+ properties. For now it just suggests last_sync + control_rate as
+ new timestamp but this will be improved in the future.
+
+ While doing that change the control-rate property to a GstClockTime
+ from guint and change it's meaning from samples to nanoseconds as
+ the GstController doesn't know anything about sampling rate. Strictly
+ speaking this breaks ABI but as the control-rate property didn't do
+ anything in the past and as such couldn't be used this should be no
+ problem.
+
+2007-05-17 Sebastian Dröge <slomo@circular-chaos.org>
+
+ reviewed by: Stefan Kost <ensonic@users.sf.net>
+
* libs/gst/controller/gstcontroller.c: (gst_controller_unset),
(gst_controller_unset_all):
* libs/gst/controller/gstcontrollerprivate.h:
struct _GstControllerPrivate
{
- guint control_rate;
+ GstClockTime control_rate;
+ GstClockTime last_sync;
};
/* imports from gst-interpolation.c */
}
/**
+ * gst_controller_suggest_next_sync:
+ * @self: the controller that handles the values
+ *
+ * Returns a suggestion for timestamps where buffers should be split
+ * to get best controller results.
+ *
+ * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
+ * if no control-rate was set.
+ *
+ * Since: 0.10.13
+ */
+GstClockTime
+gst_controller_suggest_next_sync (GstController * self)
+{
+ GstClockTime ret;
+
+ g_return_val_if_fail (GST_IS_CONTROLLER (self), GST_CLOCK_TIME_NONE);
+ g_return_val_if_fail (self->priv->control_rate != GST_CLOCK_TIME_NONE,
+ GST_CLOCK_TIME_NONE);
+
+ g_mutex_lock (self->lock);
+
+ /* TODO: Implement more logic, depending on interpolation mode
+ * and control points */
+ ret = self->priv->last_sync + self->priv->control_rate;
+
+ g_mutex_unlock (self->lock);
+
+ return ret;
+}
+
+/**
* gst_controller_sync_values:
* @self: the controller that handles the values
* @timestamp: the time that should be processed
GstControlledProperty *prop;
GList *node;
GValue *value;
- gboolean live;
+ gboolean live = FALSE;
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
g_object_set_property (self->object, prop->name, value);
}
}
+ if (G_LIKELY (!live))
+ self->priv->last_sync = timestamp;
+
g_mutex_unlock (self->lock);
/* TODO what can here go wrong, to return FALSE ?
BilboEd : Nothing I guess, as long as all the checks are made when creating the controller,
(ret == GST_STATE_CHANGE_ASYNC &&
(p_state == GST_STATE_NULL || p_state == GST_STATE_READY))) {
*/
- g_value_set_uint (value, self->priv->control_rate);
+ g_value_set_uint64 (value, self->priv->control_rate);
/*
}
else {
switch (property_id) {
case PROP_CONTROL_RATE:{
- self->priv->control_rate = g_value_get_uint (value);
+ self->priv->control_rate = g_value_get_uint64 (value);
}
break;
default:{
self->priv =
G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_CONTROLLER,
GstControllerPrivate);
+ self->priv->last_sync = GST_CLOCK_TIME_NONE;
+ self->priv->control_rate = 100 * GST_MSECOND;
}
static void
/* register properties */
g_object_class_install_property (gobject_class, PROP_CONTROL_RATE,
- g_param_spec_uint ("control-rate",
+ g_param_spec_uint64 ("control-rate",
"control rate",
- "Controlled properties will be updated this many times per second",
- 1, G_MAXUINT, 10, G_PARAM_READWRITE));
+ "Controlled properties will be updated at least every control-rate nanoseconds",
+ 1, G_MAXUINT, 100 * GST_MSECOND, G_PARAM_READWRITE));
/* register signals */
/* set defaults for overridable methods */
const GList *gst_controller_get_all (GstController * self,
gchar * property_name);
-
+GstClockTime gst_controller_suggest_next_sync (GstController *self);
gboolean gst_controller_sync_values (GstController * self,
GstClockTime timestamp);
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_get_value_arrays (GObject * object,
gboolean gst_object_get_value_array (GObject * object,
GstClockTime timestamp, GstValueArray * value_array);
-guint gst_object_get_control_rate (GObject * object);
-void gst_object_set_control_rate (GObject * object, guint control_rate);
+GstClockTime gst_object_get_control_rate (GObject * object);
+void gst_object_set_control_rate (GObject * object, GstClockTime control_rate);
/* lib init/done */
return (FALSE);
}
+ /**
+ * gst_object_suggest_next_sync:
+ * @object: the object that has controlled properties
+ * @timestamp: the time that should be processed
+ *
+ * Convenience function for GObject
+ *
+ * Returns: same thing as gst_controller_suggest_next_sync()
+ * Since: 0.10.13
+ */
+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, __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
* 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 sampling-rate/control-rate.
+ * should be up to @control-rate nanoseconds.
*
- * If the @object is not under property control, this will return 0. This allows
- * the element to avoid the sub-dividing.
+ * 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 elemnt is in
+ * The control-rate is not expected to change if the element is in
* %GST_STATE_PAUSED or %GST_STATE_PLAYING.
*
- * Returns: the control rate
+ * Returns: the control rate in nanoseconds
* Since: 0.10.10
*/
-guint
+GstClockTime
gst_object_get_control_rate (GObject * object)
{
GstController *ctrl;
- guint control_rate = 0;
+ GstClockTime control_rate = GST_CLOCK_TIME_NONE;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
/**
* gst_object_set_control_rate:
* @object: the object that has controlled properties
- * @control_rate: the new control-rate (1 .. sampling_rate)
+ * @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 sampling-rate/control-rate.
+ * should be up to @control-rate nanoseconds.
*
- * The control-rate should not change if the elemnt is in %GST_STATE_PAUSED or
+ * The control-rate should not change if the element is in %GST_STATE_PAUSED or
* %GST_STATE_PLAYING.
*
* Since: 0.10.10
*/
void
-gst_object_set_control_rate (GObject * object, guint control_rate)
+gst_object_set_control_rate (GObject * object, GstClockTime control_rate)
{
GstController *ctrl;