mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 23:06:49 +00:00
trackelement: update control bindings correctly.
When duration or inpoint change, we need to remove edge control points, and set new control points with interpolated values. Also when duration == 0, we need to remove all control points, as otherwise the controller will raise !is_end assertions. It's the duty of the application to set keyframes back when duration gets != 0 again.
This commit is contained in:
parent
e9e7f0a82c
commit
01f9dbcadc
1 changed files with 120 additions and 0 deletions
|
@ -117,6 +117,10 @@ static gboolean _set_priority (GESTimelineElement * element, guint32 priority);
|
||||||
static GParamSpec **default_list_children_properties (GESTrackElement * object,
|
static GParamSpec **default_list_children_properties (GESTrackElement * object,
|
||||||
guint * n_properties);
|
guint * n_properties);
|
||||||
|
|
||||||
|
static void
|
||||||
|
_update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
|
||||||
|
GstClockTime duration);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ges_track_element_get_property (GObject * object, guint property_id,
|
ges_track_element_get_property (GObject * object, guint property_id,
|
||||||
GValue * value, GParamSpec * pspec)
|
GValue * value, GParamSpec * pspec)
|
||||||
|
@ -281,6 +285,117 @@ ges_track_element_init (GESTrackElement * self)
|
||||||
g_free, NULL);
|
g_free, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gfloat
|
||||||
|
interpolate_values_for_position (GstTimedValue * first_value,
|
||||||
|
GstTimedValue * second_value, guint64 position)
|
||||||
|
{
|
||||||
|
gfloat diff;
|
||||||
|
GstClockTime interval;
|
||||||
|
gfloat value_at_pos;
|
||||||
|
|
||||||
|
diff = second_value->value - first_value->value;
|
||||||
|
interval = second_value->timestamp - first_value->timestamp;
|
||||||
|
|
||||||
|
if (position > first_value->timestamp)
|
||||||
|
value_at_pos =
|
||||||
|
first_value->value + ((float) (position -
|
||||||
|
first_value->timestamp) / (float) interval) * diff;
|
||||||
|
else
|
||||||
|
value_at_pos =
|
||||||
|
first_value->value - ((float) (first_value->timestamp -
|
||||||
|
position) / (float) interval) * diff;
|
||||||
|
|
||||||
|
return value_at_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
|
||||||
|
GstClockTime duration)
|
||||||
|
{
|
||||||
|
GParamSpec **specs;
|
||||||
|
guint n, n_specs;
|
||||||
|
GstControlBinding *binding;
|
||||||
|
GstTimedValueControlSource *source;
|
||||||
|
GESTrackElement *self = GES_TRACK_ELEMENT (element);
|
||||||
|
|
||||||
|
specs = ges_track_element_list_children_properties (self, &n_specs);
|
||||||
|
|
||||||
|
for (n = 0; n < n_specs; ++n) {
|
||||||
|
GList *values, *tmp;
|
||||||
|
GstTimedValue *last, *first, *prev = NULL, *next = NULL;
|
||||||
|
gfloat value_at_pos;
|
||||||
|
|
||||||
|
binding = ges_track_element_get_control_binding (self, specs[n]->name);
|
||||||
|
|
||||||
|
if (!binding)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_object_get (binding, "control_source", &source, NULL);
|
||||||
|
|
||||||
|
if (duration == 0) {
|
||||||
|
gst_timed_value_control_source_unset_all (GST_TIMED_VALUE_CONTROL_SOURCE
|
||||||
|
(source));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
values =
|
||||||
|
gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
|
||||||
|
(source));
|
||||||
|
|
||||||
|
if (g_list_length (values) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
first = values->data;
|
||||||
|
|
||||||
|
for (tmp = values->next; tmp; tmp = tmp->next) {
|
||||||
|
next = tmp->data;
|
||||||
|
|
||||||
|
if (next->timestamp > inpoint)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_at_pos = interpolate_values_for_position (first, next, inpoint);
|
||||||
|
gst_timed_value_control_source_unset (source, first->timestamp);
|
||||||
|
gst_timed_value_control_source_set (source, inpoint, value_at_pos);
|
||||||
|
|
||||||
|
values =
|
||||||
|
gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
|
||||||
|
(source));
|
||||||
|
|
||||||
|
if (duration != GST_CLOCK_TIME_NONE) {
|
||||||
|
last = g_list_last (values)->data;
|
||||||
|
|
||||||
|
for (tmp = g_list_last (values)->prev; tmp; tmp = tmp->prev) {
|
||||||
|
prev = tmp->data;
|
||||||
|
|
||||||
|
if (prev->timestamp < duration + inpoint)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_at_pos =
|
||||||
|
interpolate_values_for_position (prev, last, duration + inpoint);
|
||||||
|
|
||||||
|
gst_timed_value_control_source_unset (source, last->timestamp);
|
||||||
|
gst_timed_value_control_source_set (source, duration + inpoint,
|
||||||
|
value_at_pos);
|
||||||
|
values =
|
||||||
|
gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
|
||||||
|
(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tmp = values; tmp; tmp = tmp->next) {
|
||||||
|
GstTimedValue *value = tmp->data;
|
||||||
|
if (value->timestamp < inpoint)
|
||||||
|
gst_timed_value_control_source_unset (source, value->timestamp);
|
||||||
|
else if (duration != GST_CLOCK_TIME_NONE
|
||||||
|
&& value->timestamp > duration + inpoint)
|
||||||
|
gst_timed_value_control_source_unset (source, value->timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (specs);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_set_start (GESTimelineElement * element, GstClockTime start)
|
_set_start (GESTimelineElement * element, GstClockTime start)
|
||||||
{
|
{
|
||||||
|
@ -311,6 +426,8 @@ _set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
|
||||||
} else
|
} else
|
||||||
object->priv->pending_inpoint = inpoint;
|
object->priv->pending_inpoint = inpoint;
|
||||||
|
|
||||||
|
_update_control_bindings (element, inpoint, GST_CLOCK_TIME_NONE);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +449,9 @@ _set_duration (GESTimelineElement * element, GstClockTime duration)
|
||||||
} else
|
} else
|
||||||
priv->pending_duration = duration;
|
priv->pending_duration = duration;
|
||||||
|
|
||||||
|
_update_control_bindings (element, ges_timeline_element_get_inpoint (element),
|
||||||
|
duration);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue