mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
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:
parent
30a821e136
commit
343e8581f2
5 changed files with 62 additions and 45 deletions
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue