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