mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 16:08:51 +00:00
element: Implement a paste method
Allowing user to copy paste clips very easily
This commit is contained in:
parent
d23e43ae1a
commit
5885f58c14
8 changed files with 222 additions and 43 deletions
|
@ -454,6 +454,7 @@ ges_timeline_element_roll_end
|
||||||
ges_timeline_element_trim
|
ges_timeline_element_trim
|
||||||
ges_timeline_element_get_toplevel_parent
|
ges_timeline_element_get_toplevel_parent
|
||||||
ges_timeline_element_copy
|
ges_timeline_element_copy
|
||||||
|
ges_timeline_element_paste
|
||||||
ges_timeline_element_get_name
|
ges_timeline_element_get_name
|
||||||
ges_timeline_element_set_name
|
ges_timeline_element_set_name
|
||||||
ges_timeline_element_list_children_properties
|
ges_timeline_element_list_children_properties
|
||||||
|
|
|
@ -625,6 +625,44 @@ _edit (GESContainer * container, GList * layers,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_paste (GESTimelineElement * element, GESTimelineElement * ref,
|
||||||
|
GstClockTime paste_position)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
GESClip *self = GES_CLIP (element);
|
||||||
|
GESClip *refclip = GES_CLIP (ref);
|
||||||
|
|
||||||
|
ges_clip_set_moving_from_layer (self, TRUE);
|
||||||
|
ges_layer_add_clip (refclip->priv->layer, self);
|
||||||
|
ges_clip_set_moving_from_layer (self, FALSE);
|
||||||
|
|
||||||
|
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (self), paste_position);
|
||||||
|
|
||||||
|
for (tmp = GES_CONTAINER_CHILDREN (refclip); tmp; tmp = tmp->next) {
|
||||||
|
GESTrackElement *new_trackelement, *trackelement =
|
||||||
|
GES_TRACK_ELEMENT (tmp->data);
|
||||||
|
|
||||||
|
new_trackelement =
|
||||||
|
GES_TRACK_ELEMENT (ges_timeline_element_copy (GES_TIMELINE_ELEMENT
|
||||||
|
(trackelement), FALSE));
|
||||||
|
if (new_trackelement == NULL) {
|
||||||
|
GST_WARNING_OBJECT (trackelement, "Could not create a copy");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ges_container_add (GES_CONTAINER (self),
|
||||||
|
GES_TIMELINE_ELEMENT (new_trackelement));
|
||||||
|
|
||||||
|
ges_track_element_copy_properties (GES_TIMELINE_ELEMENT (trackelement),
|
||||||
|
GES_TIMELINE_ELEMENT (new_trackelement));
|
||||||
|
|
||||||
|
ges_track_element_copy_bindings (trackelement, new_trackelement,
|
||||||
|
GST_CLOCK_TIME_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
|
@ -715,7 +753,7 @@ ges_clip_class_init (GESClipClass * klass)
|
||||||
element_class->set_inpoint = _set_inpoint;
|
element_class->set_inpoint = _set_inpoint;
|
||||||
element_class->set_priority = _set_priority;
|
element_class->set_priority = _set_priority;
|
||||||
element_class->set_max_duration = _set_max_duration;
|
element_class->set_max_duration = _set_max_duration;
|
||||||
/* TODO implement the deep_copy Virtual method */
|
element_class->paste = _paste;
|
||||||
|
|
||||||
container_class->add_child = _add_child;
|
container_class->add_child = _add_child;
|
||||||
container_class->remove_child = _remove_child;
|
container_class->remove_child = _remove_child;
|
||||||
|
@ -1245,7 +1283,7 @@ ges_clip_split (GESClip * clip, guint64 position)
|
||||||
ges_track_element_copy_properties (GES_TIMELINE_ELEMENT (trackelement),
|
ges_track_element_copy_properties (GES_TIMELINE_ELEMENT (trackelement),
|
||||||
GES_TIMELINE_ELEMENT (new_trackelement));
|
GES_TIMELINE_ELEMENT (new_trackelement));
|
||||||
|
|
||||||
ges_track_element_split_bindings (trackelement, new_trackelement,
|
ges_track_element_copy_bindings (trackelement, new_trackelement,
|
||||||
position - start + inpoint);
|
position - start + inpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -283,6 +283,31 @@ _get_track_types (GESTimelineElement * object)
|
||||||
return types ^ GES_TRACK_TYPE_UNKNOWN;
|
return types ^ GES_TRACK_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_paste (GESTimelineElement * element, GESTimelineElement * ref,
|
||||||
|
GstClockTime paste_position)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
GESContainer *self = GES_CONTAINER (element);
|
||||||
|
GESContainer *refcontainer = GES_CONTAINER (ref);
|
||||||
|
|
||||||
|
for (tmp = GES_CONTAINER_CHILDREN (refcontainer); tmp; tmp = tmp->next) {
|
||||||
|
ChildMapping *map;
|
||||||
|
GESTimelineElement *child, *refchild = GES_TIMELINE_ELEMENT (tmp->data);
|
||||||
|
|
||||||
|
map = g_hash_table_lookup (refcontainer->priv->mappings, refchild);
|
||||||
|
child = ges_timeline_element_copy (GES_TIMELINE_ELEMENT (refchild), TRUE);
|
||||||
|
|
||||||
|
ges_timeline_element_paste (child, paste_position + map->start_offset);
|
||||||
|
ges_timeline_element_set_timeline (element,
|
||||||
|
GES_TIMELINE_ELEMENT_TIMELINE (ref));
|
||||||
|
ges_container_add (self, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
* *
|
* *
|
||||||
* GObject virtual methods implementation *
|
* GObject virtual methods implementation *
|
||||||
|
@ -382,6 +407,7 @@ ges_container_class_init (GESContainerClass * klass)
|
||||||
element_class->list_children_properties = _list_children_properties;
|
element_class->list_children_properties = _list_children_properties;
|
||||||
element_class->lookup_child = _lookup_child;
|
element_class->lookup_child = _lookup_child;
|
||||||
element_class->get_track_types = _get_track_types;
|
element_class->get_track_types = _get_track_types;
|
||||||
|
element_class->paste = _paste;
|
||||||
|
|
||||||
/* No default implementations */
|
/* No default implementations */
|
||||||
klass->remove_child = NULL;
|
klass->remove_child = NULL;
|
||||||
|
|
|
@ -598,6 +598,23 @@ _group (GList * containers)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_paste (GESTimelineElement * element, GESTimelineElement * ref,
|
||||||
|
GstClockTime paste_position)
|
||||||
|
{
|
||||||
|
if (GES_TIMELINE_ELEMENT_CLASS (parent_class)->paste (element,
|
||||||
|
ref, paste_position)) {
|
||||||
|
|
||||||
|
if (GES_CONTAINER_CHILDREN (element))
|
||||||
|
timeline_add_group (GES_TIMELINE_ELEMENT_TIMELINE (GES_CONTAINER_CHILDREN
|
||||||
|
(element)->data), GES_GROUP (element));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
|
@ -675,6 +692,7 @@ ges_group_class_init (GESGroupClass * klass)
|
||||||
element_class->set_inpoint = _set_inpoint;
|
element_class->set_inpoint = _set_inpoint;
|
||||||
element_class->set_start = _set_start;
|
element_class->set_start = _set_start;
|
||||||
element_class->set_priority = _set_priority;
|
element_class->set_priority = _set_priority;
|
||||||
|
element_class->paste = _paste;
|
||||||
|
|
||||||
/* We override start, inpoint, duration and max-duration from GESTimelineElement
|
/* We override start, inpoint, duration and max-duration from GESTimelineElement
|
||||||
* in order to makes sure those fields are not serialized.
|
* in order to makes sure those fields are not serialized.
|
||||||
|
|
|
@ -339,7 +339,7 @@ G_GNUC_INTERNAL guint32 _ges_track_element_get_layer_priority (GESTrackElement
|
||||||
G_GNUC_INTERNAL void ges_track_element_copy_properties (GESTimelineElement * element,
|
G_GNUC_INTERNAL void ges_track_element_copy_properties (GESTimelineElement * element,
|
||||||
GESTimelineElement * elementcopy);
|
GESTimelineElement * elementcopy);
|
||||||
|
|
||||||
G_GNUC_INTERNAL void ges_track_element_split_bindings (GESTrackElement *element,
|
G_GNUC_INTERNAL void ges_track_element_copy_bindings (GESTrackElement *element,
|
||||||
GESTrackElement *new_element,
|
GESTrackElement *new_element,
|
||||||
guint64 position);
|
guint64 position);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,8 @@ struct _GESTimelineElementPrivate
|
||||||
* The hashtable should look like
|
* The hashtable should look like
|
||||||
* {GParamaSpec ---> child}*/
|
* {GParamaSpec ---> child}*/
|
||||||
GHashTable *children_props;
|
GHashTable *children_props;
|
||||||
|
|
||||||
|
GESTimelineElement *copied_from;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -240,6 +242,14 @@ _set_property (GObject * object, guint property_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_timeline_element_dispose (GObject * object)
|
||||||
|
{
|
||||||
|
GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->priv->copied_from);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ges_timeline_element_finalize (GObject * self)
|
ges_timeline_element_finalize (GObject * self)
|
||||||
{
|
{
|
||||||
|
@ -387,6 +397,7 @@ ges_timeline_element_class_init (GESTimelineElementClass * klass)
|
||||||
G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic,
|
G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic,
|
||||||
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM);
|
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM);
|
||||||
|
|
||||||
|
object_class->dispose = ges_timeline_element_dispose;
|
||||||
object_class->finalize = ges_timeline_element_finalize;
|
object_class->finalize = ges_timeline_element_finalize;
|
||||||
|
|
||||||
klass->set_parent = NULL;
|
klass->set_parent = NULL;
|
||||||
|
@ -1113,6 +1124,10 @@ ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
|
||||||
" on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
|
" on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deep) {
|
||||||
|
ret->priv->copied_from = gst_object_ref (self);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1661,8 +1676,48 @@ ges_timeline_element_remove_child_property (GESTimelineElement * self,
|
||||||
GESTrackType
|
GESTrackType
|
||||||
ges_timeline_element_get_track_types (GESTimelineElement * self)
|
ges_timeline_element_get_track_types (GESTimelineElement * self)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
|
g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
|
||||||
g_return_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types);
|
g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
|
||||||
|
0);
|
||||||
|
|
||||||
return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
|
return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ges_timeline_element_paste:
|
||||||
|
* @self: The #GESTimelineElement to paste
|
||||||
|
* @paste_position: The position in the timeline the element should
|
||||||
|
* be copied to, meaning it will become the start of @self
|
||||||
|
*
|
||||||
|
* Paste @self inside the timeline. @self must have been created
|
||||||
|
* using ges_timeline_element_copy with recurse=TRUE set,
|
||||||
|
* otherwise it will fail.
|
||||||
|
*
|
||||||
|
* Since: 1.6.0
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
ges_timeline_element_paste (GESTimelineElement * self,
|
||||||
|
GstClockTime paste_position)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
|
||||||
|
|
||||||
|
if (!self->priv->copied_from) {
|
||||||
|
GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
|
||||||
|
GST_ERROR_OBJECT (self, "No paste vmethod implemented");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
|
||||||
|
self->priv->copied_from, paste_position);
|
||||||
|
|
||||||
|
g_clear_object (&self->priv->copied_from);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -186,6 +186,8 @@ struct _GESTimelineElementClass
|
||||||
gboolean (*roll_end) (GESTimelineElement *self, guint64 end);
|
gboolean (*roll_end) (GESTimelineElement *self, guint64 end);
|
||||||
gboolean (*trim) (GESTimelineElement *self, guint64 start);
|
gboolean (*trim) (GESTimelineElement *self, guint64 start);
|
||||||
void (*deep_copy) (GESTimelineElement *self, GESTimelineElement *copy);
|
void (*deep_copy) (GESTimelineElement *self, GESTimelineElement *copy);
|
||||||
|
gboolean (*paste) (GESTimelineElement *self, GESTimelineElement *ref_element,
|
||||||
|
GstClockTime paste_position);
|
||||||
|
|
||||||
GParamSpec** (*list_children_properties) (GESTimelineElement * self, guint *n_properties);
|
GParamSpec** (*list_children_properties) (GESTimelineElement * self, guint *n_properties);
|
||||||
gboolean (*lookup_child) (GESTimelineElement *self, const gchar *prop_name,
|
gboolean (*lookup_child) (GESTimelineElement *self, const gchar *prop_name,
|
||||||
|
@ -277,6 +279,9 @@ gboolean ges_timeline_element_add_child_property (GESTimelineElement * self,
|
||||||
gboolean ges_timeline_element_remove_child_property(GESTimelineElement * self,
|
gboolean ges_timeline_element_remove_child_property(GESTimelineElement * self,
|
||||||
GParamSpec *pspec);
|
GParamSpec *pspec);
|
||||||
|
|
||||||
|
gboolean ges_timeline_element_paste (GESTimelineElement * self,
|
||||||
|
GstClockTime paste_position);
|
||||||
|
|
||||||
GESTrackType ges_timeline_element_get_track_types (GESTimelineElement * self);
|
GESTrackType ges_timeline_element_get_track_types (GESTimelineElement * self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -1282,12 +1282,77 @@ ges_track_element_copy_properties (GESTimelineElement * element,
|
||||||
g_free (specs);
|
g_free (specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_split_binding (GESTrackElement * element, GESTrackElement * new_element,
|
||||||
|
guint64 position, GstTimedValueControlSource * source,
|
||||||
|
GstTimedValueControlSource * new_source, gboolean absolute)
|
||||||
|
{
|
||||||
|
GstTimedValue *last_value = NULL;
|
||||||
|
gboolean past_position = FALSE;
|
||||||
|
GList *values, *tmp;
|
||||||
|
|
||||||
|
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 > position) {
|
||||||
|
gfloat value_at_pos;
|
||||||
|
|
||||||
|
/* FIXME We should be able to use gst_control_source_get_value so
|
||||||
|
* all modes are handled. Right now that method only works if the value
|
||||||
|
* we are looking for is between two actual keyframes which is not enough
|
||||||
|
* in our case. bug #706621 */
|
||||||
|
value_at_pos =
|
||||||
|
interpolate_values_for_position (last_value, value, position,
|
||||||
|
absolute);
|
||||||
|
|
||||||
|
past_position = TRUE;
|
||||||
|
|
||||||
|
gst_timed_value_control_source_set (new_source, position, value_at_pos);
|
||||||
|
gst_timed_value_control_source_set (new_source, value->timestamp,
|
||||||
|
value->value);
|
||||||
|
gst_timed_value_control_source_unset (source, value->timestamp);
|
||||||
|
gst_timed_value_control_source_set (source, position, value_at_pos);
|
||||||
|
} else if (past_position) {
|
||||||
|
gst_timed_value_control_source_unset (source, value->timestamp);
|
||||||
|
gst_timed_value_control_source_set (new_source, value->timestamp,
|
||||||
|
value->value);
|
||||||
|
}
|
||||||
|
last_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_copy_binding (GESTrackElement * element, GESTrackElement * new_element,
|
||||||
|
guint64 position, GstTimedValueControlSource * source,
|
||||||
|
GstTimedValueControlSource * new_source, gboolean absolute)
|
||||||
|
{
|
||||||
|
GList *values, *tmp;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
gst_timed_value_control_source_set (new_source, value->timestamp,
|
||||||
|
value->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* position == GST_CLOCK_TIME_NONE means that we do a simple copy
|
||||||
|
* other position means that the function will do a splitting
|
||||||
|
* and thus interpollate the values in the element and new_element
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
ges_track_element_split_bindings (GESTrackElement * element,
|
ges_track_element_copy_bindings (GESTrackElement * element,
|
||||||
GESTrackElement * new_element, guint64 position)
|
GESTrackElement * new_element, guint64 position)
|
||||||
{
|
{
|
||||||
GParamSpec **specs;
|
GParamSpec **specs;
|
||||||
guint n, n_specs;
|
guint n, n_specs;
|
||||||
|
gboolean absolute;
|
||||||
GstControlBinding *binding;
|
GstControlBinding *binding;
|
||||||
GstTimedValueControlSource *source, *new_source;
|
GstTimedValueControlSource *source, *new_source;
|
||||||
|
|
||||||
|
@ -1295,60 +1360,31 @@ ges_track_element_split_bindings (GESTrackElement * element,
|
||||||
ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
|
ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
|
||||||
&n_specs);
|
&n_specs);
|
||||||
for (n = 0; n < n_specs; ++n) {
|
for (n = 0; n < n_specs; ++n) {
|
||||||
GList *values, *tmp;
|
|
||||||
GstTimedValue *last_value = NULL;
|
|
||||||
gboolean past_position = FALSE, absolute;
|
|
||||||
GstInterpolationMode mode;
|
GstInterpolationMode mode;
|
||||||
|
|
||||||
binding = ges_track_element_get_control_binding (element, specs[n]->name);
|
binding = ges_track_element_get_control_binding (element, specs[n]->name);
|
||||||
if (!binding)
|
if (!binding)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_object_get (binding, "control_source", &source, NULL);
|
|
||||||
|
|
||||||
/* FIXME : this should work as well with other types of control sources */
|
/* FIXME : this should work as well with other types of control sources */
|
||||||
|
g_object_get (binding, "control_source", &source, NULL);
|
||||||
if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source))
|
if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_object_get (binding, "absolute", &absolute, NULL);
|
g_object_get (binding, "absolute", &absolute, NULL);
|
||||||
|
g_object_get (source, "mode", &mode, NULL);
|
||||||
|
|
||||||
new_source =
|
new_source =
|
||||||
GST_TIMED_VALUE_CONTROL_SOURCE (gst_interpolation_control_source_new
|
GST_TIMED_VALUE_CONTROL_SOURCE (gst_interpolation_control_source_new
|
||||||
());
|
());
|
||||||
|
|
||||||
g_object_get (source, "mode", &mode, NULL);
|
|
||||||
g_object_set (new_source, "mode", mode, NULL);
|
g_object_set (new_source, "mode", mode, NULL);
|
||||||
|
|
||||||
values =
|
if (GST_CLOCK_TIME_IS_VALID (position))
|
||||||
gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
|
_split_binding (element, new_element, position, source, new_source,
|
||||||
(source));
|
absolute);
|
||||||
for (tmp = values; tmp; tmp = tmp->next) {
|
else
|
||||||
GstTimedValue *value = tmp->data;
|
_copy_binding (element, new_element, position, source, new_source,
|
||||||
if (value->timestamp > position) {
|
absolute);
|
||||||
gfloat value_at_pos;
|
|
||||||
|
|
||||||
/* FIXME We should be able to use gst_control_source_get_value so
|
|
||||||
* all modes are handled. Right now that method only works if the value
|
|
||||||
* we are looking for is between two actual keyframes which is not enough
|
|
||||||
* in our case. bug #706621 */
|
|
||||||
value_at_pos =
|
|
||||||
interpolate_values_for_position (last_value, value, position,
|
|
||||||
absolute);
|
|
||||||
|
|
||||||
past_position = TRUE;
|
|
||||||
|
|
||||||
gst_timed_value_control_source_set (new_source, position, value_at_pos);
|
|
||||||
gst_timed_value_control_source_set (new_source, value->timestamp,
|
|
||||||
value->value);
|
|
||||||
gst_timed_value_control_source_unset (source, value->timestamp);
|
|
||||||
gst_timed_value_control_source_set (source, position, value_at_pos);
|
|
||||||
} else if (past_position) {
|
|
||||||
gst_timed_value_control_source_unset (source, value->timestamp);
|
|
||||||
gst_timed_value_control_source_set (new_source, value->timestamp,
|
|
||||||
value->value);
|
|
||||||
}
|
|
||||||
last_value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We only manage direct (absolute) bindings, see TODO in set_control_source */
|
/* We only manage direct (absolute) bindings, see TODO in set_control_source */
|
||||||
if (absolute)
|
if (absolute)
|
||||||
|
|
Loading…
Reference in a new issue