libs/gst/controller/: Add a new private GstControlPoint struct which "inherits" from

Original commit message from CVS:
reviewed by: Stefan Kost <ensonic@users.sf.net>
* libs/gst/controller/gstcontroller.c: (gst_control_point_compare),
(gst_control_point_find), (gst_controlled_property_new),
(gst_control_point_free), (gst_controlled_property_free),
(gst_controller_set), (gst_controller_set_from_list),
(gst_controller_unset), (gst_controller_unset_all),
(gst_controller_sync_values):
* libs/gst/controller/gstcontroller.h:
* libs/gst/controller/gstcontrollerprivate.h:
* libs/gst/controller/gstinterpolation.c:
(gst_controlled_property_find_control_point_node),
(interpolate_none_get), (interpolate_trigger_get):
Add a new private GstControlPoint struct which "inherits" from
GstTimedValue to allow different interpolators to store internal
values next to each control point. From the outside everything is
still a GstControlPoint so we don't loose binary compatibility.
Also fixup all the GValue handling to not leak GValues or list nodes.
* tests/check/libs/controller.c: (GST_START_TEST):
Free the list nodes and GValues in the controller_misc test.
This commit is contained in:
Sebastian Dröge 2007-05-17 17:05:36 +00:00
parent 1a6e50f5ca
commit b92d7dc076
6 changed files with 135 additions and 69 deletions

View file

@ -1,3 +1,26 @@
2007-05-17 Sebastian Dröge <slomo@circular-chaos.org>
reviewed by: Stefan Kost <ensonic@users.sf.net>
* libs/gst/controller/gstcontroller.c: (gst_control_point_compare),
(gst_control_point_find), (gst_controlled_property_new),
(gst_control_point_free), (gst_controlled_property_free),
(gst_controller_set), (gst_controller_set_from_list),
(gst_controller_unset), (gst_controller_unset_all),
(gst_controller_sync_values):
* libs/gst/controller/gstcontroller.h:
* libs/gst/controller/gstcontrollerprivate.h:
* libs/gst/controller/gstinterpolation.c:
(gst_controlled_property_find_control_point_node),
(interpolate_none_get), (interpolate_trigger_get):
Add a new private GstControlPoint struct which "inherits" from
GstTimedValue to allow different interpolators to store internal
values next to each control point. From the outside everything is
still a GstControlPoint so we don't loose binary compatibility.
Also fixup all the GValue handling to not leak GValues or list nodes.
* tests/check/libs/controller.c: (GST_START_TEST):
Free the list nodes and GValues in the controller_misc test.
2007-05-17 Edward Hervey <edward@fluendo.com>
* gst/gstsegment.c:

View file

