|
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); |