controller: Fix gst_interpolation_control_source_find_control_point_iter
[platform/upstream/gstreamer.git] / libs / gst / controller / gstinterpolation.c
1 /* GStreamer
2  *
3  * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
4  * Copyright (C) 2007-2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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 #define GST_CAT_DEFAULT controller_debug
32 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
33
34 #define EMPTY(x) (x)
35
36 /* common helper */
37
38 static gint
39 gst_control_point_find (gconstpointer p1, gconstpointer p2)
40 {
41   GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp;
42   GstClockTime ct2 = *(GstClockTime *) p2;
43
44   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
45 }
46
47 /*
48  * gst_interpolation_control_source_find_control_point_iter:
49  * @self: the interpolation control source to search in
50  * @timestamp: the search key
51  *
52  * Find last value before given timestamp in control point list.
53  * If all values in the control point list come after the given
54  * timestamp or no values exist, %NULL is returned.
55  *
56  * Returns: the found #GSequenceIter or %NULL
57  */
58 static GSequenceIter *gst_interpolation_control_source_find_control_point_iter
59     (GstInterpolationControlSource * self, GstClockTime timestamp)
60 {
61   GSequenceIter *iter;
62
63   if (!self->priv->values)
64     return NULL;
65
66   iter =
67       g_sequence_search (self->priv->values, &timestamp,
68       (GCompareDataFunc) gst_control_point_find, NULL);
69
70   /* g_sequence_search() returns the iter where timestamp
71    * would be inserted, i.e. the iter > timestamp, so
72    * we need to get the previous one. And of course, if
73    * there is no previous one, we return NULL. */
74   if (g_sequence_iter_is_begin (iter))
75     return NULL;
76
77   return g_sequence_iter_prev (iter);
78 }
79
80 /*  steps-like (no-)interpolation, default */
81 /*  just returns the value for the most recent key-frame */
82 static inline const GValue *
83 _interpolate_none_get (GstInterpolationControlSource * self,
84     GSequenceIter * iter)
85 {
86   const GValue *ret;
87
88   if (iter) {
89     GstControlPoint *cp = g_sequence_get (iter);
90
91     ret = &cp->value;
92   } else {
93     ret = &self->priv->default_value;
94   }
95   return ret;
96 }
97
98 #define DEFINE_NONE_GET_FUNC_COMPARABLE(type) \
99 static inline const GValue * \
100 _interpolate_none_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter) \
101 { \
102   const GValue *ret; \
103   \
104   if (iter) { \
105     GstControlPoint *cp = g_sequence_get (iter); \
106     g##type ret_val = g_value_get_##type (&cp->value); \
107     \
108     if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \
109       ret = &self->priv->minimum_value; \
110     else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \
111       ret = &self->priv->maximum_value; \
112     else \
113       ret = &cp->value; \
114   } else { \
115     ret = &self->priv->default_value; \
116   } \
117   return ret; \
118 }
119
120 #define DEFINE_NONE_GET(type,ctype,get_func) \
121 static gboolean \
122 interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
123 { \
124   const GValue *ret; \
125   GSequenceIter *iter; \
126   \
127   g_mutex_lock (self->lock); \
128   \
129   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
130   ret = get_func (self, iter); \
131   g_value_copy (ret, value); \
132   g_mutex_unlock (self->lock); \
133   return TRUE; \
134 } \
135 \
136 static gboolean \
137 interpolate_none_get_##type##_value_array (GstInterpolationControlSource *self, \
138     GstClockTime timestamp, GstValueArray * value_array) \
139 { \
140   gint i; \
141   GstClockTime ts = timestamp; \
142   GstClockTime next_ts = 0; \
143   ctype *values = (ctype *) value_array->values; \
144   const GValue *ret_val = NULL; \
145   ctype ret = 0; \
146   GSequenceIter *iter1 = NULL, *iter2 = NULL; \
147   \
148   g_mutex_lock (self->lock); \
149   for(i = 0; i < value_array->nbsamples; i++) { \
150     if (!ret_val || ts >= next_ts) { \
151       iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
152       if (!iter1) { \
153         if (G_LIKELY (self->priv->values)) \
154           iter2 = g_sequence_get_begin_iter (self->priv->values); \
155         else \
156           iter2 = NULL; \
157       } else { \
158         iter2 = g_sequence_iter_next (iter1); \
159       } \
160       \
161       if (iter2 && !g_sequence_iter_is_end (iter2)) { \
162         GstControlPoint *cp; \
163         \
164         cp = g_sequence_get (iter2); \
165         next_ts = cp->timestamp; \
166       } else { \
167         next_ts = GST_CLOCK_TIME_NONE; \
168       } \
169       \
170       ret_val = get_func (self, iter1); \
171       ret = g_value_get_##type (ret_val); \
172     } \
173     *values = ret; \
174     ts += value_array->sample_interval; \
175     values++; \
176   } \
177   g_mutex_unlock (self->lock); \
178   return TRUE; \
179 }
180
181 DEFINE_NONE_GET_FUNC_COMPARABLE (int);
182 DEFINE_NONE_GET (int, gint, _interpolate_none_get_int);
183 DEFINE_NONE_GET_FUNC_COMPARABLE (uint);
184 DEFINE_NONE_GET (uint, guint, _interpolate_none_get_uint);
185 DEFINE_NONE_GET_FUNC_COMPARABLE (long);
186 DEFINE_NONE_GET (long, glong, _interpolate_none_get_long);
187 DEFINE_NONE_GET_FUNC_COMPARABLE (ulong);
188 DEFINE_NONE_GET (ulong, gulong, _interpolate_none_get_ulong);
189 DEFINE_NONE_GET_FUNC_COMPARABLE (int64);
190 DEFINE_NONE_GET (int64, gint64, _interpolate_none_get_int64);
191 DEFINE_NONE_GET_FUNC_COMPARABLE (uint64);
192 DEFINE_NONE_GET (uint64, guint64, _interpolate_none_get_uint64);
193 DEFINE_NONE_GET_FUNC_COMPARABLE (float);
194 DEFINE_NONE_GET (float, gfloat, _interpolate_none_get_float);
195 DEFINE_NONE_GET_FUNC_COMPARABLE (double);
196 DEFINE_NONE_GET (double, gdouble, _interpolate_none_get_double);
197
198 DEFINE_NONE_GET (boolean, gboolean, _interpolate_none_get);
199 DEFINE_NONE_GET (enum, gint, _interpolate_none_get);
200 DEFINE_NONE_GET (string, const gchar *, _interpolate_none_get);
201
202 static GstInterpolateMethod interpolate_none = {
203   (GstControlSourceGetValue) interpolate_none_get_int,
204   (GstControlSourceGetValueArray) interpolate_none_get_int_value_array,
205   (GstControlSourceGetValue) interpolate_none_get_uint,
206   (GstControlSourceGetValueArray) interpolate_none_get_uint_value_array,
207   (GstControlSourceGetValue) interpolate_none_get_long,
208   (GstControlSourceGetValueArray) interpolate_none_get_long_value_array,
209   (GstControlSourceGetValue) interpolate_none_get_ulong,
210   (GstControlSourceGetValueArray) interpolate_none_get_ulong_value_array,
211   (GstControlSourceGetValue) interpolate_none_get_int64,
212   (GstControlSourceGetValueArray) interpolate_none_get_int64_value_array,
213   (GstControlSourceGetValue) interpolate_none_get_uint64,
214   (GstControlSourceGetValueArray) interpolate_none_get_uint64_value_array,
215   (GstControlSourceGetValue) interpolate_none_get_float,
216   (GstControlSourceGetValueArray) interpolate_none_get_float_value_array,
217   (GstControlSourceGetValue) interpolate_none_get_double,
218   (GstControlSourceGetValueArray) interpolate_none_get_double_value_array,
219   (GstControlSourceGetValue) interpolate_none_get_boolean,
220   (GstControlSourceGetValueArray) interpolate_none_get_boolean_value_array,
221   (GstControlSourceGetValue) interpolate_none_get_enum,
222   (GstControlSourceGetValueArray) interpolate_none_get_enum_value_array,
223   (GstControlSourceGetValue) interpolate_none_get_string,
224   (GstControlSourceGetValueArray) interpolate_none_get_string_value_array
225 };
226
227 /*  returns the default value of the property, except for times with specific values */
228 /*  needed for one-shot events, such as notes and triggers */
229 static inline const GValue *
230 _interpolate_trigger_get (GstInterpolationControlSource * self,
231     GSequenceIter * iter, GstClockTime timestamp)
232 {
233   GstControlPoint *cp;
234
235   /* check if there is a value at the registered timestamp */
236   if (iter) {
237     cp = g_sequence_get (iter);
238     if (timestamp == cp->timestamp) {
239       return &cp->value;
240     }
241   }
242   if (self->priv->nvalues > 0)
243     return &self->priv->default_value;
244   else
245     return NULL;
246 }
247
248 #define DEFINE_TRIGGER_GET_FUNC_COMPARABLE(type) \
249 static inline const GValue * \
250 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GSequenceIter *iter, GstClockTime timestamp) \
251 { \
252   GstControlPoint *cp; \
253   \
254   /* check if there is a value at the registered timestamp */ \
255   if (iter) { \
256     cp = g_sequence_get (iter); \
257     if (timestamp == cp->timestamp) { \
258       g##type ret = g_value_get_##type (&cp->value); \
259       if (g_value_get_##type (&self->priv->minimum_value) > ret) \
260         return &self->priv->minimum_value; \
261       else if (g_value_get_##type (&self->priv->maximum_value) < ret) \
262         return &self->priv->maximum_value; \
263       else \
264         return &cp->value; \
265     } \
266   } \
267   \
268   if (self->priv->nvalues > 0) \
269     return &self->priv->default_value; \
270   else \
271     return NULL; \
272 }
273
274 #define DEFINE_TRIGGER_GET(type, ctype, get_func) \
275 static gboolean \
276 interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
277 { \
278   const GValue *ret; \
279   GSequenceIter *iter; \
280   \
281   g_mutex_lock (self->lock); \
282   \
283   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
284   ret = get_func (self, iter, timestamp); \
285   if (!ret) { \
286     g_mutex_unlock (self->lock); \
287     return FALSE; \
288   } \
289   \
290   g_value_copy (ret, value); \
291   g_mutex_unlock (self->lock); \
292   return TRUE; \
293 } \
294 \
295 static gboolean \
296 interpolate_trigger_get_##type##_value_array (GstInterpolationControlSource *self, \
297     GstClockTime timestamp, GstValueArray * value_array) \
298 { \
299   gint i; \
300   GstClockTime ts = timestamp; \
301   GstClockTime next_ts = 0; \
302   ctype *values = (ctype *) value_array->values; \
303   const GValue *ret_val = NULL; \
304   ctype ret = 0; \
305   GSequenceIter *iter1 = NULL, *iter2 = NULL; \
306   gboolean triggered = FALSE; \
307   \
308   g_mutex_lock (self->lock); \
309   for(i = 0; i < value_array->nbsamples; i++) { \
310     if (!ret_val || ts >= next_ts) { \
311       iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
312       if (!iter1) { \
313         if (G_LIKELY (self->priv->values)) \
314           iter2 = g_sequence_get_begin_iter (self->priv->values); \
315         else \
316           iter2 = NULL; \
317       } else { \
318         iter2 = g_sequence_iter_next (iter1); \
319       } \
320       \
321       if (iter2 && !g_sequence_iter_is_end (iter2)) { \
322         GstControlPoint *cp; \
323         \
324         cp = g_sequence_get (iter2); \
325         next_ts = cp->timestamp; \
326       } else { \
327         next_ts = GST_CLOCK_TIME_NONE; \
328       } \
329       \
330       ret_val = get_func (self, iter1, ts); \
331       if (!ret_val) { \
332         g_mutex_unlock (self->lock); \
333         return FALSE; \
334       } \
335       ret = g_value_get_##type (ret_val); \
336       triggered = TRUE; \
337     } else if (triggered) { \
338       ret_val = get_func (self, iter1, ts); \
339       if (!ret_val) { \
340         g_mutex_unlock (self->lock); \
341         return FALSE; \
342       } \
343       ret = g_value_get_##type (ret_val); \
344       triggered = FALSE; \
345     } \
346     *values = ret; \
347     ts += value_array->sample_interval; \
348     values++; \
349   } \
350   g_mutex_unlock (self->lock); \
351   return TRUE; \
352 }
353
354 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int);
355 DEFINE_TRIGGER_GET (int, gint, _interpolate_trigger_get_int);
356 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint);
357 DEFINE_TRIGGER_GET (uint, guint, _interpolate_trigger_get_uint);
358 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (long);
359 DEFINE_TRIGGER_GET (long, glong, _interpolate_trigger_get_long);
360 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (ulong);
361 DEFINE_TRIGGER_GET (ulong, gulong, _interpolate_trigger_get_ulong);
362 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (int64);
363 DEFINE_TRIGGER_GET (int64, gint64, _interpolate_trigger_get_int64);
364 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (uint64);
365 DEFINE_TRIGGER_GET (uint64, guint64, _interpolate_trigger_get_uint64);
366 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (float);
367 DEFINE_TRIGGER_GET (float, gfloat, _interpolate_trigger_get_float);
368 DEFINE_TRIGGER_GET_FUNC_COMPARABLE (double);
369 DEFINE_TRIGGER_GET (double, gdouble, _interpolate_trigger_get_double);
370
371 DEFINE_TRIGGER_GET (boolean, gboolean, _interpolate_trigger_get);
372 DEFINE_TRIGGER_GET (enum, gint, _interpolate_trigger_get);
373 DEFINE_TRIGGER_GET (string, const gchar *, _interpolate_trigger_get);
374
375 static GstInterpolateMethod interpolate_trigger = {
376   (GstControlSourceGetValue) interpolate_trigger_get_int,
377   (GstControlSourceGetValueArray) interpolate_trigger_get_int_value_array,
378   (GstControlSourceGetValue) interpolate_trigger_get_uint,
379   (GstControlSourceGetValueArray) interpolate_trigger_get_uint_value_array,
380   (GstControlSourceGetValue) interpolate_trigger_get_long,
381   (GstControlSourceGetValueArray) interpolate_trigger_get_long_value_array,
382   (GstControlSourceGetValue) interpolate_trigger_get_ulong,
383   (GstControlSourceGetValueArray) interpolate_trigger_get_ulong_value_array,
384   (GstControlSourceGetValue) interpolate_trigger_get_int64,
385   (GstControlSourceGetValueArray) interpolate_trigger_get_int64_value_array,
386   (GstControlSourceGetValue) interpolate_trigger_get_uint64,
387   (GstControlSourceGetValueArray) interpolate_trigger_get_uint64_value_array,
388   (GstControlSourceGetValue) interpolate_trigger_get_float,
389   (GstControlSourceGetValueArray) interpolate_trigger_get_float_value_array,
390   (GstControlSourceGetValue) interpolate_trigger_get_double,
391   (GstControlSourceGetValueArray) interpolate_trigger_get_double_value_array,
392   (GstControlSourceGetValue) interpolate_trigger_get_boolean,
393   (GstControlSourceGetValueArray) interpolate_trigger_get_boolean_value_array,
394   (GstControlSourceGetValue) interpolate_trigger_get_enum,
395   (GstControlSourceGetValueArray) interpolate_trigger_get_enum_value_array,
396   (GstControlSourceGetValue) interpolate_trigger_get_string,
397   (GstControlSourceGetValueArray) interpolate_trigger_get_string_value_array
398 };
399
400 /*  linear interpolation */
401 /*  smoothes inbetween values */
402 #define DEFINE_LINEAR_GET(vtype, round, convert) \
403 static inline void \
404 _interpolate_linear_internal_##vtype (GstClockTime timestamp1, g##vtype value1, GstClockTime timestamp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \
405 { \
406   if (GST_CLOCK_TIME_IS_VALID (timestamp2)) { \
407     gdouble slope; \
408     \
409     slope = ((gdouble) convert (value2) - (gdouble) convert (value1)) / gst_guint64_to_gdouble (timestamp2 - timestamp1); \
410     \
411     if (round) \
412       *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - timestamp1) * slope + 0.5); \
413     else \
414       *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - timestamp1) * slope); \
415   } else { \
416     *ret = value1; \
417   } \
418   *ret = CLAMP (*ret, min, max); \
419 } \
420 \
421 static gboolean \
422 interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
423 { \
424   g##vtype ret, min, max; \
425   GSequenceIter *iter; \
426   GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
427   \
428   g_mutex_lock (self->lock); \
429   \
430   min = g_value_get_##vtype (&self->priv->minimum_value); \
431   max = g_value_get_##vtype (&self->priv->maximum_value); \
432   \
433   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
434   if (iter) { \
435     cp1 = g_sequence_get (iter); \
436     iter = g_sequence_iter_next (iter); \
437   } else { \
438     cp.timestamp = G_GUINT64_CONSTANT(0); \
439     g_value_init (&cp.value, self->priv->type); \
440     g_value_copy (&self->priv->default_value, &cp.value); \
441     cp1 = &cp; \
442     if (G_LIKELY (self->priv->values)) \
443       iter = g_sequence_get_begin_iter (self->priv->values); \
444   } \
445   if (iter && !g_sequence_iter_is_end (iter)) \
446     cp2 = g_sequence_get (iter); \
447   \
448   _interpolate_linear_internal_##vtype (cp1->timestamp, g_value_get_##vtype (&cp1->value), (cp2 ? cp2->timestamp : GST_CLOCK_TIME_NONE), (cp2 ? g_value_get_##vtype (&cp2->value) : 0), timestamp, min, max, &ret); \
449   g_value_set_##vtype (value, ret); \
450   g_mutex_unlock (self->lock); \
451   if (cp1 == &cp) \
452     g_value_unset (&cp.value); \
453   return TRUE; \
454 } \
455 \
456 static gboolean \
457 interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \
458     GstClockTime timestamp, GstValueArray * value_array) \
459 { \
460   gint i; \
461   GstClockTime ts = timestamp; \
462   GstClockTime next_ts = 0; \
463   g##vtype *values = (g##vtype *) value_array->values; \
464   GSequenceIter *iter1, *iter2 = NULL; \
465   GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
466   g##vtype val1 = 0, val2 = 0, min, max; \
467   \
468   g_mutex_lock (self->lock); \
469   \
470   cp.timestamp = G_GUINT64_CONSTANT(0); \
471   g_value_init (&cp.value, self->priv->type); \
472   g_value_copy (&self->priv->default_value, &cp.value); \
473   \
474   min = g_value_get_##vtype (&self->priv->minimum_value); \
475   max = g_value_get_##vtype (&self->priv->maximum_value); \
476   \
477   for(i = 0; i < value_array->nbsamples; i++) { \
478     if (timestamp >= next_ts) { \
479       iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
480       if (!iter1) { \
481         cp1 = &cp; \
482         if (G_LIKELY (self->priv->values)) \
483           iter2 = g_sequence_get_begin_iter (self->priv->values); \
484         else \
485           iter2 = NULL; \
486       } else { \
487         cp1 = g_sequence_get (iter1); \
488         iter2 = g_sequence_iter_next (iter1); \
489       } \
490       \
491       if (iter2 && !g_sequence_iter_is_end (iter2)) { \
492         cp2 = g_sequence_get (iter2); \
493         next_ts = cp2->timestamp; \
494       } else { \
495         next_ts = GST_CLOCK_TIME_NONE; \
496       } \
497       val1 = g_value_get_##vtype (&cp1->value); \
498       if (cp2) \
499         val2 = g_value_get_##vtype (&cp2->value); \
500     } \
501     _interpolate_linear_internal_##vtype (cp1->timestamp, val1, (cp2 ? cp2->timestamp : GST_CLOCK_TIME_NONE), (cp2 ? val2 : 0), ts, min, max, values); \
502     ts += value_array->sample_interval; \
503     values++; \
504   } \
505   g_mutex_unlock (self->lock); \
506   g_value_unset (&cp.value); \
507   return TRUE; \
508 }
509
510 DEFINE_LINEAR_GET (int, TRUE, EMPTY);
511 DEFINE_LINEAR_GET (uint, TRUE, EMPTY);
512 DEFINE_LINEAR_GET (long, TRUE, EMPTY);
513 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY);
514 DEFINE_LINEAR_GET (int64, TRUE, EMPTY);
515 DEFINE_LINEAR_GET (uint64, TRUE, gst_guint64_to_gdouble);
516 DEFINE_LINEAR_GET (float, FALSE, EMPTY);
517 DEFINE_LINEAR_GET (double, FALSE, EMPTY);
518
519 static GstInterpolateMethod interpolate_linear = {
520   (GstControlSourceGetValue) interpolate_linear_get_int,
521   (GstControlSourceGetValueArray) interpolate_linear_get_int_value_array,
522   (GstControlSourceGetValue) interpolate_linear_get_uint,
523   (GstControlSourceGetValueArray) interpolate_linear_get_uint_value_array,
524   (GstControlSourceGetValue) interpolate_linear_get_long,
525   (GstControlSourceGetValueArray) interpolate_linear_get_long_value_array,
526   (GstControlSourceGetValue) interpolate_linear_get_ulong,
527   (GstControlSourceGetValueArray) interpolate_linear_get_ulong_value_array,
528   (GstControlSourceGetValue) interpolate_linear_get_int64,
529   (GstControlSourceGetValueArray) interpolate_linear_get_int64_value_array,
530   (GstControlSourceGetValue) interpolate_linear_get_uint64,
531   (GstControlSourceGetValueArray) interpolate_linear_get_uint64_value_array,
532   (GstControlSourceGetValue) interpolate_linear_get_float,
533   (GstControlSourceGetValueArray) interpolate_linear_get_float_value_array,
534   (GstControlSourceGetValue) interpolate_linear_get_double,
535   (GstControlSourceGetValueArray) interpolate_linear_get_double_value_array,
536   (GstControlSourceGetValue) NULL,
537   (GstControlSourceGetValueArray) NULL,
538   (GstControlSourceGetValue) NULL,
539   (GstControlSourceGetValueArray) NULL,
540   (GstControlSourceGetValue) NULL,
541   (GstControlSourceGetValueArray) NULL
542 };
543
544 /*  square interpolation */
545
546 /*  cubic interpolation */
547
548 /* The following functions implement a natural cubic spline interpolator.
549  * For details look at http://en.wikipedia.org/wiki/Spline_interpolation
550  *
551  * Instead of using a real matrix with n^2 elements for the linear system
552  * of equations we use three arrays o, p, q to hold the tridiagonal matrix
553  * as following to save memory:
554  *
555  * p[0] q[0]    0    0    0
556  * o[1] p[1] q[1]    0    0
557  *    0 o[2] p[2] q[2]    .
558  *    .    .    .    .    .
559  */
560
561 #define DEFINE_CUBIC_GET(vtype,round, convert) \
562 static void \
563 _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \
564 { \
565   gint i, n = self->priv->nvalues; \
566   gdouble *o = g_new0 (gdouble, n); \
567   gdouble *p = g_new0 (gdouble, n); \
568   gdouble *q = g_new0 (gdouble, n); \
569   \
570   gdouble *h = g_new0 (gdouble, n); \
571   gdouble *b = g_new0 (gdouble, n); \
572   gdouble *z = g_new0 (gdouble, n); \
573   \
574   GSequenceIter *iter; \
575   GstControlPoint *cp; \
576   GstClockTime x_prev, x, x_next; \
577   g##vtype y_prev, y, y_next; \
578   \
579   /* Fill linear system of equations */ \
580   iter = g_sequence_get_begin_iter (self->priv->values); \
581   cp = g_sequence_get (iter); \
582   x = cp->timestamp; \
583   y = g_value_get_##vtype (&cp->value); \
584   \
585   p[0] = 1.0; \
586   \
587   iter = g_sequence_iter_next (iter); \
588   cp = g_sequence_get (iter); \
589   x_next = cp->timestamp; \
590   y_next = g_value_get_##vtype (&cp->value); \
591   h[0] = gst_guint64_to_gdouble (x_next - x); \
592   \
593   for (i = 1; i < n-1; i++) { \
594     /* Shuffle x and y values */ \
595     x_prev = x; \
596     y_prev = y; \
597     x = x_next; \
598     y = y_next; \
599     iter = g_sequence_iter_next (iter); \
600     cp = g_sequence_get (iter); \
601     x_next = cp->timestamp; \
602     y_next = g_value_get_##vtype (&cp->value); \
603     \
604     h[i] = gst_guint64_to_gdouble (x_next - x); \
605     o[i] = h[i-1]; \
606     p[i] = 2.0 * (h[i-1] + h[i]); \
607     q[i] = h[i]; \
608     b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \
609   } \
610   p[n-1] = 1.0; \
611   \
612   /* Use Gauss elimination to set everything below the \
613    * diagonal to zero */ \
614   for (i = 1; i < n-1; i++) { \
615     gdouble a = o[i] / p[i-1]; \
616     p[i] -= a * q[i-1]; \
617     b[i] -= a * b[i-1]; \
618   } \
619   \
620   /* Solve everything else from bottom to top */ \
621   for (i = n-2; i > 0; i--) \
622     z[i] = (b[i] - q[i] * z[i+1]) / p[i]; \
623   \
624   /* Save cache next in the GstControlPoint */ \
625   \
626   iter = g_sequence_get_begin_iter (self->priv->values); \
627   for (i = 0; i < n; i++) { \
628     cp = g_sequence_get (iter); \
629     cp->cache.cubic.h = h[i]; \
630     cp->cache.cubic.z = z[i]; \
631     iter = g_sequence_iter_next (iter); \
632   } \
633   \
634   /* Free our temporary arrays */ \
635   g_free (o); \
636   g_free (p); \
637   g_free (q); \
638   g_free (h); \
639   g_free (b); \
640   g_free (z); \
641 } \
642 \
643 static inline void \
644 _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstControlPoint *cp1, g##vtype value1, GstControlPoint *cp2, g##vtype value2, GstClockTime timestamp, g##vtype min, g##vtype max, g##vtype *ret) \
645 { \
646   if (!self->priv->valid_cache) { \
647     _interpolate_cubic_update_cache_##vtype (self); \
648     self->priv->valid_cache = TRUE; \
649   } \
650   \
651   if (cp2) { \
652     gdouble diff1, diff2; \
653     gdouble out; \
654     \
655     diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \
656     diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \
657     \
658     out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \
659     out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \
660     out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \
661     \
662     if (round) \
663       *ret = (g##vtype) (out + 0.5); \
664     else \
665       *ret = (g##vtype) out; \
666   } \
667   else { \
668     *ret = value1; \
669   } \
670   *ret = CLAMP (*ret, min, max); \
671 } \
672 \
673 static gboolean \
674 interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \
675 { \
676   g##vtype ret, min, max; \
677   GSequenceIter *iter; \
678   GstControlPoint *cp1, *cp2 = NULL, cp = {0, }; \
679   \
680   if (self->priv->nvalues <= 2) \
681     return interpolate_linear_get_##vtype (self, timestamp, value); \
682   \
683   g_mutex_lock (self->lock); \
684   \
685   min = g_value_get_##vtype (&self->priv->minimum_value); \
686   max = g_value_get_##vtype (&self->priv->maximum_value); \
687   \
688   iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \
689   if (iter) { \
690     cp1 = g_sequence_get (iter); \
691     iter = g_sequence_iter_next (iter); \
692   } else { \
693     cp.timestamp = G_GUINT64_CONSTANT(0); \
694     g_value_init (&cp.value, self->priv->type); \
695     g_value_copy (&self->priv->default_value, &cp.value); \
696     cp1 = &cp; \
697     if (G_LIKELY (self->priv->values)) \
698       iter = g_sequence_get_begin_iter (self->priv->values); \
699   } \
700   if (iter && !g_sequence_iter_is_end (iter)) \
701     cp2 = g_sequence_get (iter); \
702   \
703   _interpolate_cubic_get_##vtype (self, cp1, g_value_get_##vtype (&cp1->value), cp2, (cp2 ? g_value_get_##vtype (&cp2->value) : 0), timestamp, min, max, &ret); \
704   g_value_set_##vtype (value, ret); \
705   g_mutex_unlock (self->lock); \
706   if (cp1 == &cp) \
707     g_value_unset (&cp.value); \
708   return TRUE; \
709 } \
710 \
711 static gboolean \
712 interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \
713     GstClockTime timestamp, GstValueArray * value_array) \
714 { \
715   gint i; \
716   GstClockTime ts = timestamp; \
717   GstClockTime next_ts = 0; \
718   g##vtype *values = (g##vtype *) value_array->values; \
719   GSequenceIter *iter1, *iter2 = NULL; \
720   GstControlPoint *cp1 = NULL, *cp2 = NULL, cp = {0, }; \
721   g##vtype val1 = 0, val2 = 0, min, max; \
722   \
723   if (self->priv->nvalues <= 2) \
724     return interpolate_linear_get_##vtype##_value_array (self, timestamp, value_array); \
725   \
726   g_mutex_lock (self->lock); \
727   \
728   cp.timestamp = G_GUINT64_CONSTANT(0); \
729   g_value_init (&cp.value, self->priv->type); \
730   g_value_copy (&self->priv->default_value, &cp.value); \
731   \
732   min = g_value_get_##vtype (&self->priv->minimum_value); \
733   max = g_value_get_##vtype (&self->priv->maximum_value); \
734   \
735   for(i = 0; i < value_array->nbsamples; i++) { \
736     if (timestamp >= next_ts) { \
737       iter1 = gst_interpolation_control_source_find_control_point_iter (self, ts); \
738       if (!iter1) { \
739         cp1 = &cp; \
740         if (G_LIKELY (self->priv->values)) \
741           iter2 = g_sequence_get_begin_iter (self->priv->values); \
742         else \
743           iter2 = NULL; \
744       } else { \
745         cp1 = g_sequence_get (iter1); \
746         iter2 = g_sequence_iter_next (iter1); \
747       } \
748       \
749       if (iter2 && !g_sequence_iter_is_end (iter2)) { \
750         cp2 = g_sequence_get (iter2); \
751         next_ts = cp2->timestamp; \
752       } else { \
753         next_ts = GST_CLOCK_TIME_NONE; \
754       } \
755       val1 = g_value_get_##vtype (&cp1->value); \
756       if (cp2) \
757         val2 = g_value_get_##vtype (&cp2->value); \
758     } \
759     _interpolate_cubic_get_##vtype (self, cp1, val1, cp2, val2, timestamp, min, max, values); \
760     ts += value_array->sample_interval; \
761     values++; \
762   } \
763   g_mutex_unlock (self->lock); \
764   g_value_unset (&cp.value); \
765   return TRUE; \
766 }
767
768 DEFINE_CUBIC_GET (int, TRUE, EMPTY);
769 DEFINE_CUBIC_GET (uint, TRUE, EMPTY);
770 DEFINE_CUBIC_GET (long, TRUE, EMPTY);
771 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY);
772 DEFINE_CUBIC_GET (int64, TRUE, EMPTY);
773 DEFINE_CUBIC_GET (uint64, TRUE, gst_guint64_to_gdouble);
774 DEFINE_CUBIC_GET (float, FALSE, EMPTY);
775 DEFINE_CUBIC_GET (double, FALSE, EMPTY);
776
777 static GstInterpolateMethod interpolate_cubic = {
778   (GstControlSourceGetValue) interpolate_cubic_get_int,
779   (GstControlSourceGetValueArray) interpolate_cubic_get_int_value_array,
780   (GstControlSourceGetValue) interpolate_cubic_get_uint,
781   (GstControlSourceGetValueArray) interpolate_cubic_get_uint_value_array,
782   (GstControlSourceGetValue) interpolate_cubic_get_long,
783   (GstControlSourceGetValueArray) interpolate_cubic_get_long_value_array,
784   (GstControlSourceGetValue) interpolate_cubic_get_ulong,
785   (GstControlSourceGetValueArray) interpolate_cubic_get_ulong_value_array,
786   (GstControlSourceGetValue) interpolate_cubic_get_int64,
787   (GstControlSourceGetValueArray) interpolate_cubic_get_int64_value_array,
788   (GstControlSourceGetValue) interpolate_cubic_get_uint64,
789   (GstControlSourceGetValueArray) interpolate_cubic_get_uint64_value_array,
790   (GstControlSourceGetValue) interpolate_cubic_get_float,
791   (GstControlSourceGetValueArray) interpolate_cubic_get_float_value_array,
792   (GstControlSourceGetValue) interpolate_cubic_get_double,
793   (GstControlSourceGetValueArray) interpolate_cubic_get_double_value_array,
794   (GstControlSourceGetValue) NULL,
795   (GstControlSourceGetValueArray) NULL,
796   (GstControlSourceGetValue) NULL,
797   (GstControlSourceGetValueArray) NULL,
798   (GstControlSourceGetValue) NULL,
799   (GstControlSourceGetValueArray) NULL
800 };
801
802 /*  register all interpolation methods */
803 GstInterpolateMethod *priv_gst_interpolation_methods[] = {
804   &interpolate_none,
805   &interpolate_trigger,
806   &interpolate_linear,
807   &interpolate_cubic,
808   &interpolate_cubic
809 };
810
811 guint priv_gst_num_interpolation_methods =
812 G_N_ELEMENTS (priv_gst_interpolation_methods);