@ -92,7 +92,7 @@ struct _GstControllerPrivate
/* imports from gst-interpolation.c */
extern GList
* gst_controlled_property_find_timed_value_node (GstControlledProperty *
* gst_controlled_property_find_control_point_node (GstControlledProperty *
prop, GstClockTime timestamp);
extern GstInterpolateMethod *interpolation_methods[];
extern guint num_interpolation_methods;
@ -127,18 +127,18 @@ on_object_controlled_property_changed (const GObject * object, GParamSpec * arg,
/* helper */
/*
* gst_timed_value_compare:
* @p1: a pointer to a #GstTimedValue
* @p2: a pointer to a #GstTimedValue
* gst_control_point_compare:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstControlPoint
*
* Compare function for g_list operations that operates on two #GstTimedValue
* Compare function for g_list operations that operates on two #GstControlPoint
* parameters.
*/
static gint
gst_timed_value_compare (gconstpointer p1, gconstpointer p2)
gst_control_point_compare (gconstpointer p1, gconstpointer p2)
{
GstClockTime ct1 = ((GstTimedValue *) p1)->timestamp;
GstClockTime ct2 = ((GstTimedValue *) p2)->timestamp;
GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
GstClockTime ct2 = ((GstControlPoint *) p2)->timestamp;
return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
/* this does not produce an gint :(
@ -147,17 +147,17 @@ gst_timed_value_compare (gconstpointer p1, gconstpointer p2)
}
/*
* gst_timed_value_find:
* @p1: a pointer to a #GstTimedValue
* gst_control_point_find:
* @p1: a pointer to a #GstControlPoint
* @p2: a pointer to a #GstClockTime
*
* Compare function for g_list operations that operates on a #GstTimedValue and
* Compare function for g_list operations that operates on a #GstControlPoint and
* a #GstClockTime.
*/
static gint
gst_timed_value_find (gconstpointer p1, gconstpointer p2)
gst_control_point_find (gconstpointer p1, gconstpointer p2)
{
GstClockTime ct1 = ((GstTimedValue *) p1)->timestamp;
GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
GstClockTime ct2 = *(GstClockTime *) p2;
return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
@ -373,7 +373,7 @@ gst_controlled_property_new (GObject * object, const gchar * name)
GST_WARNING ("incomplete implementation for paramspec type '%s'",
G_PARAM_SPEC_TYPE_NAME (pspec));
}
/* TODO what about adding a timed-val with timestamp=0 and value=default
/* TODO what about adding a control point with timestamp=0 and value=default
* a bit easier for interpolators, example:
* first timestamp is at 5
* requested value if for timestamp=3
@ -398,6 +398,23 @@ Error:
}
/*
* gst_control_point_free:
* @prop: the object to free
*
* Private method which frees all data allocated by a #GstControlPoint
* instance.
*/
static void
gst_control_point_free (GstControlPoint * cp)
{
g_return_if_fail (cp);
g_value_unset (&cp->value);
g_free (cp);
}
/*
* gst_controlled_property_free:
* @prop: the object to free
*
@ -407,12 +424,15 @@ Error:
static void
gst_controlled_property_free (GstControlledProperty * prop)
{
GList *node;
for (node = prop->values; node; node = g_list_next (node)) {
g_free (node->data);
}
g_list_foreach (prop->values, (GFunc) gst_control_point_free, NULL);
g_list_free (prop->values);
g_value_unset (&prop->default_value);
g_value_unset (&prop->result_value);
g_value_unset (&prop->last_value.value);
if (G_IS_VALUE (&prop->live_value.value))
g_value_unset (&prop->live_value.value);
g_free (prop);
}
@ -723,22 +743,24 @@ gst_controller_set (GstController * self, gchar * property_name,
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
if (G_VALUE_TYPE (value) == prop->type) {
GstTimedValue *tv;
GstControlPoint *cp;
GList *node;
/* check if a timed_value for the timestamp already exists */
/* check if a control point for the timestamp already exists */
if ((node = g_list_find_custom (prop->values, &timestamp,
gst_timed_value_find))) {
tv = node->data;
memcpy (&tv->value, value, sizeof (GValue));
gst_control_point_find))) {
cp = node->data;
g_value_reset (&cp->value);
g_value_copy (value, &cp->value);
} else {
/* create a new GstTimedValue */
tv = g_new (GstTimedValue, 1);
tv->timestamp = timestamp;
memcpy (&tv->value, value, sizeof (GValue));
/* create a new GstControlPoint */
cp = g_new0 (GstControlPoint, 1);
cp->timestamp = timestamp;
g_value_init (&cp->value, prop->type);
g_value_copy (value, &cp->value);
/* and sort it into the prop->values list */
prop->values =
g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
g_list_insert_sorted (prop->values, cp, gst_control_point_compare);
}
res = TRUE;
} else {
@ -769,6 +791,7 @@ gst_controller_set_from_list (GstController * self, gchar * property_name,
GstControlledProperty *prop;
GSList *node;
GstTimedValue *tv;
GstControlPoint *cp;
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
g_return_val_if_fail (property_name, FALSE);
@ -779,9 +802,13 @@ gst_controller_set_from_list (GstController * self, gchar * property_name,
tv = node->data;
if (G_VALUE_TYPE (&tv->value) == prop->type) {
if (GST_CLOCK_TIME_IS_VALID (tv->timestamp)) {
/* TODO copy the timed value or just link in? */
cp = g_new0 (GstControlPoint, 1);
cp->timestamp = tv->timestamp;
g_value_init (&cp->value, prop->type);
g_value_copy (&tv->value, &cp->value);
prop->values =
g_list_insert_sorted (prop->values, tv, gst_timed_value_compare);
g_list_insert_sorted (prop->values, cp,
gst_control_point_compare);
res = TRUE;
} else {
g_warning ("GstTimedValued with invalid timestamp passed to %s "
@ -823,10 +850,10 @@ gst_controller_unset (GstController * self, gchar * property_name,
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
GList *node;
/* check if a timed_value for the timestamp exists */
/* check if a control point for the timestamp exists */
if ((node = g_list_find_custom (prop->values, &timestamp,
gst_timed_value_find))) {
g_free (node->data); /* free GstTimedValue */
gst_control_point_find))) {
gst_control_point_free (node->data); /* free GstControlPoint */
prop->values = g_list_delete_link (prop->values, node);
res = TRUE;
}
@ -858,8 +885,8 @@ gst_controller_unset_all (GstController * self, gchar * property_name)
g_mutex_lock (self->lock);
if ((prop = gst_controller_find_controlled_property (self, property_name))) {
/* free GstTimedValue structures */
g_list_foreach (prop->values, (GFunc) g_free, NULL);
/* free GstControlPoint structures */
g_list_foreach (prop->values, (GFunc) gst_control_point_free, NULL);
g_list_free (prop->values);
prop->values = NULL;
res = TRUE;
@ -963,14 +990,14 @@ gst_controller_sync_values (GstController * self, GstClockTime timestamp)
live = FALSE;
if (G_UNLIKELY (G_IS_VALUE (&prop->live_value.value))) {
GList *lnode =
gst_controlled_property_find_timed_value_node (prop, timestamp);
gst_controlled_property_find_control_point_node (prop, timestamp);
if (G_UNLIKELY (!lnode)) {
GST_DEBUG (" no control changes in the queue");
live = TRUE;
} else {
GstTimedValue *tv = lnode->data;
GstControlPoint *cp = lnode->data;
if (prop->live_value.timestamp < tv->timestamp) {
if (prop->live_value.timestamp < cp->timestamp) {
g_value_unset (&prop->live_value.value);
GST_DEBUG (" live value resetted");
} else if (prop->live_value.timestamp < timestamp) {

View file

@ -51,11 +51,6 @@ typedef struct _GstTimedValue
{
GstClockTime timestamp; /* timestamp of the value change */
GValue value; /* the new value */
/* TODO what about storing the difference to next timestamp and value here
+ make calculations slightly easier and faster
- determining the GType for the value_dif is not simple
e.g. if value is G_TYPE_UCHAR value_diff needs to be G_TYPE_INT
*/
} GstTimedValue;

View file

@ -65,6 +65,24 @@ typedef struct _GstInterpolateMethod
InterpolateGetValueArray get_string_value_array;
} GstInterpolateMethod;
/**
* GstControlPoint:
*
* a internal structure for value+time and various temporary
* values used for interpolation. This "inherits" from
* GstTimedValue.
*/
/* FIXME 0.11: This should be merged with GstTimedValue for 0.11 */
typedef struct _GstControlPoint
{
/* fields from GstTimedValue. DO NOT CHANGE! */
GstClockTime timestamp; /* timestamp of the value change */
GValue value; /* the new value */
/* internal fields */
} GstControlPoint;
/**
* GstControlledProperty:
*/
@ -75,8 +93,8 @@ typedef struct _GstControlledProperty
GType base; /* base-type of the handled property */
GValue default_value; /* default value for the handled property */
GValue result_value; /* result value location for the interpolation method */
GstTimedValue last_value; /* the last value a _sink call wrote */
GstTimedValue live_value; /* temporary value override for live input */
GstControlPoint last_value; /* the last value a _sink call wrote */
GstControlPoint live_value; /* temporary value override for live input */
gulong notify_handler_id; /* id of the notify::<name> signal handler */
GstInterpolateMode interpolation; /* Interpolation mode */
/* TODO instead of *method, have pointers to get() and get_value_array() here
@ -87,7 +105,7 @@ typedef struct _GstControlledProperty
InterpolateGet get;
InterpolateGetValueArray get_value_array;
GList *values; /* List of GstTimedValue */
GList *values; /* List of GstControlPoint */
/* TODO keep the last search result to be able to continue
GList *last_value; // last search result, can be used for incremental searches
*/

View file

@ -32,22 +32,22 @@ GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
/* common helper */
/*
* gst_controlled_property_find_timed_value_node:
* gst_controlled_property_find_control_point_node:
* @prop: the controlled property to search in
* @timestamp: the search key
*
* Find last value before given timestamp in timed value list.
* Find last value before given timestamp in control point list.
*
* Returns: the found #GList node or %NULL
*/
GList *
gst_controlled_property_find_timed_value_node (GstControlledProperty * prop,
gst_controlled_property_find_control_point_node (GstControlledProperty * prop,
GstClockTime timestamp)
{
/* GList *prev_node = NULL; */
GList *prev_node = g_list_last (prop->values);
GList *node;
GstTimedValue *tv;
GstControlPoint *cp;
/*
if((prop->last_value) &&
@ -61,9 +61,9 @@ gst_controlled_property_find_timed_value_node (GstControlledProperty * prop,
/* iterate over timed value list */
for (node = prop->values; node; node = g_list_next (node)) {
tv = node->data;
cp = node->data;
/* this timestamp is newer that the one we look for */
if (timestamp < tv->timestamp) {
if (timestamp < cp->timestamp) {
/* get previous one again */
prev_node = g_list_previous (node);
break;
@ -85,10 +85,11 @@ interpolate_none_get (GstControlledProperty * prop, GstClockTime timestamp)
{
GList *node;
if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) {
GstTimedValue *tv = node->data;
if ((node =
gst_controlled_property_find_control_point_node (prop, timestamp))) {
GstControlPoint *cp = node->data;
return (&tv->value);
return (&cp->value);
}
return (&prop->default_value);
}
@ -180,13 +181,13 @@ static GValue *
interpolate_trigger_get (GstControlledProperty * prop, GstClockTime timestamp)
{
GList *node;
GstTimedValue *tv;
GstControlPoint *cp;
/* check if there is a value at the registered timestamp */
for (node = prop->values; node; node = g_list_next (node)) {
tv = node->data;
if (timestamp == tv->timestamp) {
return (&tv->value);
cp = node->data;
if (timestamp == cp->timestamp) {
return (&cp->value);
}
}
@ -230,25 +231,25 @@ _interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime times
{ \
GList *node; \
\
if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) { \
GstTimedValue *tv1, *tv2; \
if ((node = gst_controlled_property_find_control_point_node (prop, timestamp))) { \
GstControlPoint *cp1, *cp2; \
\
tv1 = node->data; \
cp1 = node->data; \
if ((node = g_list_next (node))) { \
gdouble timediff,valuediff; \
g##type value1,value2; \
\
tv2 = node->data; \
cp2 = node->data; \
\
timediff = gst_guint64_to_gdouble (tv2->timestamp - tv1->timestamp); \
value1 = g_value_get_##type (&tv1->value); \
value2 = g_value_get_##type (&tv2->value); \
timediff = gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
value1 = g_value_get_##type (&cp1->value); \
value2 = g_value_get_##type (&cp2->value); \
valuediff = (gdouble) (value2 - value1); \
\
return ((g##type) (value1 + valuediff * (gst_guint64_to_gdouble (timestamp - tv1->timestamp) / timediff))); \
return ((g##type) (value1 + valuediff * (gst_guint64_to_gdouble (timestamp - cp1->timestamp) / timediff))); \
} \
else { \
return (g_value_get_##type (&tv1->value)); \
return (g_value_get_##type (&cp1->value)); \
} \
} \
return (g_value_get_##type (&prop->default_value)); \

View file

@ -883,6 +883,8 @@ GST_START_TEST (controller_misc)
fail_unless (gst_controller_set_from_list (ctrl, "ulong", list));
/* allocated GstTimedValue now belongs to the controller, but list not */
g_value_unset (&tval->value);
g_free (tval);
g_slist_free (list);
g_object_unref (ctrl);
gst_object_unref (elem);