39 |
39 |
40 #define EMPTY(x) (x) |
40 #define EMPTY(x) (x) |
41 |
41 |
42 /* common helper */ |
42 /* common helper */ |
43 |
43 |
44 static gint |
|
45 gst_control_point_find (gconstpointer p1, gconstpointer p2) |
|
46 { |
|
47 GstClockTime ct1 = ((GstControlPoint *) p1)->timestamp; |
|
48 GstClockTime ct2 = *(GstClockTime *) p2; |
|
49 |
|
50 return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1)); |
|
51 } |
|
52 |
|
53 /* |
44 /* |
54 * gst_interpolation_control_source_find_control_point_iter: |
45 * gst_interpolation_control_source_find_control_point_node: |
55 * @self: the interpolation control source to search in |
46 * @self: the interpolation control source to search in |
56 * @timestamp: the search key |
47 * @timestamp: the search key |
57 * |
48 * |
58 * Find last value before given timestamp in control point list. |
49 * Find last value before given timestamp in control point list. |
59 * |
50 * |
60 * Returns: the found #GSequenceIter or %NULL |
51 * Returns: the found #GList node or %NULL |
61 */ |
52 */ |
62 static GSequenceIter *gst_interpolation_control_source_find_control_point_iter |
53 static GList *gst_interpolation_control_source_find_control_point_node |
63 (GstInterpolationControlSource * self, GstClockTime timestamp) |
54 (GstInterpolationControlSource * self, GstClockTime timestamp) |
64 { |
55 { |
65 GSequenceIter *iter; |
56 GList *prev_node = g_list_last (self->priv->values); |
|
57 GList *node; |
66 GstControlPoint *cp; |
58 GstControlPoint *cp; |
67 |
59 |
68 if (!self->priv->values) |
60 /* Check if we can start from the last requested value |
|
61 * to save some time */ |
|
62 node = self->priv->values; |
|
63 if (self->priv->last_requested_value) { |
|
64 GstControlPoint *last_cp = self->priv->last_requested_value->data; |
|
65 |
|
66 if (timestamp > last_cp->timestamp) |
|
67 node = self->priv->last_requested_value; |
|
68 } |
|
69 |
|
70 /* iterate over timed value list */ |
|
71 for (; node; node = g_list_next (node)) { |
|
72 cp = node->data; |
|
73 /* this timestamp is newer that the one we look for */ |
|
74 if (timestamp < cp->timestamp) { |
|
75 /* get previous one again */ |
|
76 prev_node = g_list_previous (node); |
|
77 break; |
|
78 } |
|
79 } |
|
80 |
|
81 /* If we have something to return save it as a |
|
82 * potential start position for the next search */ |
|
83 if (prev_node) |
|
84 self->priv->last_requested_value = prev_node; |
|
85 |
|
86 return prev_node; |
|
87 } |
|
88 |
|
89 /* |
|
90 * gst_interpolation_control_source_get_first_value: |
|
91 * @self: the interpolation control source to search in |
|
92 * |
|
93 * Find the first value and return it. |
|
94 * |
|
95 * Returns: the found #GValue or %NULL if there are none. |
|
96 */ |
|
97 static inline GValue * |
|
98 gst_interpolation_control_source_get_first_value (GstInterpolationControlSource |
|
99 * self) |
|
100 { |
|
101 if (self->priv->values && self->priv->nvalues > 0) { |
|
102 GstControlPoint *cp = self->priv->values->data; |
|
103 |
|
104 return &cp->value; |
|
105 } else { |
69 return NULL; |
106 return NULL; |
70 |
107 } |
71 iter = |
|
72 g_sequence_search (self->priv->values, ×tamp, |
|
73 (GCompareDataFunc) gst_control_point_find, NULL); |
|
74 |
|
75 /* g_sequence_search() returns the iter where timestamp |
|
76 * would be inserted, i.e. the iter > timestamp, so |
|
77 * we need to get the previous one */ |
|
78 iter = g_sequence_iter_prev (iter); |
|
79 |
|
80 /* g_sequence_iter_prev () on the begin iter returns |
|
81 * the begin iter. Check if the prev iter is still |
|
82 * after our timestamp, in that case return NULL |
|
83 */ |
|
84 cp = g_sequence_get (iter); |
|
85 if (cp->timestamp > timestamp) |
|
86 return NULL; |
|
87 |
|
88 /* If the iter is the end iter return NULL as no |
|
89 * data is linked to the end iter */ |
|
90 return G_UNLIKELY (g_sequence_iter_is_end (iter)) ? NULL : iter; |
|
91 } |
108 } |
92 |
109 |
93 /* steps-like (no-)interpolation, default */ |
110 /* steps-like (no-)interpolation, default */ |
94 /* just returns the value for the most recent key-frame */ |
111 /* just returns the value for the most recent key-frame */ |
95 |
112 |
96 #define DEFINE_NONE_GET(type) \ |
113 #define DEFINE_NONE_GET(type) \ |
97 static inline GValue * \ |
114 static inline GValue * \ |
98 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ |
115 _interpolate_none_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ |
99 { \ |
116 { \ |
100 GValue *ret; \ |
117 GValue *ret; \ |
101 GSequenceIter *iter; \ |
118 GList *node; \ |
102 \ |
119 \ |
103 if ((iter = \ |
120 if ((node = \ |
104 gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \ |
121 gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ |
105 GstControlPoint *cp = g_sequence_get (iter); \ |
122 GstControlPoint *cp = node->data; \ |
106 g##type ret_val = g_value_get_##type (&cp->value); \ |
123 g##type ret_val = g_value_get_##type (&cp->value); \ |
107 \ |
124 \ |
108 if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \ |
125 if (g_value_get_##type (&self->priv->minimum_value) > ret_val) \ |
109 ret = &self->priv->minimum_value; \ |
126 ret = &self->priv->minimum_value; \ |
110 else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \ |
127 else if (g_value_get_##type (&self->priv->maximum_value) < ret_val) \ |
111 ret = &self->priv->maximum_value; \ |
128 ret = &self->priv->maximum_value; \ |
112 else \ |
129 else \ |
113 ret = &cp->value; \ |
130 ret = &cp->value; \ |
114 } else { \ |
131 } else { \ |
115 ret = &self->priv->default_value; \ |
132 ret = gst_interpolation_control_source_get_first_value (self); \ |
116 } \ |
133 } \ |
117 return ret; \ |
134 return ret; \ |
118 } \ |
135 } \ |
119 \ |
136 \ |
120 static gboolean \ |
137 static gboolean \ |
308 |
325 |
309 #define DEFINE_TRIGGER_GET(type) \ |
326 #define DEFINE_TRIGGER_GET(type) \ |
310 static inline GValue * \ |
327 static inline GValue * \ |
311 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ |
328 _interpolate_trigger_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp) \ |
312 { \ |
329 { \ |
313 GSequenceIter *iter; \ |
330 GList *node; \ |
314 GstControlPoint *cp; \ |
331 GstControlPoint *cp; \ |
315 \ |
332 \ |
316 /* check if there is a value at the registered timestamp */ \ |
333 /* check if there is a value at the registered timestamp */ \ |
317 if ((iter = \ |
334 if ((node = \ |
318 gst_interpolation_control_source_find_control_point_iter (self, timestamp))) { \ |
335 gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ |
319 cp = g_sequence_get (iter); \ |
336 cp = node->data; \ |
320 if (timestamp == cp->timestamp) { \ |
337 if (timestamp == cp->timestamp) { \ |
321 g##type ret = g_value_get_##type (&cp->value); \ |
338 g##type ret = g_value_get_##type (&cp->value); \ |
322 if (g_value_get_##type (&self->priv->minimum_value) > ret) \ |
339 if (g_value_get_##type (&self->priv->minimum_value) > ret) \ |
323 return &self->priv->minimum_value; \ |
340 return &self->priv->minimum_value; \ |
324 else if (g_value_get_##type (&self->priv->maximum_value) < ret) \ |
341 else if (g_value_get_##type (&self->priv->maximum_value) < ret) \ |
522 }; |
539 }; |
523 |
540 |
524 /* linear interpolation */ |
541 /* linear interpolation */ |
525 /* smoothes inbetween values */ |
542 /* smoothes inbetween values */ |
526 |
543 |
527 #define DEFINE_LINEAR_GET(vtype,round,convert) \ |
544 #define DEFINE_LINEAR_GET(type,round,convert) \ |
528 static inline gboolean \ |
545 static inline gboolean \ |
529 _interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \ |
546 _interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \ |
530 { \ |
547 { \ |
531 GSequenceIter *iter; \ |
548 GList *node; \ |
532 GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \ |
549 \ |
533 \ |
550 if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ |
534 iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ |
551 GstControlPoint *cp1, *cp2; \ |
535 if (iter) { \ |
552 \ |
536 cp1 = g_sequence_get (iter); \ |
553 cp1 = node->data; \ |
537 iter = g_sequence_iter_next (iter); \ |
554 if ((node = g_list_next (node))) { \ |
538 iter = g_sequence_iter_is_end (iter) ? NULL : iter; \ |
555 gdouble slope; \ |
|
556 g##type value1,value2; \ |
|
557 \ |
|
558 cp2 = node->data; \ |
|
559 \ |
|
560 value1 = g_value_get_##type (&cp1->value); \ |
|
561 value2 = g_value_get_##type (&cp2->value); \ |
|
562 slope = (gdouble) convert (value2 - value1) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \ |
|
563 \ |
|
564 if (round) \ |
|
565 *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \ |
|
566 else \ |
|
567 *ret = (g##type) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \ |
|
568 } \ |
|
569 else { \ |
|
570 *ret = g_value_get_##type (&cp1->value); \ |
|
571 } \ |
539 } else { \ |
572 } else { \ |
540 cp.timestamp = G_GUINT64_CONSTANT(0); \ |
573 GValue *first = gst_interpolation_control_source_get_first_value (self); \ |
541 g_value_init (&cp.value, self->priv->type); \ |
574 if (!first) \ |
542 g_value_copy (&self->priv->default_value, &cp.value); \ |
575 return FALSE; \ |
543 cp1 = &cp; \ |
576 *ret = g_value_get_##type (first); \ |
544 if (G_LIKELY (self->priv->values)) \ |
577 } \ |
545 iter = g_sequence_get_begin_iter (self->priv->values); \ |
578 *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \ |
546 } \ |
|
547 if (iter) { \ |
|
548 gdouble slope; \ |
|
549 g##vtype value1,value2; \ |
|
550 \ |
|
551 cp2 = g_sequence_get (iter); \ |
|
552 \ |
|
553 value1 = g_value_get_##vtype (&cp1->value); \ |
|
554 value2 = g_value_get_##vtype (&cp2->value); \ |
|
555 slope = ((gdouble) convert (value2) - (gdouble) convert (value1)) / gst_guint64_to_gdouble (cp2->timestamp - cp1->timestamp); \ |
|
556 \ |
|
557 if (round) \ |
|
558 *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope + 0.5); \ |
|
559 else \ |
|
560 *ret = (g##vtype) (convert (value1) + gst_guint64_to_gdouble (timestamp - cp1->timestamp) * slope); \ |
|
561 } \ |
|
562 else { \ |
|
563 *ret = g_value_get_##vtype (&cp1->value); \ |
|
564 } \ |
|
565 *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \ |
|
566 return TRUE; \ |
579 return TRUE; \ |
567 } \ |
580 } \ |
568 \ |
581 \ |
569 static gboolean \ |
582 static gboolean \ |
570 interpolate_linear_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ |
583 interpolate_linear_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ |
571 { \ |
584 { \ |
572 g##vtype ret; \ |
585 g##type ret; \ |
573 g_mutex_lock (self->lock); \ |
586 g_mutex_lock (self->lock); \ |
574 if (_interpolate_linear_get_##vtype (self, timestamp, &ret)) { \ |
587 if (_interpolate_linear_get_##type (self, timestamp, &ret)) { \ |
575 g_value_set_##vtype (value, ret); \ |
588 g_value_set_##type (value, ret); \ |
576 g_mutex_unlock (self->lock); \ |
589 g_mutex_unlock (self->lock); \ |
577 return TRUE; \ |
590 return TRUE; \ |
578 } \ |
591 } \ |
579 g_mutex_unlock (self->lock); \ |
592 g_mutex_unlock (self->lock); \ |
580 return FALSE; \ |
593 return FALSE; \ |
581 } \ |
594 } \ |
582 \ |
595 \ |
583 static gboolean \ |
596 static gboolean \ |
584 interpolate_linear_get_##vtype##_value_array (GstInterpolationControlSource *self, \ |
597 interpolate_linear_get_##type##_value_array (GstInterpolationControlSource *self, \ |
585 GstClockTime timestamp, GstValueArray * value_array) \ |
598 GstClockTime timestamp, GstValueArray * value_array) \ |
586 { \ |
599 { \ |
587 gint i; \ |
600 gint i; \ |
588 GstClockTime ts = timestamp; \ |
601 GstClockTime ts = timestamp; \ |
589 g##vtype *values = (g##vtype *) value_array->values; \ |
602 g##type *values = (g##type *) value_array->values; \ |
590 \ |
603 \ |
591 g_mutex_lock (self->lock); \ |
604 g_mutex_lock (self->lock); \ |
592 for(i = 0; i < value_array->nbsamples; i++) { \ |
605 for(i = 0; i < value_array->nbsamples; i++) { \ |
593 if (! _interpolate_linear_get_##vtype (self, ts, values)) { \ |
606 if (! _interpolate_linear_get_##type (self, ts, values)) { \ |
594 g_mutex_unlock (self->lock); \ |
607 g_mutex_unlock (self->lock); \ |
595 return FALSE; \ |
608 return FALSE; \ |
596 } \ |
609 } \ |
597 ts += value_array->sample_interval; \ |
610 ts += value_array->sample_interval; \ |
598 values++; \ |
611 values++; \ |
606 DEFINE_LINEAR_GET (uint, TRUE, EMPTY); |
619 DEFINE_LINEAR_GET (uint, TRUE, EMPTY); |
607 DEFINE_LINEAR_GET (long, TRUE, EMPTY); |
620 DEFINE_LINEAR_GET (long, TRUE, EMPTY); |
608 |
621 |
609 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY); |
622 DEFINE_LINEAR_GET (ulong, TRUE, EMPTY); |
610 DEFINE_LINEAR_GET (int64, TRUE, EMPTY); |
623 DEFINE_LINEAR_GET (int64, TRUE, EMPTY); |
611 DEFINE_LINEAR_GET (uint64, TRUE, gst_guint64_to_gdouble); |
624 DEFINE_LINEAR_GET (uint64, TRUE, gst_util_guint64_to_gdouble); |
612 DEFINE_LINEAR_GET (float, FALSE, EMPTY); |
625 DEFINE_LINEAR_GET (float, FALSE, EMPTY); |
613 DEFINE_LINEAR_GET (double, FALSE, EMPTY); |
626 DEFINE_LINEAR_GET (double, FALSE, EMPTY); |
614 |
627 |
615 static GstInterpolateMethod interpolate_linear = { |
628 static GstInterpolateMethod interpolate_linear = { |
616 (GstControlSourceGetValue) interpolate_linear_get_int, |
629 (GstControlSourceGetValue) interpolate_linear_get_int, |
652 * o[1] p[1] q[1] 0 0 |
665 * o[1] p[1] q[1] 0 0 |
653 * 0 o[2] p[2] q[2] . |
666 * 0 o[2] p[2] q[2] . |
654 * . . . . . |
667 * . . . . . |
655 */ |
668 */ |
656 |
669 |
657 #define DEFINE_CUBIC_GET(vtype,round, convert) \ |
670 #define DEFINE_CUBIC_GET(type,round, convert) \ |
658 static void \ |
671 static void \ |
659 _interpolate_cubic_update_cache_##vtype (GstInterpolationControlSource *self) \ |
672 _interpolate_cubic_update_cache_##type (GstInterpolationControlSource *self) \ |
660 { \ |
673 { \ |
661 gint i, n = self->priv->nvalues; \ |
674 gint i, n = self->priv->nvalues; \ |
662 gdouble *o = g_new0 (gdouble, n); \ |
675 gdouble *o = g_new0 (gdouble, n); \ |
663 gdouble *p = g_new0 (gdouble, n); \ |
676 gdouble *p = g_new0 (gdouble, n); \ |
664 gdouble *q = g_new0 (gdouble, n); \ |
677 gdouble *q = g_new0 (gdouble, n); \ |
665 \ |
678 \ |
666 gdouble *h = g_new0 (gdouble, n); \ |
679 gdouble *h = g_new0 (gdouble, n); \ |
667 gdouble *b = g_new0 (gdouble, n); \ |
680 gdouble *b = g_new0 (gdouble, n); \ |
668 gdouble *z = g_new0 (gdouble, n); \ |
681 gdouble *z = g_new0 (gdouble, n); \ |
669 \ |
682 \ |
670 GSequenceIter *iter; \ |
683 GList *node; \ |
671 GstControlPoint *cp; \ |
684 GstControlPoint *cp; \ |
672 GstClockTime x_prev, x, x_next; \ |
685 GstClockTime x_prev, x, x_next; \ |
673 g##vtype y_prev, y, y_next; \ |
686 g##type y_prev, y, y_next; \ |
674 \ |
687 \ |
675 /* Fill linear system of equations */ \ |
688 /* Fill linear system of equations */ \ |
676 iter = g_sequence_get_begin_iter (self->priv->values); \ |
689 node = self->priv->values; \ |
677 cp = g_sequence_get (iter); \ |
690 cp = node->data; \ |
678 x = cp->timestamp; \ |
691 x = cp->timestamp; \ |
679 y = g_value_get_##vtype (&cp->value); \ |
692 y = g_value_get_##type (&cp->value); \ |
680 \ |
693 \ |
681 p[0] = 1.0; \ |
694 p[0] = 1.0; \ |
682 \ |
695 \ |
683 iter = g_sequence_iter_next (iter); \ |
696 node = node->next; \ |
684 cp = g_sequence_get (iter); \ |
697 cp = node->data; \ |
685 x_next = cp->timestamp; \ |
698 x_next = cp->timestamp; \ |
686 y_next = g_value_get_##vtype (&cp->value); \ |
699 y_next = g_value_get_##type (&cp->value); \ |
687 h[0] = gst_guint64_to_gdouble (x_next - x); \ |
700 h[0] = gst_util_guint64_to_gdouble (x_next - x); \ |
688 \ |
701 \ |
689 for (i = 1; i < n-1; i++) { \ |
702 for (i = 1; i < n-1; i++) { \ |
690 /* Shuffle x and y values */ \ |
703 /* Shuffle x and y values */ \ |
691 x_prev = x; \ |
704 x_prev = x; \ |
692 y_prev = y; \ |
705 y_prev = y; \ |
693 x = x_next; \ |
706 x = x_next; \ |
694 y = y_next; \ |
707 y = y_next; \ |
695 iter = g_sequence_iter_next (iter); \ |
708 node = node->next; \ |
696 cp = g_sequence_get (iter); \ |
709 cp = node->data; \ |
697 x_next = cp->timestamp; \ |
710 x_next = cp->timestamp; \ |
698 y_next = g_value_get_##vtype (&cp->value); \ |
711 y_next = g_value_get_##type (&cp->value); \ |
699 \ |
712 \ |
700 h[i] = gst_guint64_to_gdouble (x_next - x); \ |
713 h[i] = gst_util_guint64_to_gdouble (x_next - x); \ |
701 o[i] = h[i-1]; \ |
714 o[i] = h[i-1]; \ |
702 p[i] = 2.0 * (h[i-1] + h[i]); \ |
715 p[i] = 2.0 * (h[i-1] + h[i]); \ |
703 q[i] = h[i]; \ |
716 q[i] = h[i]; \ |
704 b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \ |
717 b[i] = convert (y_next - y) / h[i] - convert (y - y_prev) / h[i-1]; \ |
705 } \ |
718 } \ |
735 g_free (b); \ |
748 g_free (b); \ |
736 g_free (z); \ |
749 g_free (z); \ |
737 } \ |
750 } \ |
738 \ |
751 \ |
739 static inline gboolean \ |
752 static inline gboolean \ |
740 _interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, g##vtype *ret) \ |
753 _interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, g##type *ret) \ |
741 { \ |
754 { \ |
742 GSequenceIter *iter; \ |
755 GList *node; \ |
743 GstControlPoint *cp1 = NULL, *cp2, cp={0,}; \ |
|
744 \ |
756 \ |
745 if (self->priv->nvalues <= 2) \ |
757 if (self->priv->nvalues <= 2) \ |
746 return _interpolate_linear_get_##vtype (self, timestamp, ret); \ |
758 return _interpolate_linear_get_##type (self, timestamp, ret); \ |
747 \ |
759 \ |
748 if (!self->priv->valid_cache) { \ |
760 if (!self->priv->valid_cache) { \ |
749 _interpolate_cubic_update_cache_##vtype (self); \ |
761 _interpolate_cubic_update_cache_##type (self); \ |
750 self->priv->valid_cache = TRUE; \ |
762 self->priv->valid_cache = TRUE; \ |
751 } \ |
763 } \ |
752 \ |
764 \ |
753 iter = gst_interpolation_control_source_find_control_point_iter (self, timestamp); \ |
765 if ((node = gst_interpolation_control_source_find_control_point_node (self, timestamp))) { \ |
754 if (iter) { \ |
766 GstControlPoint *cp1, *cp2; \ |
755 cp1 = g_sequence_get (iter); \ |
767 \ |
756 iter = g_sequence_iter_next (iter); \ |
768 cp1 = node->data; \ |
757 iter = g_sequence_iter_is_end (iter) ? NULL : iter; \ |
769 if ((node = g_list_next (node))) { \ |
|
770 gdouble diff1, diff2; \ |
|
771 g##type value1,value2; \ |
|
772 gdouble out; \ |
|
773 \ |
|
774 cp2 = node->data; \ |
|
775 \ |
|
776 value1 = g_value_get_##type (&cp1->value); \ |
|
777 value2 = g_value_get_##type (&cp2->value); \ |
|
778 \ |
|
779 diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \ |
|
780 diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \ |
|
781 \ |
|
782 out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \ |
|
783 out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \ |
|
784 out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \ |
|
785 \ |
|
786 if (round) \ |
|
787 *ret = (g##type) (out + 0.5); \ |
|
788 else \ |
|
789 *ret = (g##type) out; \ |
|
790 } \ |
|
791 else { \ |
|
792 *ret = g_value_get_##type (&cp1->value); \ |
|
793 } \ |
758 } else { \ |
794 } else { \ |
759 cp.timestamp = G_GUINT64_CONSTANT(0); \ |
795 GValue *first = gst_interpolation_control_source_get_first_value (self); \ |
760 g_value_init (&cp.value, self->priv->type); \ |
796 if (!first) \ |
761 g_value_copy (&self->priv->default_value, &cp.value); \ |
797 return FALSE; \ |
762 cp1 = &cp; \ |
798 *ret = g_value_get_##type (first); \ |
763 iter = g_sequence_get_begin_iter (self->priv->values); \ |
799 } \ |
764 } \ |
800 *ret = CLAMP (*ret, g_value_get_##type (&self->priv->minimum_value), g_value_get_##type (&self->priv->maximum_value)); \ |
765 if (iter) { \ |
|
766 gdouble diff1, diff2; \ |
|
767 g##vtype value1,value2; \ |
|
768 gdouble out; \ |
|
769 \ |
|
770 cp2 = g_sequence_get (iter); \ |
|
771 \ |
|
772 value1 = g_value_get_##vtype (&cp1->value); \ |
|
773 value2 = g_value_get_##vtype (&cp2->value); \ |
|
774 \ |
|
775 diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); \ |
|
776 diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); \ |
|
777 \ |
|
778 out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; \ |
|
779 out += (convert (value2) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; \ |
|
780 out += (convert (value1) / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; \ |
|
781 \ |
|
782 if (round) \ |
|
783 *ret = (g##vtype) (out + 0.5); \ |
|
784 else \ |
|
785 *ret = (g##vtype) out; \ |
|
786 } \ |
|
787 else { \ |
|
788 *ret = g_value_get_##vtype (&cp1->value); \ |
|
789 } \ |
|
790 *ret = CLAMP (*ret, g_value_get_##vtype (&self->priv->minimum_value), g_value_get_##vtype (&self->priv->maximum_value)); \ |
|
791 return TRUE; \ |
801 return TRUE; \ |
792 } \ |
802 } \ |
793 \ |
803 \ |
794 static gboolean \ |
804 static gboolean \ |
795 interpolate_cubic_get_##vtype (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ |
805 interpolate_cubic_get_##type (GstInterpolationControlSource *self, GstClockTime timestamp, GValue *value) \ |
796 { \ |
806 { \ |
797 g##vtype ret; \ |
807 g##type ret; \ |
798 g_mutex_lock (self->lock); \ |
808 g_mutex_lock (self->lock); \ |
799 if (_interpolate_cubic_get_##vtype (self, timestamp, &ret)) { \ |
809 if (_interpolate_cubic_get_##type (self, timestamp, &ret)) { \ |
800 g_value_set_##vtype (value, ret); \ |
810 g_value_set_##type (value, ret); \ |
801 g_mutex_unlock (self->lock); \ |
811 g_mutex_unlock (self->lock); \ |
802 return TRUE; \ |
812 return TRUE; \ |
803 } \ |
813 } \ |
804 g_mutex_unlock (self->lock); \ |
814 g_mutex_unlock (self->lock); \ |
805 return FALSE; \ |
815 return FALSE; \ |
806 } \ |
816 } \ |
807 \ |
817 \ |
808 static gboolean \ |
818 static gboolean \ |
809 interpolate_cubic_get_##vtype##_value_array (GstInterpolationControlSource *self, \ |
819 interpolate_cubic_get_##type##_value_array (GstInterpolationControlSource *self, \ |
810 GstClockTime timestamp, GstValueArray * value_array) \ |
820 GstClockTime timestamp, GstValueArray * value_array) \ |
811 { \ |
821 { \ |
812 gint i; \ |
822 gint i; \ |
813 GstClockTime ts = timestamp; \ |
823 GstClockTime ts = timestamp; \ |
814 g##vtype *values = (g##vtype *) value_array->values; \ |
824 g##type *values = (g##type *) value_array->values; \ |
815 \ |
825 \ |
816 g_mutex_lock (self->lock); \ |
826 g_mutex_lock (self->lock); \ |
817 for(i = 0; i < value_array->nbsamples; i++) { \ |
827 for(i = 0; i < value_array->nbsamples; i++) { \ |
818 if (! _interpolate_cubic_get_##vtype (self, ts, values)) { \ |
828 if (! _interpolate_cubic_get_##type (self, ts, values)) { \ |
819 g_mutex_unlock (self->lock); \ |
829 g_mutex_unlock (self->lock); \ |
820 return FALSE; \ |
830 return FALSE; \ |
821 } \ |
831 } \ |
822 ts += value_array->sample_interval; \ |
832 ts += value_array->sample_interval; \ |
823 values++; \ |
833 values++; \ |
831 DEFINE_CUBIC_GET (uint, TRUE, EMPTY); |
841 DEFINE_CUBIC_GET (uint, TRUE, EMPTY); |
832 DEFINE_CUBIC_GET (long, TRUE, EMPTY); |
842 DEFINE_CUBIC_GET (long, TRUE, EMPTY); |
833 |
843 |
834 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY); |
844 DEFINE_CUBIC_GET (ulong, TRUE, EMPTY); |
835 DEFINE_CUBIC_GET (int64, TRUE, EMPTY); |
845 DEFINE_CUBIC_GET (int64, TRUE, EMPTY); |
836 DEFINE_CUBIC_GET (uint64, TRUE, gst_guint64_to_gdouble); |
846 DEFINE_CUBIC_GET (uint64, TRUE, gst_util_guint64_to_gdouble); |
837 DEFINE_CUBIC_GET (float, FALSE, EMPTY); |
847 DEFINE_CUBIC_GET (float, FALSE, EMPTY); |
838 DEFINE_CUBIC_GET (double, FALSE, EMPTY); |
848 DEFINE_CUBIC_GET (double, FALSE, EMPTY); |
839 |
849 |
840 static GstInterpolateMethod interpolate_cubic = { |
850 static GstInterpolateMethod interpolate_cubic = { |
841 (GstControlSourceGetValue) interpolate_cubic_get_int, |
851 (GstControlSourceGetValue) interpolate_cubic_get_int, |