gstreamer_core/libs/gst/controller/gstinterpolation.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
     1 /* GStreamer
     1 /* GStreamer
     2  *
     2  *
     3  * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
     3  * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
     4  * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
     4  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
     5  *
     5  *
     6  * gstinterpolation.c: Interpolation methods for dynamic properties
     6  * gstinterpolation.c: Interpolation methods for dynamic properties
     7  *
     7  *
     8  * This library is free software; you can redistribute it and/or
     8  * This library is free software; you can redistribute it and/or
     9  * modify it under the terms of the GNU Library General Public
     9  * modify it under the terms of the GNU Library General Public
    39 
    39 
    40 #define EMPTY(x) (x)
    40 #define EMPTY(x) (x)
    41 
    41 
    42 /* common helper */
    42 /* common helper */
    43 
    43 
    44 static gint
       
    45 gst_control_point_find (gconstpointer p1, gconstpointer p2)
       
    46 {
       
    47   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
       
    48   GstClockTime ct2 = *(GstClockTime *) p2;
       
    49 
       
    50   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
       
    51 }
       
    52 
       
    53 /*
    44 /*
    54  * gst_interpolation_control_source_find_control_point_iter:
    45  * gst_interpolation_control_source_find_control_point_node:
    55  * @self: the interpolation control source to search in
    46  * @self: the interpolation control source to search in
    56  * @timestamp: the search key
    47  * @timestamp: the search key
    57  *
    48  *
    58  * Find last value before given timestamp in control point list.
    49  * Find last value before given timestamp in control point list.
    59  *
    50  *
    60  * Returns: the found #GSequenceIter or %NULL
    51  * Returns: the found #GList node or %NULL
    61  */
    52  */
    62 static GSequenceIter *gst_interpolation_control_source_find_control_point_iter
    53 static GList *gst_interpolation_control_source_find_control_point_node
    63     (GstInterpolationControlSource * self, GstClockTime timestamp)
    54     (GstInterpolationControlSource * self, GstClockTime timestamp)
    64 {
    55 {
    65   GSequenceIter *iter;
    56   GList *prev_node = g_list_last (self->priv->values);
       
    57   GList *node;
    66   GstControlPoint *cp;
    58   GstControlPoint *cp;
    67 
    59 
    68   if (!self->priv->values)
    60   /* Check if we can start from the last requested value
       
    61    * to save some time */
       
    62   node = self->priv->values;
       
    63   if (self->priv->last_requested_value) {
       
    64     GstControlPoint *last_cp = self->priv->last_requested_value->data;
       
    65 
       
    66     if (timestamp > last_cp->timestamp)
       
    67       node = self->priv->last_requested_value;
       
    68   }
       
    69 
       
    70   /* iterate over timed value list */
       
    71   for (; node; node = g_list_next (node)) {
       
    72     cp = node->data;
       
    73     /* this timestamp is newer that the one we look for */
       
    74     if (timestamp < cp->timestamp) {
       
    75       /* get previous one again */
       
    76       prev_node = g_list_previous (node);
       
    77       break;
       
    78     }
       
    79   }
       
    80 
       
    81   /* If we have something to return save it as a
       
    82    * potential start position for the next search */
       
    83   if (prev_node)
       
    84     self->priv->last_requested_value = prev_node;
       
    85 
       
    86   return prev_node;
       
    87 }
       
    88 
       
    89 /*
       
    90  * gst_interpolation_control_source_get_first_value:
       
    91  * @self: the interpolation control source to search in
       
    92  *
       
    93  * Find the first value and return it.
       
    94  *
       
    95  * Returns: the found #GValue or %NULL if there are none.
       
    96  */
       
    97 static inline GValue *
       
    98 gst_interpolation_control_source_get_first_value (GstInterpolationControlSource
       
    99     * self)
       
   100 {
       
   101   if (self->priv->values && self->priv->nvalues > 0) {
       
   102     GstControlPoint *cp = self->priv->values->data;
       
   103 
       
   104     return &cp->value;
       
   105   } else {
    69     return NULL;
   106     return NULL;
    70 
   107   }
    71   iter =
       
    72       g_sequence_search (self->priv->values, &timestamp,
       
    73       (GCompareDataFunc) gst_control_point_find, NULL);
       
    74 
       
    75   /* g_sequence_search() returns the iter where timestamp
       
    76    * would be inserted, i.e. the iter > timestamp, so
       
    77    * we need to get the previous one */
       
    78   iter = g_sequence_iter_prev (iter);
       
    79 
       
    80   /* g_sequence_iter_prev () on the begin iter returns
       
    81    * the begin iter. Check if the prev iter is still
       
    82    * after our timestamp, in that case return NULL
       
    83    */
       
    84   cp = g_sequence_get (iter);
       
    85   if (cp->timestamp > timestamp)
       
    86     return NULL;
       
    87 
       
    88   /* If the iter is the end iter return NULL as no
       
    89    * data is linked to the end iter */
       
    90   return G_UNLIKELY (g_sequence_iter_is_end (iter)) ? NULL : iter;
       
    91 }
   108 }
    92 
   109 
    93 /*  steps-like (no-)interpolation, default */
   110 /*  steps-like (no-)interpolation, default */
    94 /*  just returns the value for the most recent key-frame */
   111 /*  just returns the value for the most recent key-frame */
    95 
   112 
    96 #define DEFINE_NONE_GET(type) \
   113 #define DEFINE_NONE_GET(type) \
    97 static inline GValue * \
   114 static inline GValue * \
    98 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
   115 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
    99 { \
   116 { \
   100   GValue *ret; \
   117   GValue *ret; \
   101   GSequenceIter *iter; \
   118   GList *node; \
   102   \
   119   \
   103   if ((iter = \
   120   if ((node = \
   104           gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \
   121           gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
   105     GstControlPoint *cp = g_sequence_get (iter); \
   122     GstControlPoint *cp = node->data; \
   106     g##type ret_val = g_value_get_##type (&cp->value); \
   123     g##type ret_val = g_value_get_##type (&cp->value); \
   107     \
   124     \
   108     if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
   125     if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
   109       ret = &self->priv->minimum_value; \
   126       ret = &self->priv->minimum_value; \
   110     else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
   127     else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
   111       ret = &self->priv->maximum_value; \
   128       ret = &self->priv->maximum_value; \
   112     else \
   129     else \
   113       ret = &cp->value; \
   130       ret = &cp->value; \
   114   } else { \
   131   } else { \
   115     ret = &self->priv->default_value; \
   132     ret = gst_interpolation_control_source_get_first_value (self); \
   116   } \
   133   } \
   117   return ret; \
   134   return ret; \
   118 } \
   135 } \
   119 \
   136 \
   120 static gboolean \
   137 static gboolean \
   142   g##type *values = (g##type *) value_array->values; \
   159   g##type *values = (g##type *) value_array->values; \
   143   GValue *ret; \
   160   GValue *ret; \
   144   \
   161   \
   145   g_mutex_lock (self->lock); \
   162   g_mutex_lock (self->lock); \
   146   for(i = 0; i < value_array->nbsamples; i++) { \
   163   for(i = 0; i < value_array->nbsamples; i++) { \
   147     ret = _interpolate_none_get_##type (self, ts); \
   164     ret = _interpolate_none_get_##type (self, timestamp); \
   148     if (!ret) { \
   165     if (!ret) { \
   149       g_mutex_unlock (self->lock); \
   166       g_mutex_unlock (self->lock); \
   150       return FALSE; \
   167       return FALSE; \
   151     } \
   168     } \
   152     *values = g_value_get_##type (ret); \
   169     *values = g_value_get_##type (ret); \
   170 
   187 
   171 static inline GValue *
   188 static inline GValue *
   172 _interpolate_none_get (GstInterpolationControlSource * self,
   189 _interpolate_none_get (GstInterpolationControlSource * self,
   173     GstClockTime timestamp)
   190     GstClockTime timestamp)
   174 {
   191 {
   175   GSequenceIter *iter;
   192   GList *node;
   176   GValue *ret;
   193   GValue *ret;
   177 
   194 
   178   if ((iter =
   195   if ((node =
   179           gst_interpolation_control_source_find_control_point_iter (self,
   196           gst_interpolation_control_source_find_control_point_node (self,
   180               timestamp))) {
   197               timestamp))) {
   181     GstControlPoint *cp = g_sequence_get (iter);
   198     GstControlPoint *cp = node->data;
   182 
   199 
   183     ret = &cp->value;
   200     ret = &cp->value;
   184   } else {
   201   } else {
   185     ret = &self->priv->default_value;
   202     ret = gst_interpolation_control_source_get_first_value (self);
   186   }
   203   }
   187   return ret;
   204   return ret;
   188 }
   205 }
   189 
   206 
   190 static gboolean
   207 static gboolean
   215   gboolean *values = (gboolean *) value_array->values;
   232   gboolean *values = (gboolean *) value_array->values;
   216   GValue *ret;
   233   GValue *ret;
   217 
   234 
   218   g_mutex_lock (self->lock);
   235   g_mutex_lock (self->lock);
   219   for (i = 0; i < value_array->nbsamples; i++) {
   236   for (i = 0; i < value_array->nbsamples; i++) {
   220     ret = _interpolate_none_get (self, ts);
   237     ret = _interpolate_none_get (self, timestamp);
   221     if (!ret) {
   238     if (!ret) {
   222       g_mutex_unlock (self->lock);
   239       g_mutex_unlock (self->lock);
   223       return FALSE;
   240       return FALSE;
   224     }
   241     }
   225     *values = g_value_get_boolean (ret);
   242     *values = g_value_get_boolean (ret);
   239   gint *values = (gint *) value_array->values;
   256   gint *values = (gint *) value_array->values;
   240   GValue *ret;
   257   GValue *ret;
   241 
   258 
   242   g_mutex_lock (self->lock);
   259   g_mutex_lock (self->lock);
   243   for (i = 0; i < value_array->nbsamples; i++) {
   260   for (i = 0; i < value_array->nbsamples; i++) {
   244     ret = _interpolate_none_get (self, ts);
   261     ret = _interpolate_none_get (self, timestamp);
   245     if (!ret) {
   262     if (!ret) {
   246       g_mutex_unlock (self->lock);
   263       g_mutex_unlock (self->lock);
   247       return FALSE;
   264       return FALSE;
   248     }
   265     }
   249     *values = g_value_get_enum (ret);
   266     *values = g_value_get_enum (ret);
   263   gchar **values = (gchar **) value_array->values;
   280   gchar **values = (gchar **) value_array->values;
   264   GValue *ret;
   281   GValue *ret;
   265 
   282 
   266   g_mutex_lock (self->lock);
   283   g_mutex_lock (self->lock);
   267   for (i = 0; i < value_array->nbsamples; i++) {
   284   for (i = 0; i < value_array->nbsamples; i++) {
   268     ret = _interpolate_none_get (self, ts);
   285     ret = _interpolate_none_get (self, timestamp);
   269     if (!ret) {
   286     if (!ret) {
   270       g_mutex_unlock (self->lock);
   287       g_mutex_unlock (self->lock);
   271       return FALSE;
   288       return FALSE;
   272     }
   289     }
   273     *values = (gchar *) g_value_get_string (ret);
   290     *values = (gchar *) g_value_get_string (ret);
   308 
   325 
   309 #define DEFINE_TRIGGER_GET(type) \
   326 #define DEFINE_TRIGGER_GET(type) \
   310 static inline GValue * \
   327 static inline GValue * \
   311 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
   328 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
   312 { \
   329 { \
   313   GSequenceIter *iter; \
   330   GList *node; \
   314   GstControlPoint *cp; \
   331   GstControlPoint *cp; \
   315   \
   332   \
   316   /* check if there is a value at the registered timestamp */ \
   333   /* check if there is a value at the registered timestamp */ \
   317   if ((iter = \
   334   if ((node = \
   318           gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \
   335           gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
   319     cp = g_sequence_get (iter); \
   336     cp = node->data; \
   320     if (timestamp == cp->timestamp) { \
   337     if (timestamp == cp->timestamp) { \
   321       g##type ret = g_value_get_##type (&cp->value); \
   338       g##type ret = g_value_get_##type (&cp->value); \
   322       if (g_value_get_##type (&self->priv->minimum_value) > ret) \
   339       if (g_value_get_##type (&self->priv->minimum_value) > ret) \
   323         return &self->priv->minimum_value; \
   340         return &self->priv->minimum_value; \
   324       else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
   341       else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
   358   g##type *values = (g##type *) value_array->values; \
   375   g##type *values = (g##type *) value_array->values; \
   359   GValue *ret; \
   376   GValue *ret; \
   360   \
   377   \
   361   g_mutex_lock (self->lock); \
   378   g_mutex_lock (self->lock); \
   362   for(i = 0; i < value_array->nbsamples; i++) { \
   379   for(i = 0; i < value_array->nbsamples; i++) { \
   363     ret = _interpolate_trigger_get_##type (self, ts); \
   380     ret = _interpolate_trigger_get_##type (self, timestamp); \
   364     if (!ret) { \
   381     if (!ret) { \
   365       g_mutex_unlock (self->lock); \
   382       g_mutex_unlock (self->lock); \
   366       return FALSE; \
   383       return FALSE; \
   367     } \
   384     } \
   368     *values = g_value_get_##type (ret); \
   385     *values = g_value_get_##type (ret); \
   387 
   404 
   388 static inline GValue *
   405 static inline GValue *
   389 _interpolate_trigger_get (GstInterpolationControlSource * self,
   406 _interpolate_trigger_get (GstInterpolationControlSource * self,
   390     GstClockTime timestamp)
   407     GstClockTime timestamp)
   391 {
   408 {
   392   GSequenceIter *iter;
   409   GList *node;
   393   GstControlPoint *cp;
   410   GstControlPoint *cp;
   394 
   411 
   395   /* check if there is a value at the registered timestamp */
   412   /* check if there is a value at the registered timestamp */
   396   if ((iter =
   413   if ((node =
   397           gst_interpolation_control_source_find_control_point_iter (self,
   414           gst_interpolation_control_source_find_control_point_node (self,
   398               timestamp))) {
   415               timestamp))) {
   399     cp = g_sequence_get (iter);
   416     cp = node->data;
   400     if (timestamp == cp->timestamp) {
   417     if (timestamp == cp->timestamp) {
   401       return &cp->value;
   418       return &cp->value;
   402     }
   419     }
   403   }
   420   }
   404   if (self->priv->nvalues > 0)
   421   if (self->priv->nvalues > 0)
   433   gint *values = (gint *) value_array->values;
   450   gint *values = (gint *) value_array->values;
   434   GValue *ret;
   451   GValue *ret;
   435 
   452 
   436   g_mutex_lock (self->lock);
   453   g_mutex_lock (self->lock);
   437   for (i = 0; i < value_array->nbsamples; i++) {
   454   for (i = 0; i < value_array->nbsamples; i++) {
   438     ret = _interpolate_trigger_get (self, ts);
   455     ret = _interpolate_trigger_get (self, timestamp);
   439     if (!ret) {
   456     if (!ret) {
   440       g_mutex_unlock (self->lock);
   457       g_mutex_unlock (self->lock);
   441       return FALSE;
   458       return FALSE;
   442     }
   459     }
   443     *values = g_value_get_boolean (ret);
   460     *values = g_value_get_boolean (ret);
   457   gint *values = (gint *) value_array->values;
   474   gint *values = (gint *) value_array->values;
   458   GValue *ret;
   475   GValue *ret;
   459 
   476 
   460   g_mutex_lock (self->lock);
   477   g_mutex_lock (self->lock);
   461   for (i = 0; i < value_array->nbsamples; i++) {
   478   for (i = 0; i < value_array->nbsamples; i++) {
   462     ret = _interpolate_trigger_get (self, ts);
   479     ret = _interpolate_trigger_get (self, timestamp);
   463     if (!ret) {
   480     if (!ret) {
   464       g_mutex_unlock (self->lock);
   481       g_mutex_unlock (self->lock);
   465       return FALSE;
   482       return FALSE;
   466     }
   483     }
   467     *values = g_value_get_enum (ret);
   484     *values = g_value_get_enum (ret);
   481   gchar **values = (gchar **) value_array->values;
   498   gchar **values = (gchar **) value_array->values;
   482   GValue *ret;
   499   GValue *ret;
   483 
   500 
   484   g_mutex_lock (self->lock);
   501   g_mutex_lock (self->lock);
   485   for (i = 0; i < value_array->nbsamples; i++) {
   502   for (i = 0; i < value_array->nbsamples; i++) {
   486     ret = _interpolate_trigger_get (self, ts);
   503     ret = _interpolate_trigger_get (self, timestamp);
   487     if (!ret) {
   504     if (!ret) {
   488       g_mutex_unlock (self->lock);
   505       g_mutex_unlock (self->lock);
   489       return FALSE;
   506       return FALSE;
   490     }
   507     }
   491     *values = (gchar *) g_value_get_string (ret);
   508     *values = (gchar *) g_value_get_string (ret);
   522 };
   539 };
   523 
   540 
   524 /*  linear interpolation */
   541 /*  linear interpolation */
   525 /*  smoothes inbetween values */
   542 /*  smoothes inbetween values */
   526 
   543 
   527 #define DEFINE_LINEAR_GET(vtype,round,convert) \
   544 #define DEFINE_LINEAR_GET(type,round,convert) \
   528 static inline gboolean \
   545 static inline gboolean \
   529 _interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \
   546 _interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
   530 { \
   547 { \
   531   GSequenceIter *iter; \
   548   GList *node; \
   532   GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \
   549   \
   533   \
   550   if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
   534   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
   551     GstControlPoint *cp1, *cp2; \
   535   if (iter) { \
   552     \
   536     cp1 = g_sequence_get (iter); \
   553     cp1 = node->data; \
   537     iter = g_sequence_iter_next (iter); \
   554     if ((node = g_list_next (node))) { \
   538     iter = g_sequence_iter_is_end (iter) ? NULL : iter; \
   555       gdouble slope; \
       
   556       g##type value1,value2; \
       
   557       \
       
   558       cp2 = node->data; \
       
   559       \
       
   560       value1 = g_value_get_##type (&cp1->value); \
       
   561       value2 = g_value_get_##type (&cp2->value); \
       
   562       slope = (gdouble) convert (value2 - value1) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
       
   563       \
       
   564       if (round) \
       
   565         *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \
       
   566       else \
       
   567         *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \
       
   568     } \
       
   569     else { \
       
   570       *ret = g_value_get_##type (&cp1->value); \
       
   571     } \
   539   } else { \
   572   } else { \
   540     cp.timestamp = G_GUINT64_CONSTANT(0); \
   573     GValue *first = gst_interpolation_control_source_get_first_value (self); \
   541     g_value_init (&cp.value, self->priv->type); \
   574     if (!first) \
   542     g_value_copy (&self->priv->default_value, &cp.value); \
   575       return FALSE; \
   543     cp1 = &cp; \
   576     *ret = g_value_get_##type (first); \
   544     if (G_LIKELY (self->priv->values)) \
   577   } \
   545       iter = g_sequence_get_begin_iter (self->priv->values); \
   578   *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
   546   } \
       
   547   if (iter) { \
       
   548     gdouble slope; \
       
   549     g##vtype value1,value2; \
       
   550     \
       
   551     cp2 = g_sequence_get (iter); \
       
   552     \
       
   553     value1 = g_value_get_##vtype (&cp1->value); \
       
   554     value2 = g_value_get_##vtype (&cp2->value); \
       
   555     slope = ((gdouble) convert (value2) - (gdouble) convert (value1)) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \
       
   556     \
       
   557     if (round) \
       
   558       *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \
       
   559     else \
       
   560       *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \
       
   561   } \
       
   562   else { \
       
   563     *ret = g_value_get_##vtype (&cp1->value); \
       
   564   } \
       
   565   *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \
       
   566   return TRUE; \
   579   return TRUE; \
   567 } \
   580 } \
   568 \
   581 \
   569 static gboolean \
   582 static gboolean \
   570 interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
   583 interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
   571 { \
   584 { \
   572   g##vtype ret; \
   585   g##type ret; \
   573   g_mutex_lock (self->lock); \
   586   g_mutex_lock (self->lock); \
   574   if (_interpolate_linear_get_##vtype (self, timestamp, &ret)) { \
   587   if (_interpolate_linear_get_##type (self, timestamp, &ret)) { \
   575     g_value_set_##vtype (value, ret); \
   588     g_value_set_##type (value, ret); \
   576     g_mutex_unlock (self->lock); \
   589     g_mutex_unlock (self->lock); \
   577     return TRUE; \
   590     return TRUE; \
   578   } \
   591   } \
   579   g_mutex_unlock (self->lock); \
   592   g_mutex_unlock (self->lock); \
   580   return FALSE; \
   593   return FALSE; \
   581 } \
   594 } \
   582 \
   595 \
   583 static gboolean \
   596 static gboolean \
   584 interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \
   597 interpolate_linear_get_##type##_value_array (GstInterpolationControlSource *self, \
   585     GstClockTime timestamp, GstValueArray * value_array) \
   598     GstClockTime timestamp, GstValueArray * value_array) \
   586 { \
   599 { \
   587   gint i; \
   600   gint i; \
   588   GstClockTime ts = timestamp; \
   601   GstClockTime ts = timestamp; \
   589   g##vtype *values = (g##vtype *) value_array->values; \
   602   g##type *values = (g##type *) value_array->values; \
   590   \
   603   \
   591   g_mutex_lock (self->lock); \
   604   g_mutex_lock (self->lock); \
   592   for(i = 0; i < value_array->nbsamples; i++) { \
   605   for(i = 0; i < value_array->nbsamples; i++) { \
   593     if (! _interpolate_linear_get_##vtype (self, ts, values)) { \
   606     if (! _interpolate_linear_get_##type (self, ts, values)) { \
   594       g_mutex_unlock (self->lock); \
   607       g_mutex_unlock (self->lock); \
   595       return FALSE; \
   608       return FALSE; \
   596     } \
   609     } \
   597     ts += value_array->sample_interval; \
   610     ts += value_array->sample_interval; \
   598     values++; \
   611     values++; \
   606 DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
   619 DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
   607 DEFINE_LINEAR_GET (long, TRUE, EMPTY);
   620 DEFINE_LINEAR_GET (long, TRUE, EMPTY);
   608 
   621 
   609 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
   622 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
   610 DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
   623 DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
   611 DEFINE_LINEAR_GET (uint64, TRUE, gst_guint64_to_gdouble);
   624 DEFINE_LINEAR_GET (uint64, TRUE, gst_util_guint64_to_gdouble);
   612 DEFINE_LINEAR_GET (float, FALSE, EMPTY);
   625 DEFINE_LINEAR_GET (float, FALSE, EMPTY);
   613 DEFINE_LINEAR_GET (double, FALSE, EMPTY);
   626 DEFINE_LINEAR_GET (double, FALSE, EMPTY);
   614 
   627 
   615 static GstInterpolateMethod interpolate_linear = {
   628 static GstInterpolateMethod interpolate_linear = {
   616   (GstControlSourceGetValue) interpolate_linear_get_int,
   629   (GstControlSourceGetValue) interpolate_linear_get_int,
   652  * o[1] p[1] q[1]    0    0
   665  * o[1] p[1] q[1]    0    0
   653  *    0 o[2] p[2] q[2]    .
   666  *    0 o[2] p[2] q[2]    .
   654  *    .    .    .    .    .
   667  *    .    .    .    .    .
   655  */
   668  */
   656 
   669 
   657 #define DEFINE_CUBIC_GET(vtype,round, convert) \
   670 #define DEFINE_CUBIC_GET(type,round, convert) \
   658 static void \
   671 static void \
   659 _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
   672 _interpolate_cubic_update_cache_##type (GstInterpolationControlSource *self) \
   660 { \
   673 { \
   661   gint i, n = self->priv->nvalues; \
   674   gint i, n = self->priv->nvalues; \
   662   gdouble *o = g_new0 (gdouble, n); \
   675   gdouble *o = g_new0 (gdouble, n); \
   663   gdouble *p = g_new0 (gdouble, n); \
   676   gdouble *p = g_new0 (gdouble, n); \
   664   gdouble *q = g_new0 (gdouble, n); \
   677   gdouble *q = g_new0 (gdouble, n); \
   665   \
   678   \
   666   gdouble *h = g_new0 (gdouble, n); \
   679   gdouble *h = g_new0 (gdouble, n); \
   667   gdouble *b = g_new0 (gdouble, n); \
   680   gdouble *b = g_new0 (gdouble, n); \
   668   gdouble *z = g_new0 (gdouble, n); \
   681   gdouble *z = g_new0 (gdouble, n); \
   669   \
   682   \
   670   GSequenceIter *iter; \
   683   GList *node; \
   671   GstControlPoint *cp; \
   684   GstControlPoint *cp; \
   672   GstClockTime x_prev, x, x_next; \
   685   GstClockTime x_prev, x, x_next; \
   673   g##vtype y_prev, y, y_next; \
   686   g##type y_prev, y, y_next; \
   674   \
   687   \
   675   /* Fill linear system of equations */ \
   688   /* Fill linear system of equations */ \
   676   iter = g_sequence_get_begin_iter (self->priv->values); \
   689   node = self->priv->values; \
   677   cp = g_sequence_get (iter); \
   690   cp = node->data; \
   678   x = cp->timestamp; \
   691   x = cp->timestamp; \
   679   y = g_value_get_##vtype (&cp->value); \
   692   y = g_value_get_##type (&cp->value); \
   680   \
   693   \
   681   p[0] = 1.0; \
   694   p[0] = 1.0; \
   682   \
   695   \
   683   iter = g_sequence_iter_next (iter); \
   696   node = node->next; \
   684   cp = g_sequence_get (iter); \
   697   cp = node->data; \
   685   x_next = cp->timestamp; \
   698   x_next = cp->timestamp; \
   686   y_next = g_value_get_##vtype (&cp->value); \
   699   y_next = g_value_get_##type (&cp->value); \
   687   h[0] = gst_guint64_to_gdouble (x_next - x); \
   700   h[0] = gst_util_guint64_to_gdouble (x_next - x); \
   688   \
   701   \
   689   for (i = 1; i < n-1; i++) { \
   702   for (i = 1; i < n-1; i++) { \
   690     /* Shuffle x and y values */ \
   703     /* Shuffle x and y values */ \
   691     x_prev = x; \
   704     x_prev = x; \
   692     y_prev = y; \
   705     y_prev = y; \
   693     x = x_next; \
   706     x = x_next; \
   694     y = y_next; \
   707     y = y_next; \
   695     iter = g_sequence_iter_next (iter); \
   708     node = node->next; \
   696     cp = g_sequence_get (iter); \
   709     cp = node->data; \
   697     x_next = cp->timestamp; \
   710     x_next = cp->timestamp; \
   698     y_next = g_value_get_##vtype (&cp->value); \
   711     y_next = g_value_get_##type (&cp->value); \
   699     \
   712     \
   700     h[i] = gst_guint64_to_gdouble (x_next - x); \
   713     h[i] = gst_util_guint64_to_gdouble (x_next - x); \
   701     o[i] = h[i-1]; \
   714     o[i] = h[i-1]; \
   702     p[i] = 2.0 * (h[i-1] + h[i]); \
   715     p[i] = 2.0 * (h[i-1] + h[i]); \
   703     q[i] = h[i]; \
   716     q[i] = h[i]; \
   704     b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
   717     b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
   705   } \
   718   } \
   717   for (i = n-2; i > 0; i--) \
   730   for (i = n-2; i > 0; i--) \
   718     z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
   731     z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
   719   \
   732   \
   720   /* Save cache next in the GstControlPoint */ \
   733   /* Save cache next in the GstControlPoint */ \
   721   \
   734   \
   722   iter = g_sequence_get_begin_iter (self->priv->values); \
   735   node = self->priv->values; \
   723   for (i = 0; i < n; i++) { \
   736   for (i = 0; i < n; i++) { \
   724     cp = g_sequence_get (iter); \
   737     cp = node->data; \
   725     cp->cache.cubic.h = h[i]; \
   738     cp->cache.cubic.h = h[i]; \
   726     cp->cache.cubic.z = z[i]; \
   739     cp->cache.cubic.z = z[i]; \
   727     iter = g_sequence_iter_next (iter); \
   740     node = node->next; \
   728   } \
   741   } \
   729   \
   742   \
   730   /* Free our temporary arrays */ \
   743   /* Free our temporary arrays */ \
   731   g_free (o); \
   744   g_free (o); \
   732   g_free (p); \
   745   g_free (p); \
   735   g_free (b); \
   748   g_free (b); \
   736   g_free (z); \
   749   g_free (z); \
   737 } \
   750 } \
   738 \
   751 \
   739 static inline gboolean \
   752 static inline gboolean \
   740 _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \
   753 _interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
   741 { \
   754 { \
   742   GSequenceIter *iter; \
   755   GList *node; \
   743   GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \
       
   744   \
   756   \
   745   if (self->priv->nvalues <= 2) \
   757   if (self->priv->nvalues <= 2) \
   746     return _interpolate_linear_get_##vtype (self, timestamp, ret); \
   758     return _interpolate_linear_get_##type (self, timestamp, ret); \
   747   \
   759   \
   748   if (!self->priv->valid_cache) { \
   760   if (!self->priv->valid_cache) { \
   749     _interpolate_cubic_update_cache_##vtype (self); \
   761     _interpolate_cubic_update_cache_##type (self); \
   750     self->priv->valid_cache = TRUE; \
   762     self->priv->valid_cache = TRUE; \
   751   } \
   763   } \
   752   \
   764   \
   753   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
   765   if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
   754   if (iter) { \
   766     GstControlPoint *cp1, *cp2; \
   755     cp1 = g_sequence_get (iter); \
   767     \
   756     iter = g_sequence_iter_next (iter); \
   768     cp1 = node->data; \
   757     iter = g_sequence_iter_is_end (iter) ? NULL : iter; \
   769     if ((node = g_list_next (node))) { \
       
   770       gdouble diff1, diff2; \
       
   771       g##type value1,value2; \
       
   772       gdouble out; \
       
   773       \
       
   774       cp2 = node->data; \
       
   775       \
       
   776       value1 = g_value_get_##type (&cp1->value); \
       
   777       value2 = g_value_get_##type (&cp2->value); \
       
   778       \
       
   779       diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \
       
   780       diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \
       
   781       \
       
   782       out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
       
   783       out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
       
   784       out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
       
   785       \
       
   786       if (round) \
       
   787         *ret = (g##type) (out + 0.5); \
       
   788       else \
       
   789         *ret = (g##type) out; \
       
   790     } \
       
   791     else { \
       
   792       *ret = g_value_get_##type (&cp1->value); \
       
   793     } \
   758   } else { \
   794   } else { \
   759     cp.timestamp = G_GUINT64_CONSTANT(0); \
   795     GValue *first = gst_interpolation_control_source_get_first_value (self); \
   760     g_value_init (&cp.value, self->priv->type); \
   796     if (!first) \
   761     g_value_copy (&self->priv->default_value, &cp.value); \
   797       return FALSE; \
   762     cp1 = &cp; \
   798     *ret = g_value_get_##type (first); \
   763     iter = g_sequence_get_begin_iter (self->priv->values); \
   799   } \
   764   } \
   800   *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
   765   if (iter) { \
       
   766     gdouble diff1, diff2; \
       
   767     g##vtype value1,value2; \
       
   768     gdouble out; \
       
   769     \
       
   770     cp2 = g_sequence_get (iter); \
       
   771     \
       
   772     value1 = g_value_get_##vtype (&cp1->value); \
       
   773     value2 = g_value_get_##vtype (&cp2->value); \
       
   774     \
       
   775     diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \
       
   776     diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \
       
   777     \
       
   778     out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
       
   779     out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
       
   780     out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
       
   781     \
       
   782     if (round) \
       
   783       *ret = (g##vtype) (out + 0.5); \
       
   784     else \
       
   785       *ret = (g##vtype) out; \
       
   786   } \
       
   787   else { \
       
   788     *ret = g_value_get_##vtype (&cp1->value); \
       
   789   } \
       
   790   *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \
       
   791   return TRUE; \
   801   return TRUE; \
   792 } \
   802 } \
   793 \
   803 \
   794 static gboolean \
   804 static gboolean \
   795 interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
   805 interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
   796 { \
   806 { \
   797   g##vtype ret; \
   807   g##type ret; \
   798   g_mutex_lock (self->lock); \
   808   g_mutex_lock (self->lock); \
   799   if (_interpolate_cubic_get_##vtype (self, timestamp, &ret)) { \
   809   if (_interpolate_cubic_get_##type (self, timestamp, &ret)) { \
   800     g_value_set_##vtype (value, ret); \
   810     g_value_set_##type (value, ret); \
   801     g_mutex_unlock (self->lock); \
   811     g_mutex_unlock (self->lock); \
   802     return TRUE; \
   812     return TRUE; \
   803   } \
   813   } \
   804   g_mutex_unlock (self->lock); \
   814   g_mutex_unlock (self->lock); \
   805   return FALSE; \
   815   return FALSE; \
   806 } \
   816 } \
   807 \
   817 \
   808 static gboolean \
   818 static gboolean \
   809 interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \
   819 interpolate_cubic_get_##type##_value_array (GstInterpolationControlSource *self, \
   810     GstClockTime timestamp, GstValueArray * value_array) \
   820     GstClockTime timestamp, GstValueArray * value_array) \
   811 { \
   821 { \
   812   gint i; \
   822   gint i; \
   813   GstClockTime ts = timestamp; \
   823   GstClockTime ts = timestamp; \
   814   g##vtype *values = (g##vtype *) value_array->values; \
   824   g##type *values = (g##type *) value_array->values; \
   815   \
   825   \
   816   g_mutex_lock (self->lock); \
   826   g_mutex_lock (self->lock); \
   817   for(i = 0; i < value_array->nbsamples; i++) { \
   827   for(i = 0; i < value_array->nbsamples; i++) { \
   818     if (! _interpolate_cubic_get_##vtype (self, ts, values)) { \
   828     if (! _interpolate_cubic_get_##type (self, ts, values)) { \
   819       g_mutex_unlock (self->lock); \
   829       g_mutex_unlock (self->lock); \
   820       return FALSE; \
   830       return FALSE; \
   821     } \
   831     } \
   822     ts += value_array->sample_interval; \
   832     ts += value_array->sample_interval; \
   823     values++; \
   833     values++; \
   831 DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
   841 DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
   832 DEFINE_CUBIC_GET (long, TRUE, EMPTY);
   842 DEFINE_CUBIC_GET (long, TRUE, EMPTY);
   833 
   843 
   834 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
   844 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
   835 DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
   845 DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
   836 DEFINE_CUBIC_GET (uint64, TRUE, gst_guint64_to_gdouble);
   846 DEFINE_CUBIC_GET (uint64, TRUE, gst_util_guint64_to_gdouble);
   837 DEFINE_CUBIC_GET (float, FALSE, EMPTY);
   847 DEFINE_CUBIC_GET (float, FALSE, EMPTY);
   838 DEFINE_CUBIC_GET (double, FALSE, EMPTY);
   848 DEFINE_CUBIC_GET (double, FALSE, EMPTY);
   839 
   849 
   840 static GstInterpolateMethod interpolate_cubic = {
   850 static GstInterpolateMethod interpolate_cubic = {
   841   (GstControlSourceGetValue) interpolate_cubic_get_int,
   851   (GstControlSourceGetValue) interpolate_cubic_get_int,
   860   (GstControlSourceGetValueArray) NULL,
   870   (GstControlSourceGetValueArray) NULL,
   861   (GstControlSourceGetValue) NULL,
   871   (GstControlSourceGetValue) NULL,
   862   (GstControlSourceGetValueArray) NULL
   872   (GstControlSourceGetValueArray) NULL
   863 };
   873 };
   864 
   874 
       
   875 
   865 /*  register all interpolation methods */
   876 /*  register all interpolation methods */
   866 GstInterpolateMethod *priv_gst_interpolation_methods[] = {
   877 GstInterpolateMethod *interpolation_methods[] = {
   867   &interpolate_none,
   878   &interpolate_none,
   868   &interpolate_trigger,
   879   &interpolate_trigger,
   869   &interpolate_linear,
   880   &interpolate_linear,
   870   &interpolate_cubic,
   881   &interpolate_cubic,
   871   &interpolate_cubic
   882   &interpolate_cubic
   872 };
   883 };
   873 
   884 
   874 guint priv_gst_num_interpolation_methods =
   885 guint num_interpolation_methods = G_N_ELEMENTS (interpolation_methods);
   875 G_N_ELEMENTS (priv_gst_interpolation_methods);