timeline-tree: freeze auto-transitions whilst editing

Freeze the auto-tranistions so they do not destroy themselves during an
edit. Once complete the auto-transitions can move themselves back into
position, or remove themselves if their sources are no longer
overlapping.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/169>
This commit is contained in:
Henry Wilkes 2020-04-22 15:06:32 +01:00
parent 30a821e136
commit 343e8581f2
5 changed files with 62 additions and 45 deletions

View file

@ -43,33 +43,25 @@ neighbour_changed_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED,
GESAutoTransition * self) GESAutoTransition * self)
{ {
gint64 new_duration; gint64 new_duration;
GESTimelineElement *parent = guint32 layer_prio;
ges_timeline_element_peak_toplevel (GES_TIMELINE_ELEMENT (clip)); GESLayer *layer;
GESTimeline *timeline;
if (GES_TIMELINE_ELEMENT_BEING_EDITED (parent)) if (self->frozen) {
return; GST_LOG_OBJECT (self, "Not updating because frozen");
if (parent) {
GESTimelineElement *prev_topparent =
ges_timeline_element_peak_toplevel (GES_TIMELINE_ELEMENT
(self->next_source));
GESTimelineElement *next_topparent =
ges_timeline_element_peak_toplevel (GES_TIMELINE_ELEMENT
(self->previous_source));
if (GES_TIMELINE_ELEMENT_BEING_EDITED (prev_topparent) ||
GES_TIMELINE_ELEMENT_BEING_EDITED (next_topparent))
return;
if (parent == prev_topparent && parent == next_topparent) {
GST_DEBUG_OBJECT (self,
"Moving all inside the same group, nothing to do");
return; return;
} }
if (self->positioning) {
/* this can happen when the transition is moved layers as the layer
* may resync its priorities */
GST_LOG_OBJECT (self, "Not updating because positioning");
return;
} }
if (GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->next_source) != layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->next_source);
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->previous_source)) {
if (layer_prio != GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->previous_source)) {
GST_DEBUG_OBJECT (self, "Destroy changed layer"); GST_DEBUG_OBJECT (self, "Destroy changed layer");
g_signal_emit (self, auto_transition_signals[DESTROY_ME], 0); g_signal_emit (self, auto_transition_signals[DESTROY_ME], 0);
return; return;
@ -88,13 +80,24 @@ neighbour_changed_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED,
return; return;
} }
timeline = GES_TIMELINE_ELEMENT_TIMELINE (self->transition_clip);
layer = timeline ? ges_timeline_get_layer (timeline, layer_prio) : NULL;
if (!layer) {
GST_DEBUG_OBJECT (self, "Destroy no layer");
g_signal_emit (self, auto_transition_signals[DESTROY_ME], 0);
return;
}
self->positioning = TRUE; self->positioning = TRUE;
GES_TIMELINE_ELEMENT_SET_BEING_EDITED (self->transition_clip); GES_TIMELINE_ELEMENT_SET_BEING_EDITED (self->transition_clip);
_set_start0 (GES_TIMELINE_ELEMENT (self->transition_clip), _set_start0 (GES_TIMELINE_ELEMENT (self->transition_clip),
_START (self->next_source)); _START (self->next_source));
_set_duration0 (GES_TIMELINE_ELEMENT (self->transition_clip), new_duration); _set_duration0 (GES_TIMELINE_ELEMENT (self->transition_clip), new_duration);
ges_clip_move_to_layer (self->transition_clip, layer);
GES_TIMELINE_ELEMENT_UNSET_BEING_EDITED (self->transition_clip); GES_TIMELINE_ELEMENT_UNSET_BEING_EDITED (self->transition_clip);
self->positioning = FALSE; self->positioning = FALSE;
gst_object_unref (layer);
} }
static void static void
@ -153,6 +156,7 @@ ges_auto_transition_new (GESTrackElement * transition,
{ {
GESAutoTransition *self = g_object_new (GES_TYPE_AUTO_TRANSITION, NULL); GESAutoTransition *self = g_object_new (GES_TYPE_AUTO_TRANSITION, NULL);
self->frozen = FALSE;
self->previous_source = previous_source; self->previous_source = previous_source;
self->next_source = next_source; self->next_source = next_source;
self->transition = transition; self->transition = transition;

View file

@ -58,6 +58,8 @@ struct _GESAutoTransition
gchar *key; gchar *key;
gboolean frozen;
/* Padding for API extension */ /* Padding for API extension */
gpointer _ges_reserved[GES_PADDING]; gpointer _ges_reserved[GES_PADDING];
}; };

View file

@ -103,6 +103,8 @@ GstDebugCategory * _ges_debug (void);
#define SUPRESS_UNUSED_WARNING(a) (void)a #define SUPRESS_UNUSED_WARNING(a) (void)a
G_GNUC_INTERNAL void
ges_timeline_freeze_auto_transitions (GESTimeline * timeline, gboolean freeze);
G_GNUC_INTERNAL gboolean G_GNUC_INTERNAL gboolean
ges_timeline_edit (GESTimeline * timeline, GESTimelineElement * element, ges_timeline_edit (GESTimeline * timeline, GESTimelineElement * element,
@ -135,10 +137,6 @@ G_GNUC_INTERNAL
GNode * GNode *
timeline_get_tree (GESTimeline *timeline); timeline_get_tree (GESTimeline *timeline);
G_GNUC_INTERNAL
void
timeline_update_transition (GESTimeline *timeline);
G_GNUC_INTERNAL G_GNUC_INTERNAL
void void
timeline_fill_gaps (GESTimeline *timeline); timeline_fill_gaps (GESTimeline *timeline);

View file

@ -1541,6 +1541,9 @@ timeline_tree_perform_edits (GNode * root, GHashTable * edits)
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
/* freeze the auto-transitions whilst we edit */
ges_timeline_freeze_auto_transitions (root->data, TRUE);
g_hash_table_iter_init (&iter, edits); g_hash_table_iter_init (&iter, edits);
while (g_hash_table_iter_next (&iter, &key, &value)) { while (g_hash_table_iter_next (&iter, &key, &value)) {
GESTimelineElement *element = key; GESTimelineElement *element = key;
@ -1548,9 +1551,10 @@ timeline_tree_perform_edits (GNode * root, GHashTable * edits)
if (!perform_element_edit (element, edit_data)) if (!perform_element_edit (element, edit_data))
no_errors = FALSE; no_errors = FALSE;
} }
/* allow the transitions to update if they can */
ges_timeline_freeze_auto_transitions (root->data, FALSE);
timeline_tree_create_transitions (root, ges_timeline_find_auto_transition); timeline_tree_create_transitions (root, ges_timeline_find_auto_transition);
timeline_update_transition (root->data);
timeline_update_duration (root->data); timeline_update_duration (root->data);
return no_errors; return no_errors;
@ -2032,6 +2036,10 @@ create_transition_if_needed (GESTimeline * timeline, GESTrackElement * prev,
"]", _START (next), duration); "]", _START (next), duration);
ges_timeline_create_transition (timeline, prev, next, NULL, layer, ges_timeline_create_transition (timeline, prev, next, NULL, layer,
_START (next), duration); _START (next), duration);
} else {
GST_INFO ("Already have transition %" GES_FORMAT " between %" GES_FORMAT
" and %" GES_FORMAT, GES_ARGS (trans), GES_ARGS (prev),
GES_ARGS (next));
} }
} }
@ -2043,12 +2051,10 @@ create_transitions (GNode * node,
GESTimeline *timeline; GESTimeline *timeline;
GESLayer *layer; GESLayer *layer;
if (G_NODE_IS_ROOT (node)) if (!GES_IS_SOURCE (node->data))
return FALSE; return FALSE;
timeline = GES_TIMELINE_ELEMENT_TIMELINE (node->data); timeline = GES_TIMELINE_ELEMENT_TIMELINE (node->data);
if (!GES_IS_SOURCE (node->data))
return FALSE;
if (!timeline) { if (!timeline) {
GST_INFO ("%" GES_FORMAT " not in timeline yet", GES_ARGS (node->data)); GST_INFO ("%" GES_FORMAT " not in timeline yet", GES_ARGS (node->data));
@ -2064,6 +2070,7 @@ create_transitions (GNode * node,
if (!ges_layer_get_auto_transition (layer)) if (!ges_layer_get_auto_transition (layer))
return FALSE; return FALSE;
GST_LOG (node->data, "Checking for overlaps");
data.root = g_node_get_root (node); data.root = g_node_get_root (node);
check_all_overlaps_with_element (node, &data); check_all_overlaps_with_element (node, &data);

View file

@ -1110,6 +1110,24 @@ done:
} }
} }
void
ges_timeline_freeze_auto_transitions (GESTimeline * timeline, gboolean freeze)
{
GList *tmp, *trans = g_list_copy (timeline->priv->auto_transitions);
for (tmp = trans; tmp; tmp = tmp->next) {
GESAutoTransition *auto_transition = tmp->data;
auto_transition->frozen = freeze;
if (freeze == FALSE) {
GST_LOG_OBJECT (timeline, "Un-Freezing %" GES_FORMAT,
GES_ARGS (auto_transition->transition_clip));
ges_auto_transition_update (auto_transition);
} else {
GST_LOG_OBJECT (timeline, "Freezing %" GES_FORMAT,
GES_ARGS (auto_transition->transition_clip));
}
}
g_list_free (trans);
}
static gint static gint
_edit_auto_transition (GESTimeline * timeline, GESTimelineElement * element, _edit_auto_transition (GESTimeline * timeline, GESTimelineElement * element,
@ -1217,17 +1235,6 @@ timeline_add_group (GESTimeline * timeline, GESGroup * group)
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), timeline); ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), timeline);
} }
void
timeline_update_transition (GESTimeline * timeline)
{
GList *tmp, *auto_transs;
auto_transs = g_list_copy (timeline->priv->auto_transitions);
for (tmp = auto_transs; tmp; tmp = tmp->next)
ges_auto_transition_update (tmp->data);
g_list_free (auto_transs);
}
/** /**
* timeline_emit_group_added: * timeline_emit_group_added:
* @timeline: The #GESTimeline * @timeline: The #GESTimeline
@ -1689,8 +1696,7 @@ ges_timeline_add_clip (GESTimeline * timeline, GESClip * clip)
if (ges_clip_is_moving_from_layer (clip)) { if (ges_clip_is_moving_from_layer (clip)) {
GST_DEBUG ("Clip %p moving from one layer to another, not creating " GST_DEBUG ("Clip %p moving from one layer to another, not creating "
"TrackElement", clip); "TrackElement", clip);
timeline_tree_create_transitions (timeline->priv->tree, /* timeline-tree handles creation of auto-transitions */
ges_timeline_find_auto_transition);
ret = TRUE; ret = TRUE;
} else { } else {
ret = add_object_to_tracks (timeline, clip, NULL); ret = add_object_to_tracks (timeline, clip, NULL);