Fix: VSE: hang after making meta strip

Caused by incorrectly using mutable `ListBase` iterator, which caused
adding same strip to meta twice. This caused `next` and `prev` fields
to be set to same value resulting in infinite loop in next iterator.

Since multiple strips can be removed from list in one iteration, collect
these into `VectorSet` and move them in separate for loop.

Also do cache invalidation while strips are in original `seqbase`,
otherwise it can skip invalidation of strips downstream.

Pull Request: https://projects.blender.org/blender/blender/pulls/127951
This commit is contained in:
Richard Antalik
2024-09-23 18:51:54 +02:00
committed by Richard Antalik
parent c31893ed87
commit 8da413877b

View File

@@ -2059,22 +2059,24 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
/* Remove all selected from main list, and put in meta.
* Sequence is moved within the same edit, no need to re-generate the UID. */
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, active_seqbase) {
blender::VectorSet<Sequence *> strips_to_move;
LISTBASE_FOREACH (Sequence *, seq, active_seqbase) {
if (seq != seqm && seq->flag & SELECT) {
blender::VectorSet<Sequence *> related = SEQ_get_connected_strips(seq);
related.add(seq);
for (Sequence *rel : related) {
BLI_remlink(active_seqbase, rel);
BLI_addtail(&seqm->seqbase, rel);
SEQ_relations_invalidate_cache_preprocessed(scene, rel);
channel_max = max_ii(rel->machine, channel_max);
channel_min = min_ii(rel->machine, channel_min);
meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(scene, rel), meta_start_frame);
meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(scene, rel), meta_end_frame);
}
strips_to_move.add(seq);
strips_to_move.add_multiple(SEQ_get_connected_strips(seq));
}
}
for (Sequence *seq : strips_to_move) {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
BLI_remlink(active_seqbase, seq);
BLI_addtail(&seqm->seqbase, seq);
channel_max = max_ii(seq->machine, channel_max);
channel_min = min_ii(seq->machine, channel_min);
meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(scene, seq), meta_start_frame);
meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(scene, seq), meta_end_frame);
}
ListBase *channels_cur = SEQ_channels_displayed_get(ed);
ListBase *channels_meta = &seqm->channels;
for (int i = channel_min; i <= channel_max; i++) {