gstreamer_core/libs/gst/controller/gstinterpolation.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  *
       
     3  * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
       
     4  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
       
     5  *
       
     6  * gstinterpolation.c: Interpolation methods for dynamic properties
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 
       
    24 #ifdef HAVE_CONFIG_H
       
    25 #  include "config.h"
       
    26 #endif
       
    27 
       
    28 #include "gstinterpolationcontrolsource.h"
       
    29 #include "gstinterpolationcontrolsourceprivate.h"
       
    30 
       
    31 #ifdef __SYMBIAN32__
       
    32 #include <glib_global.h>
       
    33 #include <gobject_global.h>
       
    34 
       
    35 #endif
       
    36 
       
    37 #define GST_CAT_DEFAULT controller_debug
       
    38 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
       
    39 
       
    40 #define EMPTY(x) (x)
       
    41 
       
    42 /* common helper */
       
    43 
       
    44 /*
       
    45  * gst_interpolation_control_source_find_control_point_node:
       
    46  * @self: the interpolation control source to search in
       
    47  * @timestamp: the search key
       
    48  *
       
    49  * Find last value before given timestamp in control point list.
       
    50  *
       
    51  * Returns: the found #GList node or %NULL
       
    52  */
       
    53 static GList *gst_interpolation_control_source_find_control_point_node
       
    54     (GstInterpolationControlSource * self, GstClockTime timestamp)
       
    55 {
       
    56   GList *prev_node = g_list_last (self->priv->values);
       
    57   GList *node;
       
    58   GstControlPoint *cp;
       
    59 
       
    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 {
       
   106     return NULL;
       
   107   }
       
   108 }
       
   109 
       
   110 /*  steps-like (no-)interpolation, default */
       
   111 /*  just returns the value for the most recent key-frame */
       
   112 
       
   113 #define DEFINE_NONE_GET(type) \
       
   114 static inline GValue * \
       
   115 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
       
   116 { \
       
   117   GValue *ret; \
       
   118   GList *node; \
       
   119   \
       
   120   if ((node = \
       
   121           gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
       
   122     GstControlPoint *cp = node->data; \
       
   123     g##type ret_val = g_value_get_##type (&cp->value); \
       
   124     \
       
   125     if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
       
   126       ret = &self->priv->minimum_value; \
       
   127     else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
       
   128       ret = &self->priv->maximum_value; \
       
   129     else \
       
   130       ret = &cp->value; \
       
   131   } else { \
       
   132     ret = gst_interpolation_control_source_get_first_value (self); \
       
   133   } \
       
   134   return ret; \
       
   135 } \
       
   136 \
       
   137 static gboolean \
       
   138 interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
       
   139 { \
       
   140   GValue *ret; \
       
   141   g_mutex_lock (self->lock); \
       
   142   \
       
   143   ret = _interpolate_none_get_##type (self, timestamp); \
       
   144   if (!ret) { \
       
   145     g_mutex_unlock (self->lock); \
       
   146     return FALSE; \
       
   147   } \
       
   148   g_value_copy (ret, value); \
       
   149   g_mutex_unlock (self->lock); \
       
   150   return TRUE; \
       
   151 } \
       
   152 \
       
   153 static gboolean \
       
   154 interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \
       
   155     GstClockTime timestamp, GstValueArray * value_array) \
       
   156 { \
       
   157   gint i; \
       
   158   GstClockTime ts = timestamp; \
       
   159   g##type *values = (g##type *) value_array->values; \
       
   160   GValue *ret; \
       
   161   \
       
   162   g_mutex_lock (self->lock); \
       
   163   for(i = 0; i < value_array->nbsamples; i++) { \
       
   164     ret = _interpolate_none_get_##type (self, timestamp); \
       
   165     if (!ret) { \
       
   166       g_mutex_unlock (self->lock); \
       
   167       return FALSE; \
       
   168     } \
       
   169     *values = g_value_get_##type (ret); \
       
   170     ts += value_array->sample_interval; \
       
   171     values++; \
       
   172   } \
       
   173   g_mutex_unlock (self->lock); \
       
   174   return TRUE; \
       
   175 }
       
   176 
       
   177 
       
   178 DEFINE_NONE_GET (int);
       
   179 DEFINE_NONE_GET (uint);
       
   180 DEFINE_NONE_GET (long);
       
   181 
       
   182 DEFINE_NONE_GET (ulong);
       
   183 DEFINE_NONE_GET (int64);
       
   184 DEFINE_NONE_GET (uint64);
       
   185 DEFINE_NONE_GET (float);
       
   186 DEFINE_NONE_GET (double);
       
   187 
       
   188 static inline GValue *
       
   189 _interpolate_none_get (GstInterpolationControlSource * self,
       
   190     GstClockTime timestamp)
       
   191 {
       
   192   GList *node;
       
   193   GValue *ret;
       
   194 
       
   195   if ((node =
       
   196           gst_interpolation_control_source_find_control_point_node (self,
       
   197               timestamp))) {
       
   198     GstControlPoint *cp = node->data;
       
   199 
       
   200     ret = &cp->value;
       
   201   } else {
       
   202     ret = gst_interpolation_control_source_get_first_value (self);
       
   203   }
       
   204   return ret;
       
   205 }
       
   206 
       
   207 static gboolean
       
   208 interpolate_none_get (GstInterpolationControlSource * self,
       
   209     GstClockTime timestamp, GValue * value)
       
   210 {
       
   211   GValue *ret;
       
   212 
       
   213   g_mutex_lock (self->lock);
       
   214   ret = _interpolate_none_get (self, timestamp);
       
   215 
       
   216   if (!ret) {
       
   217     g_mutex_unlock (self->lock);
       
   218     return FALSE;
       
   219   }
       
   220 
       
   221   g_value_copy (ret, value);
       
   222   g_mutex_unlock (self->lock);
       
   223   return TRUE;
       
   224 }
       
   225 
       
   226 static gboolean
       
   227 interpolate_none_get_boolean_value_array (GstInterpolationControlSource * self,
       
   228     GstClockTime timestamp, GstValueArray * value_array)
       
   229 {
       
   230   gint i;
       
   231   GstClockTime ts = timestamp;
       
   232   gboolean *values = (gboolean *) value_array->values;
       
   233   GValue *ret;
       
   234 
       
   235   g_mutex_lock (self->lock);
       
   236   for (i = 0; i < value_array->nbsamples; i++) {
       
   237     ret = _interpolate_none_get (self, timestamp);
       
   238     if (!ret) {
       
   239       g_mutex_unlock (self->lock);
       
   240       return FALSE;
       
   241     }
       
   242     *values = g_value_get_boolean (ret);
       
   243     ts += value_array->sample_interval;
       
   244     values++;
       
   245   }
       
   246   g_mutex_unlock (self->lock);
       
   247   return TRUE;
       
   248 }
       
   249 
       
   250 static gboolean
       
   251 interpolate_none_get_enum_value_array (GstInterpolationControlSource * self,
       
   252     GstClockTime timestamp, GstValueArray * value_array)
       
   253 {
       
   254   gint i;
       
   255   GstClockTime ts = timestamp;
       
   256   gint *values = (gint *) value_array->values;
       
   257   GValue *ret;
       
   258 
       
   259   g_mutex_lock (self->lock);
       
   260   for (i = 0; i < value_array->nbsamples; i++) {
       
   261     ret = _interpolate_none_get (self, timestamp);
       
   262     if (!ret) {
       
   263       g_mutex_unlock (self->lock);
       
   264       return FALSE;
       
   265     }
       
   266     *values = g_value_get_enum (ret);
       
   267     ts += value_array->sample_interval;
       
   268     values++;
       
   269   }
       
   270   g_mutex_unlock (self->lock);
       
   271   return TRUE;
       
   272 }
       
   273 
       
   274 static gboolean
       
   275 interpolate_none_get_string_value_array (GstInterpolationControlSource * self,
       
   276     GstClockTime timestamp, GstValueArray * value_array)
       
   277 {
       
   278   gint i;
       
   279   GstClockTime ts = timestamp;
       
   280   gchar **values = (gchar **) value_array->values;
       
   281   GValue *ret;
       
   282 
       
   283   g_mutex_lock (self->lock);
       
   284   for (i = 0; i < value_array->nbsamples; i++) {
       
   285     ret = _interpolate_none_get (self, timestamp);
       
   286     if (!ret) {
       
   287       g_mutex_unlock (self->lock);
       
   288       return FALSE;
       
   289     }
       
   290     *values = (gchar *) g_value_get_string (ret);
       
   291     ts += value_array->sample_interval;
       
   292     values++;
       
   293   }
       
   294   g_mutex_unlock (self->lock);
       
   295   return TRUE;
       
   296 }
       
   297 
       
   298 static GstInterpolateMethod interpolate_none = {
       
   299   (GstControlSourceGetValue) interpolate_none_get_int,
       
   300   (GstControlSourceGetValueArray) interpolate_none_get_int_value_array,
       
   301   (GstControlSourceGetValue) interpolate_none_get_uint,
       
   302   (GstControlSourceGetValueArray) interpolate_none_get_uint_value_array,
       
   303   (GstControlSourceGetValue) interpolate_none_get_long,
       
   304   (GstControlSourceGetValueArray) interpolate_none_get_long_value_array,
       
   305   (GstControlSourceGetValue) interpolate_none_get_ulong,
       
   306   (GstControlSourceGetValueArray) interpolate_none_get_ulong_value_array,
       
   307   (GstControlSourceGetValue) interpolate_none_get_int64,
       
   308   (GstControlSourceGetValueArray) interpolate_none_get_int64_value_array,
       
   309   (GstControlSourceGetValue) interpolate_none_get_uint64,
       
   310   (GstControlSourceGetValueArray) interpolate_none_get_uint64_value_array,
       
   311   (GstControlSourceGetValue) interpolate_none_get_float,
       
   312   (GstControlSourceGetValueArray) interpolate_none_get_float_value_array,
       
   313   (GstControlSourceGetValue) interpolate_none_get_double,
       
   314   (GstControlSourceGetValueArray) interpolate_none_get_double_value_array,
       
   315   (GstControlSourceGetValue) interpolate_none_get,
       
   316   (GstControlSourceGetValueArray) interpolate_none_get_boolean_value_array,
       
   317   (GstControlSourceGetValue) interpolate_none_get,
       
   318   (GstControlSourceGetValueArray) interpolate_none_get_enum_value_array,
       
   319   (GstControlSourceGetValue) interpolate_none_get,
       
   320   (GstControlSourceGetValueArray) interpolate_none_get_string_value_array
       
   321 };
       
   322 
       
   323 /*  returns the default value of the property, except for times with specific values */
       
   324 /*  needed for one-shot events, such as notes and triggers */
       
   325 
       
   326 #define DEFINE_TRIGGER_GET(type) \
       
   327 static inline GValue * \
       
   328 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \
       
   329 { \
       
   330   GList *node; \
       
   331   GstControlPoint *cp; \
       
   332   \
       
   333   /* check if there is a value at the registered timestamp */ \
       
   334   if ((node = \
       
   335           gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
       
   336     cp = node->data; \
       
   337     if (timestamp == cp->timestamp) { \
       
   338       g##type ret = g_value_get_##type (&cp->value); \
       
   339       if (g_value_get_##type (&self->priv->minimum_value) > ret) \
       
   340         return &self->priv->minimum_value; \
       
   341       else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
       
   342         return &self->priv->maximum_value; \
       
   343       else \
       
   344         return &cp->value; \
       
   345     } \
       
   346   } \
       
   347   \
       
   348   if (self->priv->nvalues > 0) \
       
   349     return &self->priv->default_value; \
       
   350   else \
       
   351     return NULL; \
       
   352 } \
       
   353 \
       
   354 static gboolean \
       
   355 interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
       
   356 { \
       
   357   GValue *ret; \
       
   358   g_mutex_lock (self->lock); \
       
   359   ret = _interpolate_trigger_get_##type (self, timestamp); \
       
   360   if (!ret) { \
       
   361     g_mutex_unlock (self->lock); \
       
   362     return FALSE; \
       
   363   } \
       
   364   g_value_copy (ret, value); \
       
   365   g_mutex_unlock (self->lock); \
       
   366   return TRUE; \
       
   367 } \
       
   368 \
       
   369 static gboolean \
       
   370 interpolate_trigger_get_##type##_value_array (GstInterpolationControlSource *self, \
       
   371     GstClockTime timestamp, GstValueArray * value_array) \
       
   372 { \
       
   373   gint i; \
       
   374   GstClockTime ts = timestamp; \
       
   375   g##type *values = (g##type *) value_array->values; \
       
   376   GValue *ret; \
       
   377   \
       
   378   g_mutex_lock (self->lock); \
       
   379   for(i = 0; i < value_array->nbsamples; i++) { \
       
   380     ret = _interpolate_trigger_get_##type (self, timestamp); \
       
   381     if (!ret) { \
       
   382       g_mutex_unlock (self->lock); \
       
   383       return FALSE; \
       
   384     } \
       
   385     *values = g_value_get_##type (ret); \
       
   386     ts += value_array->sample_interval; \
       
   387     values++; \
       
   388   } \
       
   389   g_mutex_unlock (self->lock); \
       
   390   return TRUE; \
       
   391 }
       
   392 
       
   393 
       
   394 DEFINE_TRIGGER_GET (int);
       
   395 
       
   396 DEFINE_TRIGGER_GET (uint);
       
   397 DEFINE_TRIGGER_GET (long);
       
   398 
       
   399 DEFINE_TRIGGER_GET (ulong);
       
   400 DEFINE_TRIGGER_GET (int64);
       
   401 DEFINE_TRIGGER_GET (uint64);
       
   402 DEFINE_TRIGGER_GET (float);
       
   403 DEFINE_TRIGGER_GET (double);
       
   404 
       
   405 static inline GValue *
       
   406 _interpolate_trigger_get (GstInterpolationControlSource * self,
       
   407     GstClockTime timestamp)
       
   408 {
       
   409   GList *node;
       
   410   GstControlPoint *cp;
       
   411 
       
   412   /* check if there is a value at the registered timestamp */
       
   413   if ((node =
       
   414           gst_interpolation_control_source_find_control_point_node (self,
       
   415               timestamp))) {
       
   416     cp = node->data;
       
   417     if (timestamp == cp->timestamp) {
       
   418       return &cp->value;
       
   419     }
       
   420   }
       
   421   if (self->priv->nvalues > 0)
       
   422     return &self->priv->default_value;
       
   423   else
       
   424     return NULL;
       
   425 }
       
   426 
       
   427 static gboolean
       
   428 interpolate_trigger_get (GstInterpolationControlSource * self,
       
   429     GstClockTime timestamp, GValue * value)
       
   430 {
       
   431   GValue *ret;
       
   432 
       
   433   g_mutex_lock (self->lock);
       
   434   ret = _interpolate_trigger_get (self, timestamp);
       
   435   if (!ret) {
       
   436     g_mutex_unlock (self->lock);
       
   437     return FALSE;
       
   438   }
       
   439   g_value_copy (ret, value);
       
   440   g_mutex_unlock (self->lock);
       
   441   return TRUE;
       
   442 }
       
   443 
       
   444 static gboolean
       
   445 interpolate_trigger_get_boolean_value_array (GstInterpolationControlSource *
       
   446     self, GstClockTime timestamp, GstValueArray * value_array)
       
   447 {
       
   448   gint i;
       
   449   GstClockTime ts = timestamp;
       
   450   gint *values = (gint *) value_array->values;
       
   451   GValue *ret;
       
   452 
       
   453   g_mutex_lock (self->lock);
       
   454   for (i = 0; i < value_array->nbsamples; i++) {
       
   455     ret = _interpolate_trigger_get (self, timestamp);
       
   456     if (!ret) {
       
   457       g_mutex_unlock (self->lock);
       
   458       return FALSE;
       
   459     }
       
   460     *values = g_value_get_boolean (ret);
       
   461     ts += value_array->sample_interval;
       
   462     values++;
       
   463   }
       
   464   g_mutex_unlock (self->lock);
       
   465   return TRUE;
       
   466 }
       
   467 
       
   468 static gboolean
       
   469 interpolate_trigger_get_enum_value_array (GstInterpolationControlSource * self,
       
   470     GstClockTime timestamp, GstValueArray * value_array)
       
   471 {
       
   472   gint i;
       
   473   GstClockTime ts = timestamp;
       
   474   gint *values = (gint *) value_array->values;
       
   475   GValue *ret;
       
   476 
       
   477   g_mutex_lock (self->lock);
       
   478   for (i = 0; i < value_array->nbsamples; i++) {
       
   479     ret = _interpolate_trigger_get (self, timestamp);
       
   480     if (!ret) {
       
   481       g_mutex_unlock (self->lock);
       
   482       return FALSE;
       
   483     }
       
   484     *values = g_value_get_enum (ret);
       
   485     ts += value_array->sample_interval;
       
   486     values++;
       
   487   }
       
   488   g_mutex_unlock (self->lock);
       
   489   return TRUE;
       
   490 }
       
   491 
       
   492 static gboolean
       
   493 interpolate_trigger_get_string_value_array (GstInterpolationControlSource *
       
   494     self, GstClockTime timestamp, GstValueArray * value_array)
       
   495 {
       
   496   gint i;
       
   497   GstClockTime ts = timestamp;
       
   498   gchar **values = (gchar **) value_array->values;
       
   499   GValue *ret;
       
   500 
       
   501   g_mutex_lock (self->lock);
       
   502   for (i = 0; i < value_array->nbsamples; i++) {
       
   503     ret = _interpolate_trigger_get (self, timestamp);
       
   504     if (!ret) {
       
   505       g_mutex_unlock (self->lock);
       
   506       return FALSE;
       
   507     }
       
   508     *values = (gchar *) g_value_get_string (ret);
       
   509     ts += value_array->sample_interval;
       
   510     values++;
       
   511   }
       
   512   g_mutex_unlock (self->lock);
       
   513   return TRUE;
       
   514 }
       
   515 
       
   516 static GstInterpolateMethod interpolate_trigger = {
       
   517   (GstControlSourceGetValue) interpolate_trigger_get_int,
       
   518   (GstControlSourceGetValueArray) interpolate_trigger_get_int_value_array,
       
   519   (GstControlSourceGetValue) interpolate_trigger_get_uint,
       
   520   (GstControlSourceGetValueArray) interpolate_trigger_get_uint_value_array,
       
   521   (GstControlSourceGetValue) interpolate_trigger_get_long,
       
   522   (GstControlSourceGetValueArray) interpolate_trigger_get_long_value_array,
       
   523   (GstControlSourceGetValue) interpolate_trigger_get_ulong,
       
   524   (GstControlSourceGetValueArray) interpolate_trigger_get_ulong_value_array,
       
   525   (GstControlSourceGetValue) interpolate_trigger_get_int64,
       
   526   (GstControlSourceGetValueArray) interpolate_trigger_get_int64_value_array,
       
   527   (GstControlSourceGetValue) interpolate_trigger_get_uint64,
       
   528   (GstControlSourceGetValueArray) interpolate_trigger_get_uint64_value_array,
       
   529   (GstControlSourceGetValue) interpolate_trigger_get_float,
       
   530   (GstControlSourceGetValueArray) interpolate_trigger_get_float_value_array,
       
   531   (GstControlSourceGetValue) interpolate_trigger_get_double,
       
   532   (GstControlSourceGetValueArray) interpolate_trigger_get_double_value_array,
       
   533   (GstControlSourceGetValue) interpolate_trigger_get,
       
   534   (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array,
       
   535   (GstControlSourceGetValue) interpolate_trigger_get,
       
   536   (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array,
       
   537   (GstControlSourceGetValue) interpolate_trigger_get,
       
   538   (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array
       
   539 };
       
   540 
       
   541 /*  linear interpolation */
       
   542 /*  smoothes inbetween values */
       
   543 
       
   544 #define DEFINE_LINEAR_GET(type,round,convert) \
       
   545 static inline gboolean \
       
   546 _interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
       
   547 { \
       
   548   GList *node; \
       
   549   \
       
   550   if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
       
   551     GstControlPoint *cp1, *cp2; \
       
   552     \
       
   553     cp1 = node->data; \
       
   554     if ((node = g_list_next (node))) { \
       
   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     } \
       
   572   } else { \
       
   573     GValue *first = gst_interpolation_control_source_get_first_value (self); \
       
   574     if (!first) \
       
   575       return FALSE; \
       
   576     *ret = g_value_get_##type (first); \
       
   577   } \
       
   578   *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
       
   579   return TRUE; \
       
   580 } \
       
   581 \
       
   582 static gboolean \
       
   583 interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
       
   584 { \
       
   585   g##type ret; \
       
   586   g_mutex_lock (self->lock); \
       
   587   if (_interpolate_linear_get_##type (self, timestamp, &ret)) { \
       
   588     g_value_set_##type (value, ret); \
       
   589     g_mutex_unlock (self->lock); \
       
   590     return TRUE; \
       
   591   } \
       
   592   g_mutex_unlock (self->lock); \
       
   593   return FALSE; \
       
   594 } \
       
   595 \
       
   596 static gboolean \
       
   597 interpolate_linear_get_##type##_value_array (GstInterpolationControlSource *self, \
       
   598     GstClockTime timestamp, GstValueArray * value_array) \
       
   599 { \
       
   600   gint i; \
       
   601   GstClockTime ts = timestamp; \
       
   602   g##type *values = (g##type *) value_array->values; \
       
   603   \
       
   604   g_mutex_lock (self->lock); \
       
   605   for(i = 0; i < value_array->nbsamples; i++) { \
       
   606     if (! _interpolate_linear_get_##type (self, ts, values)) { \
       
   607       g_mutex_unlock (self->lock); \
       
   608       return FALSE; \
       
   609     } \
       
   610     ts += value_array->sample_interval; \
       
   611     values++; \
       
   612   } \
       
   613   g_mutex_unlock (self->lock); \
       
   614   return TRUE; \
       
   615 }
       
   616 
       
   617 DEFINE_LINEAR_GET (int, TRUE, EMPTY);
       
   618 
       
   619 DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
       
   620 DEFINE_LINEAR_GET (long, TRUE, EMPTY);
       
   621 
       
   622 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
       
   623 DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
       
   624 DEFINE_LINEAR_GET (uint64, TRUE, gst_util_guint64_to_gdouble);
       
   625 DEFINE_LINEAR_GET (float, FALSE, EMPTY);
       
   626 DEFINE_LINEAR_GET (double, FALSE, EMPTY);
       
   627 
       
   628 static GstInterpolateMethod interpolate_linear = {
       
   629   (GstControlSourceGetValue) interpolate_linear_get_int,
       
   630   (GstControlSourceGetValueArray) interpolate_linear_get_int_value_array,
       
   631   (GstControlSourceGetValue) interpolate_linear_get_uint,
       
   632   (GstControlSourceGetValueArray) interpolate_linear_get_uint_value_array,
       
   633   (GstControlSourceGetValue) interpolate_linear_get_long,
       
   634   (GstControlSourceGetValueArray) interpolate_linear_get_long_value_array,
       
   635   (GstControlSourceGetValue) interpolate_linear_get_ulong,
       
   636   (GstControlSourceGetValueArray) interpolate_linear_get_ulong_value_array,
       
   637   (GstControlSourceGetValue) interpolate_linear_get_int64,
       
   638   (GstControlSourceGetValueArray) interpolate_linear_get_int64_value_array,
       
   639   (GstControlSourceGetValue) interpolate_linear_get_uint64,
       
   640   (GstControlSourceGetValueArray) interpolate_linear_get_uint64_value_array,
       
   641   (GstControlSourceGetValue) interpolate_linear_get_float,
       
   642   (GstControlSourceGetValueArray) interpolate_linear_get_float_value_array,
       
   643   (GstControlSourceGetValue) interpolate_linear_get_double,
       
   644   (GstControlSourceGetValueArray) interpolate_linear_get_double_value_array,
       
   645   (GstControlSourceGetValue) NULL,
       
   646   (GstControlSourceGetValueArray) NULL,
       
   647   (GstControlSourceGetValue) NULL,
       
   648   (GstControlSourceGetValueArray) NULL,
       
   649   (GstControlSourceGetValue) NULL,
       
   650   (GstControlSourceGetValueArray) NULL
       
   651 };
       
   652 
       
   653 /*  square interpolation */
       
   654 
       
   655 /*  cubic interpolation */
       
   656 
       
   657 /* The following functions implement a natural cubic spline interpolator.
       
   658  * For details look at http://en.wikipedia.org/wiki/Spline_interpolation
       
   659  *
       
   660  * Instead of using a real matrix with n^2 elements for the linear system
       
   661  * of equations we use three arrays o, p, q to hold the tridiagonal matrix
       
   662  * as following to save memory:
       
   663  *
       
   664  * p[0] q[0]    0    0    0
       
   665  * o[1] p[1] q[1]    0    0
       
   666  *    0 o[2] p[2] q[2]    .
       
   667  *    .    .    .    .    .
       
   668  */
       
   669 
       
   670 #define DEFINE_CUBIC_GET(type,round, convert) \
       
   671 static void \
       
   672 _interpolate_cubic_update_cache_##type (GstInterpolationControlSource *self) \
       
   673 { \
       
   674   gint i, n = self->priv->nvalues; \
       
   675   gdouble *o = g_new0 (gdouble, n); \
       
   676   gdouble *p = g_new0 (gdouble, n); \
       
   677   gdouble *q = g_new0 (gdouble, n); \
       
   678   \
       
   679   gdouble *h = g_new0 (gdouble, n); \
       
   680   gdouble *b = g_new0 (gdouble, n); \
       
   681   gdouble *z = g_new0 (gdouble, n); \
       
   682   \
       
   683   GList *node; \
       
   684   GstControlPoint *cp; \
       
   685   GstClockTime x_prev, x, x_next; \
       
   686   g##type y_prev, y, y_next; \
       
   687   \
       
   688   /* Fill linear system of equations */ \
       
   689   node = self->priv->values; \
       
   690   cp = node->data; \
       
   691   x = cp->timestamp; \
       
   692   y = g_value_get_##type (&cp->value); \
       
   693   \
       
   694   p[0] = 1.0; \
       
   695   \
       
   696   node = node->next; \
       
   697   cp = node->data; \
       
   698   x_next = cp->timestamp; \
       
   699   y_next = g_value_get_##type (&cp->value); \
       
   700   h[0] = gst_util_guint64_to_gdouble (x_next - x); \
       
   701   \
       
   702   for (i = 1; i < n-1; i++) { \
       
   703     /* Shuffle x and y values */ \
       
   704     x_prev = x; \
       
   705     y_prev = y; \
       
   706     x = x_next; \
       
   707     y = y_next; \
       
   708     node = node->next; \
       
   709     cp = node->data; \
       
   710     x_next = cp->timestamp; \
       
   711     y_next = g_value_get_##type (&cp->value); \
       
   712     \
       
   713     h[i] = gst_util_guint64_to_gdouble (x_next - x); \
       
   714     o[i] = h[i-1]; \
       
   715     p[i] = 2.0 * (h[i-1] + h[i]); \
       
   716     q[i] = h[i]; \
       
   717     b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
       
   718   } \
       
   719   p[n-1] = 1.0; \
       
   720   \
       
   721   /* Use Gauss elimination to set everything below the \
       
   722    * diagonal to zero */ \
       
   723   for (i = 1; i < n-1; i++) { \
       
   724     gdouble a = o[i] / p[i-1]; \
       
   725     p[i] -= a * q[i-1]; \
       
   726     b[i] -= a * b[i-1]; \
       
   727   } \
       
   728   \
       
   729   /* Solve everything else from bottom to top */ \
       
   730   for (i = n-2; i > 0; i--) \
       
   731     z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
       
   732   \
       
   733   /* Save cache next in the GstControlPoint */ \
       
   734   \
       
   735   node = self->priv->values; \
       
   736   for (i = 0; i < n; i++) { \
       
   737     cp = node->data; \
       
   738     cp->cache.cubic.h = h[i]; \
       
   739     cp->cache.cubic.z = z[i]; \
       
   740     node = node->next; \
       
   741   } \
       
   742   \
       
   743   /* Free our temporary arrays */ \
       
   744   g_free (o); \
       
   745   g_free (p); \
       
   746   g_free (q); \
       
   747   g_free (h); \
       
   748   g_free (b); \
       
   749   g_free (z); \
       
   750 } \
       
   751 \
       
   752 static inline gboolean \
       
   753 _interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \
       
   754 { \
       
   755   GList *node; \
       
   756   \
       
   757   if (self->priv->nvalues <= 2) \
       
   758     return _interpolate_linear_get_##type (self, timestamp, ret); \
       
   759   \
       
   760   if (!self->priv->valid_cache) { \
       
   761     _interpolate_cubic_update_cache_##type (self); \
       
   762     self->priv->valid_cache = TRUE; \
       
   763   } \
       
   764   \
       
   765   if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \
       
   766     GstControlPoint *cp1, *cp2; \
       
   767     \
       
   768     cp1 = node->data; \
       
   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     } \
       
   794   } else { \
       
   795     GValue *first = gst_interpolation_control_source_get_first_value (self); \
       
   796     if (!first) \
       
   797       return FALSE; \
       
   798     *ret = g_value_get_##type (first); \
       
   799   } \
       
   800   *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \
       
   801   return TRUE; \
       
   802 } \
       
   803 \
       
   804 static gboolean \
       
   805 interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
       
   806 { \
       
   807   g##type ret; \
       
   808   g_mutex_lock (self->lock); \
       
   809   if (_interpolate_cubic_get_##type (self, timestamp, &ret)) { \
       
   810     g_value_set_##type (value, ret); \
       
   811     g_mutex_unlock (self->lock); \
       
   812     return TRUE; \
       
   813   } \
       
   814   g_mutex_unlock (self->lock); \
       
   815   return FALSE; \
       
   816 } \
       
   817 \
       
   818 static gboolean \
       
   819 interpolate_cubic_get_##type##_value_array (GstInterpolationControlSource *self, \
       
   820     GstClockTime timestamp, GstValueArray * value_array) \
       
   821 { \
       
   822   gint i; \
       
   823   GstClockTime ts = timestamp; \
       
   824   g##type *values = (g##type *) value_array->values; \
       
   825   \
       
   826   g_mutex_lock (self->lock); \
       
   827   for(i = 0; i < value_array->nbsamples; i++) { \
       
   828     if (! _interpolate_cubic_get_##type (self, ts, values)) { \
       
   829       g_mutex_unlock (self->lock); \
       
   830       return FALSE; \
       
   831     } \
       
   832     ts += value_array->sample_interval; \
       
   833     values++; \
       
   834   } \
       
   835   g_mutex_unlock (self->lock); \
       
   836   return TRUE; \
       
   837 }
       
   838 
       
   839 DEFINE_CUBIC_GET (int, TRUE, EMPTY);
       
   840 
       
   841 DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
       
   842 DEFINE_CUBIC_GET (long, TRUE, EMPTY);
       
   843 
       
   844 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
       
   845 DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
       
   846 DEFINE_CUBIC_GET (uint64, TRUE, gst_util_guint64_to_gdouble);
       
   847 DEFINE_CUBIC_GET (float, FALSE, EMPTY);
       
   848 DEFINE_CUBIC_GET (double, FALSE, EMPTY);
       
   849 
       
   850 static GstInterpolateMethod interpolate_cubic = {
       
   851   (GstControlSourceGetValue) interpolate_cubic_get_int,
       
   852   (GstControlSourceGetValueArray) interpolate_cubic_get_int_value_array,
       
   853   (GstControlSourceGetValue) interpolate_cubic_get_uint,
       
   854   (GstControlSourceGetValueArray) interpolate_cubic_get_uint_value_array,
       
   855   (GstControlSourceGetValue) interpolate_cubic_get_long,
       
   856   (GstControlSourceGetValueArray) interpolate_cubic_get_long_value_array,
       
   857   (GstControlSourceGetValue) interpolate_cubic_get_ulong,
       
   858   (GstControlSourceGetValueArray) interpolate_cubic_get_ulong_value_array,
       
   859   (GstControlSourceGetValue) interpolate_cubic_get_int64,
       
   860   (GstControlSourceGetValueArray) interpolate_cubic_get_int64_value_array,
       
   861   (GstControlSourceGetValue) interpolate_cubic_get_uint64,
       
   862   (GstControlSourceGetValueArray) interpolate_cubic_get_uint64_value_array,
       
   863   (GstControlSourceGetValue) interpolate_cubic_get_float,
       
   864   (GstControlSourceGetValueArray) interpolate_cubic_get_float_value_array,
       
   865   (GstControlSourceGetValue) interpolate_cubic_get_double,
       
   866   (GstControlSourceGetValueArray) interpolate_cubic_get_double_value_array,
       
   867   (GstControlSourceGetValue) NULL,
       
   868   (GstControlSourceGetValueArray) NULL,
       
   869   (GstControlSourceGetValue) NULL,
       
   870   (GstControlSourceGetValueArray) NULL,
       
   871   (GstControlSourceGetValue) NULL,
       
   872   (GstControlSourceGetValueArray) NULL
       
   873 };
       
   874 
       
   875 
       
   876 /*  register all interpolation methods */
       
   877 GstInterpolateMethod *interpolation_methods[] = {
       
   878   &interpolate_none,
       
   879   &interpolate_trigger,
       
   880   &interpolate_linear,
       
   881   &interpolate_cubic,
       
   882   &interpolate_cubic
       
   883 };
       
   884 
       
   885 guint num_interpolation_methods = G_N_ELEMENTS (interpolation_methods);