diff --git a/libs/gst/controller/gstinterpolation.c b/libs/gst/controller/gstinterpolation.c index 4590372659..917250a184 100644 --- a/libs/gst/controller/gstinterpolation.c +++ b/libs/gst/controller/gstinterpolation.c @@ -1,7 +1,7 @@ /* GStreamer * * Copyright (C) <2005> Stefan Kost - * Copyright (C) 2007 Sebastian Dröge + * Copyright (C) 2007,2009 Sebastian Dröge * * gstinterpolation.c: Interpolation methods for dynamic properties * @@ -35,49 +35,53 @@ GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT); /* common helper */ +static gint +gst_control_point_find (gconstpointer p1, gconstpointer p2) +{ + GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp; + GstClockTime ct2 = *(GstClockTime *) p2; + + return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1)); +} + /* - * gst_interpolation_control_source_find_control_point_node: + * gst_interpolation_control_source_find_control_point_iter: * @self: the interpolation control source to search in * @timestamp: the search key * * Find last value before given timestamp in control point list. * - * Returns: the found #GList node or %NULL + * Returns: the found #GSequenceIter or %NULL */ -static GList *gst_interpolation_control_source_find_control_point_node +static GSequenceIter *gst_interpolation_control_source_find_control_point_iter (GstInterpolationControlSource * self, GstClockTime timestamp) { - GList *prev_node = g_list_last (self->priv->values); - GList *node; + GSequenceIter *iter; GstControlPoint *cp; - /* Check if we can start from the last requested value - * to save some time */ - node = self->priv->values; - if (self->priv->last_requested_value) { - GstControlPoint *last_cp = self->priv->last_requested_value->data; + if (!self->priv->values) + return NULL; - if (timestamp > last_cp->timestamp) - node = self->priv->last_requested_value; - } + iter = + g_sequence_search (self->priv->values, ×tamp, + (GCompareDataFunc) gst_control_point_find, NULL); - /* iterate over timed value list */ - for (; node; node = g_list_next (node)) { - cp = node->data; - /* this timestamp is newer that the one we look for */ - if (timestamp < cp->timestamp) { - /* get previous one again */ - prev_node = g_list_previous (node); - break; - } - } + /* g_sequence_search() returns the iter where timestamp + * would be inserted, i.e. the iter > timestamp, so + * we need to get the previous one */ + iter = g_sequence_iter_prev (iter); - /* If we have something to return save it as a - * potential start position for the next search */ - if (prev_node) - self->priv->last_requested_value = prev_node; + /* g_sequence_iter_prev () on the begin iter returns + * the begin iter. Check if the prev iter is still + * after our timestamp, in that case return NULL + */ + cp = g_sequence_get (iter); + if (cp->timestamp > timestamp) + return NULL; - return prev_node; + /* If the iter is the end iter return NULL as no + * data is linked to the end iter */ + return G_UNLIKELY (g_sequence_iter_is_end (iter)) ? NULL : iter; } /* steps-like (no-)interpolation, default */ @@ -88,11 +92,11 @@ static inline GValue * \ _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ { \ GValue *ret; \ - GList *node; \ + GSequenceIter *iter; \ \ - if ((node = \ - gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ - GstControlPoint *cp = node->data; \ + if ((iter = \ + gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \ + GstControlPoint *cp = g_sequence_get (iter); \ g##type ret_val = g_value_get_##type (&cp->value); \ \ if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \ @@ -162,13 +166,13 @@ static inline GValue * _interpolate_none_get (GstInterpolationControlSource * self, GstClockTime timestamp) { - GList *node; + GSequenceIter *iter; GValue *ret; - if ((node = - gst_interpolation_control_source_find_control_point_node (self, + if ((iter = + gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { - GstControlPoint *cp = node->data; + GstControlPoint *cp = g_sequence_get (iter); ret = &cp->value; } else { @@ -300,13 +304,13 @@ static GstInterpolateMethod interpolate_none = { static inline GValue * \ _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ { \ - GList *node; \ + GSequenceIter *iter; \ GstControlPoint *cp; \ \ /* check if there is a value at the registered timestamp */ \ - if ((node = \ - gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ - cp = node->data; \ + if ((iter = \ + gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \ + cp = g_sequence_get (iter); \ if (timestamp == cp->timestamp) { \ g##type ret = g_value_get_##type (&cp->value); \ if (g_value_get_##type (&self->priv->minimum_value) > ret) \ @@ -379,14 +383,14 @@ static inline GValue * _interpolate_trigger_get (GstInterpolationControlSource * self, GstClockTime timestamp) { - GList *node; + GSequenceIter *iter; GstControlPoint *cp; /* check if there is a value at the registered timestamp */ - if ((node = - gst_interpolation_control_source_find_control_point_node (self, + if ((iter = + gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { - cp = node->data; + cp = g_sequence_get (iter); if (timestamp == cp->timestamp) { return &cp->value; } @@ -518,25 +522,26 @@ static GstInterpolateMethod interpolate_trigger = { static inline gboolean \ _interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \ { \ - GList *node; \ + GSequenceIter *iter; \ GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \ \ - node = gst_interpolation_control_source_find_control_point_node (self, timestamp); \ - if (node) { \ - cp1 = node->data; \ - node = g_list_next (node); \ + iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ + if (iter) { \ + cp1 = g_sequence_get (iter); \ + iter = g_sequence_iter_next (iter); \ + iter = g_sequence_iter_is_end (iter) ? NULL : iter; \ } else { \ cp.timestamp = G_GUINT64_CONSTANT(0); \ g_value_init (&cp.value, self->priv->type); \ g_value_copy (&self->priv->default_value, &cp.value); \ cp1 = &cp; \ - node = self->priv->values; \ + iter = g_sequence_get_begin_iter (self->priv->values); \ } \ - if (node) { \ + if (iter) { \ gdouble slope; \ g##vtype value1,value2; \ \ - cp2 = node->data; \ + cp2 = g_sequence_get (iter); \ \ value1 = g_value_get_##vtype (&cp1->value); \ value2 = g_value_get_##vtype (&cp2->value); \ @@ -655,21 +660,21 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ gdouble *b = g_new0 (gdouble, n); \ gdouble *z = g_new0 (gdouble, n); \ \ - GList *node; \ + GSequenceIter *iter; \ GstControlPoint *cp; \ GstClockTime x_prev, x, x_next; \ g##vtype y_prev, y, y_next; \ \ /* Fill linear system of equations */ \ - node = self->priv->values; \ - cp = node->data; \ + iter = g_sequence_get_begin_iter (self->priv->values); \ + cp = g_sequence_get (iter); \ x = cp->timestamp; \ y = g_value_get_##vtype (&cp->value); \ \ p[0] = 1.0; \ \ - node = node->next; \ - cp = node->data; \ + iter = g_sequence_iter_next (iter); \ + cp = g_sequence_get (iter); \ x_next = cp->timestamp; \ y_next = g_value_get_##vtype (&cp->value); \ h[0] = gst_guint64_to_gdouble (x_next - x); \ @@ -680,8 +685,8 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ y_prev = y; \ x = x_next; \ y = y_next; \ - node = node->next; \ - cp = node->data; \ + iter = g_sequence_iter_next (iter); \ + cp = g_sequence_get (iter); \ x_next = cp->timestamp; \ y_next = g_value_get_##vtype (&cp->value); \ \ @@ -707,12 +712,12 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ \ /* Save cache next in the GstControlPoint */ \ \ - node = self->priv->values; \ + iter = g_sequence_get_begin_iter (self->priv->values); \ for (i = 0; i < n; i++) { \ - cp = node->data; \ + cp = g_sequence_get (iter); \ cp->cache.cubic.h = h[i]; \ cp->cache.cubic.z = z[i]; \ - node = node->next; \ + iter = g_sequence_iter_next (iter); \ } \ \ /* Free our temporary arrays */ \ @@ -727,7 +732,7 @@ _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ static inline gboolean \ _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \ { \ - GList *node; \ + GSequenceIter *iter; \ GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \ \ if (self->priv->nvalues <= 2) \ @@ -738,23 +743,24 @@ _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTim self->priv->valid_cache = TRUE; \ } \ \ - node = gst_interpolation_control_source_find_control_point_node (self, timestamp); \ - if (node) { \ - cp1 = node->data; \ - node = g_list_next (node); \ + iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ + if (iter) { \ + cp1 = g_sequence_get (iter); \ + iter = g_sequence_iter_next (iter); \ + iter = g_sequence_iter_is_end (iter) ? NULL : iter; \ } else { \ cp.timestamp = G_GUINT64_CONSTANT(0); \ g_value_init (&cp.value, self->priv->type); \ g_value_copy (&self->priv->default_value, &cp.value); \ cp1 = &cp; \ - node = self->priv->values; \ + iter = g_sequence_get_begin_iter (self->priv->values); \ } \ - if (node) { \ + if (iter) { \ gdouble diff1, diff2; \ g##vtype value1,value2; \ gdouble out; \ \ - cp2 = node->data; \ + cp2 = g_sequence_get (iter); \ \ value1 = g_value_get_##vtype (&cp1->value); \ value2 = g_value_get_##vtype (&cp2->value); \ diff --git a/libs/gst/controller/gstinterpolationcontrolsource.c b/libs/gst/controller/gstinterpolationcontrolsource.c index ace4255c64..85ab095eac 100644 --- a/libs/gst/controller/gstinterpolationcontrolsource.c +++ b/libs/gst/controller/gstinterpolationcontrolsource.c @@ -1,6 +1,6 @@ /* GStreamer * - * Copyright (C) 2007 Sebastian Dröge + * Copyright (C) 2007,2009 Sebastian Dröge * * gstinterpolationcontrolsource.c: Control source that provides several * interpolation methods @@ -89,13 +89,11 @@ gst_interpolation_control_source_reset (GstInterpolationControlSource * self) g_value_unset (&self->priv->maximum_value); if (self->priv->values) { - g_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL); - g_list_free (self->priv->values); + g_sequence_free (self->priv->values); self->priv->values = NULL; } self->priv->nvalues = 0; - self->priv->last_requested_value = NULL; self->priv->valid_cache = FALSE; } @@ -125,9 +123,8 @@ gst_interpolation_control_source_new (void) * Returns: %TRUE if the interpolation mode could be set, %FALSE otherwise */ gboolean -gst_interpolation_control_source_set_interpolation_mode - (GstInterpolationControlSource * self, GstInterpolateMode mode) -{ + gst_interpolation_control_source_set_interpolation_mode + (GstInterpolationControlSource * self, GstInterpolateMode mode) { gboolean ret = TRUE; GstControlSource *csource = GST_CONTROL_SOURCE (self); @@ -416,44 +413,6 @@ gst_control_point_find (gconstpointer p1, gconstpointer p2) return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1)); } -/* - * _list_find_sorted_custom: - * - * This works like g_list_find_custom() with the difference that it expects the - * list to be sorted in ascending order (0->MAX), stops when it the list-values - * are bigger that what is searched for and optionaly delivers the last node - * back in the @prev_node argument. This can be used to quickly insert a new - * node at the correct position. - */ -static GList * -_list_find_sorted_custom (GList * list, gconstpointer data, GCompareFunc func, - GList ** prev_node) -{ - GList *prev = list; - gint cmp; - - g_return_val_if_fail (func != NULL, list); - - while (list) { - cmp = func (list->data, data); - switch (cmp) { - case -1: - prev = list; - list = list->next; - break; - case 0: - return list; - case 1: - if (prev_node) - *prev_node = prev; - return NULL; - } - } - if (prev_node) - *prev_node = prev; - return NULL; -} - static GstControlPoint * _make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp, GValue * value) @@ -473,43 +432,38 @@ static void gst_interpolation_control_source_set_internal (GstInterpolationControlSource * self, GstClockTime timestamp, GValue * value) { - GList *node, *prev = self->priv->values; - - /* check if we can shortcut and append */ - if ((node = g_list_last (self->priv->values))) { - GstControlPoint *last_cp = node->data; - - if (timestamp > last_cp->timestamp) { - /* pass 'node' instead of list, and also deliberately ignore the result */ - node = g_list_append (node, _make_new_cp (self, timestamp, value)); - self->priv->nvalues++; - goto done; - } - } + GSequenceIter *iter; /* check if a control point for the timestamp already exists */ - if ((node = _list_find_sorted_custom (self->priv->values, ×tamp, - gst_control_point_find, &prev))) { - /* update control point */ - GstControlPoint *cp = node->data; - g_value_reset (&cp->value); - g_value_copy (value, &cp->value); - } else { - /* sort new cp into the prop->values list */ - if (self->priv->values) { - GList *new_list; - /* pass 'prev' instead of list */ - new_list = g_list_insert_sorted (prev, - _make_new_cp (self, timestamp, value), gst_control_point_compare); - if (self->priv->values == prev) - self->priv->values = new_list; - } else { - self->priv->values = g_list_prepend (NULL, - _make_new_cp (self, timestamp, value)); + /* iter contains the iter right *after* timestamp */ + if (self->priv->values) { + iter = + g_sequence_search (self->priv->values, ×tamp, + (GCompareDataFunc) gst_control_point_find, NULL); + if (iter) { + GSequenceIter *prev = g_sequence_iter_prev (iter); + GstControlPoint *cp = g_sequence_get (prev); + + /* If the timestamp is the same just update the control point value */ + if (cp->timestamp == timestamp) { + /* update control point */ + g_value_reset (&cp->value); + g_value_copy (value, &cp->value); + goto done; + } } - self->priv->nvalues++; } + + /* sort new cp into the prop->values list */ + if (!self->priv->values) + self->priv->values = + g_sequence_new ((GDestroyNotify) gst_control_point_free); + + g_sequence_insert_sorted (self->priv->values, _make_new_cp (self, timestamp, + value), (GCompareDataFunc) gst_control_point_compare, NULL); + self->priv->nvalues++; + done: self->priv->valid_cache = FALSE; } @@ -595,7 +549,7 @@ gboolean gst_interpolation_control_source_unset (GstInterpolationControlSource * self, GstClockTime timestamp) { - GList *node; + GSequenceIter *iter; gboolean res = FALSE; g_return_val_if_fail (GST_IS_INTERPOLATION_CONTROL_SOURCE (self), FALSE); @@ -603,15 +557,22 @@ gst_interpolation_control_source_unset (GstInterpolationControlSource * self, g_mutex_lock (self->lock); /* check if a control point for the timestamp exists */ - if ((node = g_list_find_custom (self->priv->values, ×tamp, - gst_control_point_find))) { - if (node == self->priv->last_requested_value) - self->priv->last_requested_value = NULL; - gst_control_point_free (node->data); /* free GstControlPoint */ - self->priv->values = g_list_delete_link (self->priv->values, node); - self->priv->nvalues--; - self->priv->valid_cache = FALSE; - res = TRUE; + if ((iter = + g_sequence_search (self->priv->values, ×tamp, + (GCompareDataFunc) gst_control_point_find, NULL))) { + GstControlPoint *cp; + + /* Iter contains the iter right after timestamp, i.e. + * we need to get the previous one and check the timestamp + */ + iter = g_sequence_iter_prev (iter); + cp = g_sequence_get (iter); + if (cp->timestamp == timestamp) { + g_sequence_remove (iter); + self->priv->nvalues--; + self->priv->valid_cache = FALSE; + res = TRUE; + } } g_mutex_unlock (self->lock); @@ -633,9 +594,7 @@ gst_interpolation_control_source_unset_all (GstInterpolationControlSource * g_mutex_lock (self->lock); /* free GstControlPoint structures */ - g_list_foreach (self->priv->values, (GFunc) gst_control_point_free, NULL); - g_list_free (self->priv->values); - self->priv->last_requested_value = NULL; + g_sequence_free (self->priv->values); self->priv->values = NULL; self->priv->nvalues = 0; self->priv->valid_cache = FALSE; @@ -643,6 +602,12 @@ gst_interpolation_control_source_unset_all (GstInterpolationControlSource * g_mutex_unlock (self->lock); } +static void +_append_control_point (GstControlPoint * cp, GList ** l) +{ + *l = g_list_prepend (*l, cp); +} + /** * gst_interpolation_control_source_get_all: * @self: the #GstInterpolationControlSource to get the list from @@ -661,10 +626,11 @@ gst_interpolation_control_source_get_all (GstInterpolationControlSource * self) g_mutex_lock (self->lock); if (self->priv->values) - res = g_list_copy (self->priv->values); + g_sequence_foreach (self->priv->values, (GFunc) _append_control_point, + &res); g_mutex_unlock (self->lock); - return res; + return g_list_reverse (res); } /** diff --git a/libs/gst/controller/gstinterpolationcontrolsourceprivate.h b/libs/gst/controller/gstinterpolationcontrolsourceprivate.h index 64f510e945..1058d1b6c1 100644 --- a/libs/gst/controller/gstinterpolationcontrolsourceprivate.h +++ b/libs/gst/controller/gstinterpolationcontrolsourceprivate.h @@ -90,9 +90,8 @@ struct _GstInterpolationControlSourcePrivate GValue maximum_value; /* max value for the handled property */ GstInterpolateMode interpolation_mode; - GList *values; /* List of GstControlPoint */ + GSequence *values; /* List of GstControlPoint */ gint nvalues; /* Number of control points */ - GList *last_requested_value; /* last search result, can be used for incremental searches */ gboolean valid_cache; };