mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
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:
parent
1a6e50f5ca
commit
b92d7dc076
6 changed files with 135 additions and 69 deletions
23
ChangeLog
23
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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, ×tamp,
|
||||
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, ×tamp,
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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)); \
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue