From 343e8581f2b574766c81e0d1632d837f7956ce0f Mon Sep 17 00:00:00 2001 From: Henry Wilkes Date: Wed, 22 Apr 2020 15:06:32 +0100 Subject: [PATCH] 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: --- ges/ges-auto-transition.c | 50 +++++++++++++++++++++------------------ ges/ges-auto-transition.h | 4 +++- ges/ges-internal.h | 6 ++--- ges/ges-timeline-tree.c | 15 ++++++++---- ges/ges-timeline.c | 32 +++++++++++++++---------- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/ges/ges-auto-transition.c b/ges/ges-auto-transition.c index df0c4cc1fc..dd89c4a53c 100644 --- a/ges/ges-auto-transition.c +++ b/ges/ges-auto-transition.c @@ -43,33 +43,25 @@ neighbour_changed_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED, GESAutoTransition * self) { gint64 new_duration; - GESTimelineElement *parent = - ges_timeline_element_peak_toplevel (GES_TIMELINE_ELEMENT (clip)); + guint32 layer_prio; + GESLayer *layer; + GESTimeline *timeline; - if (GES_TIMELINE_ELEMENT_BEING_EDITED (parent)) + if (self->frozen) { + GST_LOG_OBJECT (self, "Not updating because frozen"); return; - - 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; - } } - if (GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->next_source) != - GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->previous_source)) { + 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; + } + + layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->next_source); + + if (layer_prio != GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self->previous_source)) { GST_DEBUG_OBJECT (self, "Destroy changed layer"); g_signal_emit (self, auto_transition_signals[DESTROY_ME], 0); return; @@ -88,13 +80,24 @@ neighbour_changed_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED, 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; GES_TIMELINE_ELEMENT_SET_BEING_EDITED (self->transition_clip); _set_start0 (GES_TIMELINE_ELEMENT (self->transition_clip), _START (self->next_source)); _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); self->positioning = FALSE; + + gst_object_unref (layer); } static void @@ -153,6 +156,7 @@ ges_auto_transition_new (GESTrackElement * transition, { GESAutoTransition *self = g_object_new (GES_TYPE_AUTO_TRANSITION, NULL); + self->frozen = FALSE; self->previous_source = previous_source; self->next_source = next_source; self->transition = transition; diff --git a/ges/ges-auto-transition.h b/ges/ges-auto-transition.h index 4be91a8fd5..a6e2ebb34e 100644 --- a/ges/ges-auto-transition.h +++ b/ges/ges-auto-transition.h @@ -58,6 +58,8 @@ struct _GESAutoTransition gchar *key; + gboolean frozen; + /* Padding for API extension */ gpointer _ges_reserved[GES_PADDING]; }; @@ -67,4 +69,4 @@ G_GNUC_INTERNAL GESAutoTransition * ges_auto_transition_new (GESTrackElement * t GESTrackElement * previous_source, GESTrackElement * next_source); -G_END_DECLS \ No newline at end of file +G_END_DECLS diff --git a/ges/ges-internal.h b/ges/ges-internal.h index 756a12b272..5c4100649c 100644 --- a/ges/ges-internal.h +++ b/ges/ges-internal.h @@ -103,6 +103,8 @@ GstDebugCategory * _ges_debug (void); #define SUPRESS_UNUSED_WARNING(a) (void)a +G_GNUC_INTERNAL void +ges_timeline_freeze_auto_transitions (GESTimeline * timeline, gboolean freeze); G_GNUC_INTERNAL gboolean ges_timeline_edit (GESTimeline * timeline, GESTimelineElement * element, @@ -135,10 +137,6 @@ G_GNUC_INTERNAL GNode * timeline_get_tree (GESTimeline *timeline); -G_GNUC_INTERNAL -void -timeline_update_transition (GESTimeline *timeline); - G_GNUC_INTERNAL void timeline_fill_gaps (GESTimeline *timeline); diff --git a/ges/ges-timeline-tree.c b/ges/ges-timeline-tree.c index 9bc85b3717..851e25ea06 100644 --- a/ges/ges-timeline-tree.c +++ b/ges/ges-timeline-tree.c @@ -1541,6 +1541,9 @@ timeline_tree_perform_edits (GNode * root, GHashTable * edits) GHashTableIter iter; 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); while (g_hash_table_iter_next (&iter, &key, &value)) { GESTimelineElement *element = key; @@ -1548,9 +1551,10 @@ timeline_tree_perform_edits (GNode * root, GHashTable * edits) if (!perform_element_edit (element, edit_data)) 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_update_transition (root->data); timeline_update_duration (root->data); return no_errors; @@ -2032,6 +2036,10 @@ create_transition_if_needed (GESTimeline * timeline, GESTrackElement * prev, "]", _START (next), duration); ges_timeline_create_transition (timeline, prev, next, NULL, layer, _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; GESLayer *layer; - if (G_NODE_IS_ROOT (node)) + if (!GES_IS_SOURCE (node->data)) return FALSE; timeline = GES_TIMELINE_ELEMENT_TIMELINE (node->data); - if (!GES_IS_SOURCE (node->data)) - return FALSE; if (!timeline) { 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)) return FALSE; + GST_LOG (node->data, "Checking for overlaps"); data.root = g_node_get_root (node); check_all_overlaps_with_element (node, &data); diff --git a/ges/ges-timeline.c b/ges/ges-timeline.c index 26ed9904a2..71e90b8c75 100644 --- a/ges/ges-timeline.c +++ b/ges/ges-timeline.c @@ -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 _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); } -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: The #GESTimeline @@ -1689,8 +1696,7 @@ ges_timeline_add_clip (GESTimeline * timeline, GESClip * clip) if (ges_clip_is_moving_from_layer (clip)) { GST_DEBUG ("Clip %p moving from one layer to another, not creating " "TrackElement", clip); - timeline_tree_create_transitions (timeline->priv->tree, - ges_timeline_find_auto_transition); + /* timeline-tree handles creation of auto-transitions */ ret = TRUE; } else { ret = add_object_to_tracks (timeline, clip, NULL);