Page MenuHome

Better handling of effect strip splitting
ClosedPublic

Authored by Richard Antalik (ISS) on Jan 26 2021, 2:16 PM.

Details

Summary

Splitting of effect strip alone wasn't handled properly. Previously
this resulted in duplicating effect strip, and it was broken at least
from 2.79.

Change in rB8ec6b34b8eb2 was intended to allow splitting strips
individually, so it can be used as RNA API function but also so it
requires as little glue logic as possible.

This is fixed by splitting all dependent strips at once in 2 separate
ListBases for left and right strips. Strips can be finally moved into
original ListBase.

With this fix it is still possible to split strips individually with
little glue logic. RNA API function could return list of split strips
as well, currently at least one strip in chain will be provided so
chain can be reconstructed on python side.

Test file:

Diff Detail

Repository
rB Blender

Event Timeline

Richard Antalik (ISS) requested review of this revision.Jan 26 2021, 2:16 PM
  • Remove unused include

In order to get this patch to compiled with strict flags I had to apply P1916.

Assuming those warnings are resolved, the new behavior seems to make more sense from user perspective than silently creating overlapping strips. Ont thing I've noticed is that if you have image and effect, and try to cut image without effect selected the effect strip is not cut and its length is only evaluated once you move strip. This is something to look into.


That being said, this change is not really a fix for the crash, but rather masquerades it. I will leave a comment in T84847 about what's going on and suggestion of how to move forward.

Sergey Sharybin (sergey) requested changes to this revision.Jan 26 2021, 3:53 PM
This revision now requires changes to proceed.Jan 26 2021, 3:53 PM

In order to get this patch to compiled with strict flags I had to apply P1916.

Assuming those warnings are resolved, the new behavior seems to make more sense from user perspective than silently creating overlapping strips. Ont thing I've noticed is that if you have image and effect, and try to cut image without effect selected the effect strip is not cut and its length is only evaluated once you move strip. This is something to look into.


That being said, this change is not really a fix for the crash, but rather masquerades it. I will leave a comment in T84847 about what's going on and suggestion of how to move forward.

Thanks I haven't checked the cause of crash before making this patch.

P1917 seems more reasonable as fix for 2.92 I would say. So I will change this patch to general development instead of bugfix.

  • Fix build issues
Richard Antalik (ISS) retitled this revision from Fix T84847: Crash after splitting effect strip to Better handling of effect strip splitting.Jan 26 2021, 4:49 PM
Richard Antalik (ISS) edited the summary of this revision. (Show Details)
  • Return on failed precondition

Alternative version based on new iterator:

1diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
2index 9c204373ffc..e215041b374 100644
3--- a/source/blender/editors/space_sequencer/sequencer_edit.c
4+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
5@@ -1570,52 +1570,41 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
6
7 RNA_def_property_flag(prop, PROP_HIDDEN);
8 }
9
10 /** \} */
11
12 /* -------------------------------------------------------------------- */
13 /** \name Duplicate Strips Operator
14 * \{ */
15
16-static int apply_unique_name_fn(Sequence *seq, void *arg_pt)
17-{
18- Scene *scene = (Scene *)arg_pt;
19- char name[sizeof(seq->name) - 2];
20-
21- BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
22- SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
23- SEQ_dupe_animdata(scene, name, seq->name + 2);
24- return 1;
25-}
26-
27 static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
28 {
29 Scene *scene = CTX_data_scene(C);
30 Editing *ed = SEQ_editing_get(scene, false);
31
32 ListBase nseqbase = {NULL, NULL};
33
34 if (ed == NULL) {
35 return OPERATOR_CANCELLED;
36 }
37
38 SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0);
39
40 if (nseqbase.first) {
41 Sequence *seq = nseqbase.first;
42 /* Rely on the nseqbase list being added at the end.
43 * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
44 BLI_movelisttolist(ed->seqbasep, &nseqbase);
45
46 for (; seq; seq = seq->next) {
47- SEQ_recursive_apply(seq, apply_unique_name_fn, scene);
48+ SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene);
49 }
50
51 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
52 return OPERATOR_FINISHED;
53 }
54
55 return OPERATOR_CANCELLED;
56 }
57
58 void SEQUENCER_OT_duplicate(wmOperatorType *ot)
59@@ -2458,21 +2447,21 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
60 SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard);
61
62 iseq_first = nseqbase.first;
63
64 /* NOTE: SEQ_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences
65 * in the new list. */
66 BLI_movelisttolist(ed->seqbasep, &nseqbase);
67
68 for (iseq = iseq_first; iseq; iseq = iseq->next) {
69 /* Make sure, that pasted strips have unique names. */
70- SEQ_recursive_apply(iseq, apply_unique_name_fn, scene);
71+ SEQ_recursive_apply(iseq, SEQ_apply_unique_name_fn, scene);
72 /* Translate after name has been changed, otherwise this will affect animdata of original
73 * strip. */
74 SEQ_transform_translate_sequence(scene, iseq, ofs);
75 /* Ensure, that pasted strips don't overlap. */
76 if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) {
77 SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene);
78 }
79 }
80
81 DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
82diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
83index 0eaf8cc02ea..2fbf96419ba 100644
84--- a/source/blender/editors/space_sequencer/sequencer_select.c
85+++ b/source/blender/editors/space_sequencer/sequencer_select.c
86@@ -1614,51 +1614,20 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
87 LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
88 if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
89 seq->flag |= SELECT;
90 changed = true;
91 }
92 }
93
94 return changed;
95 }
96
97-/* Query all effect strips that are directly or indirectly connected to seq_reference. */
98-void query_strip_effect_chain(Sequence *seq_reference,
99- ListBase *seqbase,
100- SeqCollection *collection)
101-{
102- if (!SEQ_collection_append_strip(seq_reference, collection)) {
103- return; /* Strip is already in set, so all effects connected to it are as well. */
104- }
105-
106- /* Find all strips that seq_reference is connected to. */
107- if (seq_reference->type & SEQ_TYPE_EFFECT) {
108- if (seq_reference->seq1) {
109- query_strip_effect_chain(seq_reference->seq1, seqbase, collection);
110- }
111- if (seq_reference->seq2) {
112- query_strip_effect_chain(seq_reference->seq2, seqbase, collection);
113- }
114- if (seq_reference->seq3) {
115- query_strip_effect_chain(seq_reference->seq3, seqbase, collection);
116- }
117- }
118-
119- /* Find all strips connected to seq_reference. */
120- LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
121- if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference ||
122- seq_test->seq3 == seq_reference) {
123- query_strip_effect_chain(seq_test, seqbase, collection);
124- }
125- }
126-}
127-
128 /* Query strips that are in lower channel and intersect in time with seq_reference. */
129 static void query_lower_channel_strips(Sequence *seq_reference,
130 ListBase *seqbase,
131 SeqCollection *collection)
132 {
133 LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
134 if (seq_test->machine > seq_reference->machine) {
135 continue; /* Not lower channel. */
136 }
137 if (seq_test->enddisp <= seq_reference->startdisp ||
138@@ -1672,21 +1641,21 @@ static void query_lower_channel_strips(Sequence *seq_reference,
139 /* Select all strips within time range and with lower channel of initial selection. Then select
140 * effect chains of these strips. */
141 static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
142 {
143 ListBase *seqbase = SEQ_active_seqbase_get(ed);
144
145 /* Get collection of strips. */
146 SeqCollection *collection = SEQ_query_selected_strips(seqbase);
147 const int selected_strip_count = BLI_gset_len(collection->set);
148 SEQ_collection_expand(seqbase, collection, query_lower_channel_strips);
149- SEQ_collection_expand(seqbase, collection, query_strip_effect_chain);
150+ SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
151
152 /* Check if other strips will be affected. */
153 const bool changed = BLI_gset_len(collection->set) > selected_strip_count;
154
155 /* Actual logic. */
156 SEQ_ITERATOR_FOREACH (seq, collection) {
157 seq->flag |= SELECT;
158 }
159 SEQ_collection_free(collection);
160
161diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
162index ac1d958add5..a440cc0744b 100644
163--- a/source/blender/sequencer/SEQ_iterator.h
164+++ b/source/blender/sequencer/SEQ_iterator.h
165@@ -72,14 +72,17 @@ void SEQ_collection_expand(struct ListBase *seqbase,
166 void query_func(struct Sequence *seq_reference,
167 struct ListBase *seqbase,
168 SeqCollection *collection));
169 SeqCollection *SEQ_reference_query(struct Sequence *seq_reference,
170 struct ListBase *seqbase,
171 void seq_query_func(struct Sequence *seq_reference,
172 struct ListBase *seqbase,
173 SeqCollection *collection));
174 SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase);
175 SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
176+void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
177+ struct ListBase *seqbase,
178+ SeqCollection *collection);
179
180 #ifdef __cplusplus
181 }
182 #endif
183diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
184index 52fac5d7d0e..51d63d365f0 100644
185--- a/source/blender/sequencer/SEQ_utils.h
186+++ b/source/blender/sequencer/SEQ_utils.h
187@@ -53,13 +53,14 @@ void SEQ_set_scale_to_fit(const struct Sequence *seq,
188 const int image_height,
189 const int preview_width,
190 const int preview_height,
191 const eSeqImageFitMethod fit_method);
192 int SEQ_seqbase_recursive_apply(struct ListBase *seqbase,
193 int (*apply_fn)(struct Sequence *seq, void *),
194 void *arg);
195 int SEQ_recursive_apply(struct Sequence *seq,
196 int (*apply_fn)(struct Sequence *, void *),
197 void *arg);
198+int SEQ_apply_unique_name_fn(struct Sequence *seq, void *arg_pt);
199 #ifdef __cplusplus
200 }
201 #endif
202diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
203index ab34be2bfd8..305e7e2528a 100644
204--- a/source/blender/sequencer/intern/iterator.c
205+++ b/source/blender/sequencer/intern/iterator.c
206@@ -173,10 +173,47 @@ SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
207 {
208 SeqCollection *collection = SEQ_collection_create();
209 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
210 if ((seq->flag & SELECT) == 0) {
211 continue;
212 }
213 SEQ_collection_append_strip(seq, collection);
214 }
215 return collection;
216 }
217+
218+/**
219+ * Query all effect strips that are directly or indirectly connected to seq_reference.
220+ *
221+ * \param seq_reference: reference strip
222+ * \param seqbase: ListBase in which strips are queried
223+ * \param collection: collection to be filled
224+ */
225+void SEQ_query_strip_effect_chain(Sequence *seq_reference,
226+ ListBase *seqbase,
227+ SeqCollection *collection)
228+{
229+ if (!SEQ_collection_append_strip(seq_reference, collection)) {
230+ return; /* Strip is already in set, so all effects connected to it are as well. */
231+ }
232+
233+ /* Find all strips that seq_reference is connected to. */
234+ if (seq_reference->type & SEQ_TYPE_EFFECT) {
235+ if (seq_reference->seq1) {
236+ SEQ_query_strip_effect_chain(seq_reference->seq1, seqbase, collection);
237+ }
238+ if (seq_reference->seq2) {
239+ SEQ_query_strip_effect_chain(seq_reference->seq2, seqbase, collection);
240+ }
241+ if (seq_reference->seq3) {
242+ SEQ_query_strip_effect_chain(seq_reference->seq3, seqbase, collection);
243+ }
244+ }
245+
246+ /* Find all strips connected to seq_reference. */
247+ LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
248+ if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference ||
249+ seq_test->seq3 == seq_reference) {
250+ SEQ_query_strip_effect_chain(seq_test, seqbase, collection);
251+ }
252+ }
253+}
254diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
255index 4a27fb3a087..1cbc1c219fe 100644
256--- a/source/blender/sequencer/intern/strip_edit.c
257+++ b/source/blender/sequencer/intern/strip_edit.c
258@@ -32,24 +32,26 @@
259 #include "BLI_string.h"
260
261 #include "BLT_translation.h"
262
263 #include "BKE_main.h"
264 #include "BKE_movieclip.h"
265 #include "BKE_scene.h"
266 #include "BKE_sound.h"
267
268 #include "strip_time.h"
269+#include "utils.h"
270
271 #include "SEQ_add.h"
272 #include "SEQ_edit.h"
273 #include "SEQ_effects.h"
274+#include "SEQ_iterator.h"
275 #include "SEQ_relations.h"
276 #include "SEQ_sequencer.h"
277 #include "SEQ_time.h"
278 #include "SEQ_transform.h"
279 #include "SEQ_utils.h"
280
281 int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
282 {
283 char name[sizeof(seq_a->name)];
284
285@@ -336,20 +338,43 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame)
286 seq->startstill = seq->start - timeline_frame;
287 }
288 /* Adjust within range of extended stillframes after strip. */
289 if ((seq->start + seq->len) < timeline_frame) {
290 seq->start = timeline_frame - seq->len + 1;
291 seq->endstill = seq->enddisp - timeline_frame - 1;
292 }
293 SEQ_transform_set_left_handle_frame(seq, timeline_frame);
294 }
295
296+static void seq_edit_split_handle_strip_offsets(Main *bmain,
297+ Scene *scene,
298+ Sequence *left_seq,
299+ Sequence *right_seq,
300+ const int timeline_frame,
301+ const eSeqSplitMethod method)
302+{
303+ switch (method) {
304+ case SEQ_SPLIT_SOFT:
305+ seq_split_set_left_offset(right_seq, timeline_frame);
306+ seq_split_set_right_offset(left_seq, timeline_frame);
307+ break;
308+ case SEQ_SPLIT_HARD:
309+ seq_split_set_right_hold_offset(left_seq, timeline_frame);
310+ seq_split_set_left_hold_offset(right_seq, timeline_frame);
311+ SEQ_add_reload_new_file(bmain, scene, left_seq, false);
312+ SEQ_add_reload_new_file(bmain, scene, right_seq, false);
313+ break;
314+ }
315+ SEQ_time_update_sequence(scene, left_seq);
316+ SEQ_time_update_sequence(scene, right_seq);
317+}
318+
319 /**
320 * Split Sequence at timeline_frame in two.
321 *
322 * \param bmain: Main in which Sequence is located
323 * \param scene: Scene in which Sequence is located
324 * \param seqbase: ListBase in which Sequence is located
325 * \param seq: Sequence to be split
326 * \param timeline_frame: frame at which seq is split.
327 * \param method: affects type of offset to be applied to resize Sequence
328 * \return The newly created sequence strip. This is always Sequence on right side.
329@@ -358,47 +383,57 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
330 Scene *scene,
331 ListBase *seqbase,
332 Sequence *seq,
333 const int timeline_frame,
334 const eSeqSplitMethod method)
335 {
336 if (timeline_frame <= seq->startdisp || timeline_frame >= seq->enddisp) {
337 return NULL;
338 }
339
340- if (method == SEQ_SPLIT_HARD) {
341- /* Precaution, needed because the length saved on-disk may not match the length saved in the
342- * blend file, or our code may have minor differences reading file length between versions.
343- * This causes hard-split to fail, see: T47862. */
344- SEQ_add_reload_new_file(bmain, scene, seq, true);
345- SEQ_time_update_sequence(scene, seq);
346+ SeqCollection *collection = SEQ_collection_create();
347+ SEQ_collection_append_strip(seq, collection);
348+ SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
349+
350+ /* Move strips in collection from seqbase to new ListBase. */
351+ ListBase left_strips = {NULL, NULL};
352+ SEQ_ITERATOR_FOREACH (seq, collection) {
353+ BLI_remlink(seqbase, seq);
354+ BLI_addtail(&left_strips, seq);
355 }
356
357- Sequence *left_seq = seq;
358- Sequence *right_seq = SEQ_sequence_dupli_recursive(
359- scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
360+ /* Sort list, so that no strip can depend on next strip in list. */
361+ seq_sort_ex(&left_strips);
362+
363+ /* Duplicate ListBase. */
364+ ListBase right_strips = {NULL, NULL};
365+ SEQ_sequence_base_dupli_recursive(
366+ scene, scene, &right_strips, &left_strips, SEQ_DUPE_ANIM | SEQ_DUPE_ALL, 0);
367+
368+ /* Split strips. */
369+ Sequence *left_seq = left_strips.first;
370+ Sequence *right_seq = right_strips.first;
371+ Sequence *return_seq = right_strips.first;
372+ while (left_seq && right_seq) {
373+ seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
374+ left_seq = left_seq->next;
375+ right_seq = right_seq->next;
376+ }
377
378- switch (method) {
379- case SEQ_SPLIT_SOFT:
380- seq_split_set_left_offset(right_seq, timeline_frame);
381- seq_split_set_right_offset(left_seq, timeline_frame);
382- break;
383- case SEQ_SPLIT_HARD:
384- seq_split_set_right_hold_offset(left_seq, timeline_frame);
385- seq_split_set_left_hold_offset(right_seq, timeline_frame);
386- SEQ_add_reload_new_file(bmain, scene, left_seq, false);
387- SEQ_add_reload_new_file(bmain, scene, right_seq, false);
388- break;
389+ /* Move strips back to seqbase. Move right strips first, so left strips don't change name. */
390+ BLI_movelisttolist(seqbase, &right_strips);
391+ BLI_movelisttolist(seqbase, &left_strips);
392+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
393+ SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene);
394 }
395- SEQ_time_update_sequence(scene, left_seq);
396- SEQ_time_update_sequence(scene, right_seq);
397- return right_seq;
398+
399+ return return_seq;
400 }
401
402 /**
403 * Find gap after initial_frame and move strips on right side to close the gap
404 *
405 * \param scene: Scene in which strips are located
406 * \param seqbase: ListBase in which strips are located
407 * \param initial_frame: frame on timeline from where gaps are searched for
408 * \param remove_all_gaps: remove all gaps instead of one gap
409 * \return true if gap is removed, otherwise false
410diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
411index 6d5332b2b15..84712db23ad 100644
412--- a/source/blender/sequencer/intern/utils.c
413+++ b/source/blender/sequencer/intern/utils.c
414@@ -26,88 +26,91 @@
415
416 #include <stdlib.h>
417 #include <string.h>
418
419 #include "MEM_guardedalloc.h"
420
421 #include "DNA_mask_types.h"
422 #include "DNA_scene_types.h"
423 #include "DNA_sequence_types.h"
424
425-#include "BLI_listbase.h"
426-#include "BLI_path_util.h"
427-#include "BLI_string.h"
428-#include "BLI_utildefines.h"
429+#include "BLI_blenlib.h"
430
431 #include "BKE_image.h"
432 #include "BKE_main.h"
433 #include "BKE_scene.h"
434
435 #include "SEQ_iterator.h"
436 #include "SEQ_relations.h"
437 #include "SEQ_select.h"
438 #include "SEQ_sequencer.h"
439 #include "SEQ_utils.h"
440
441 #include "IMB_imbuf.h"
442 #include "IMB_imbuf_types.h"
443
444 #include "multiview.h"
445 #include "proxy.h"
446 #include "utils.h"
447
448-void SEQ_sort(Scene *scene)
449+void seq_sort_ex(ListBase *seqbase)
450 {
451- /* all strips together per kind, and in order of y location ("machine") */
452- ListBase seqbase, effbase;
453- Editing *ed = SEQ_editing_get(scene, false);
454+ /* all strips together per kind, and in order of y location ("machine") */
455+ ListBase inputbase, effbase;
456 Sequence *seq, *seqt;
457
458- if (ed == NULL) {
459- return;
460- }
461-
462- BLI_listbase_clear(&seqbase);
463+ BLI_listbase_clear(&inputbase);
464 BLI_listbase_clear(&effbase);
465
466- while ((seq = BLI_pophead(ed->seqbasep))) {
467+ while ((seq = BLI_pophead(seqbase))) {
468
469 if (seq->type & SEQ_TYPE_EFFECT) {
470 seqt = effbase.first;
471 while (seqt) {
472 if (seqt->machine >= seq->machine) {
473 BLI_insertlinkbefore(&effbase, seqt, seq);
474 break;
475 }
476 seqt = seqt->next;
477 }
478 if (seqt == NULL) {
479 BLI_addtail(&effbase, seq);
480 }
481 }
482 else {
483- seqt = seqbase.first;
484+ seqt = inputbase.first;
485 while (seqt) {
486 if (seqt->machine >= seq->machine) {
487- BLI_insertlinkbefore(&seqbase, seqt, seq);
488+ BLI_insertlinkbefore(&inputbase, seqt, seq);
489 break;
490 }
491 seqt = seqt->next;
492 }
493 if (seqt == NULL) {
494- BLI_addtail(&seqbase, seq);
495+ BLI_addtail(&inputbase, seq);
496 }
497 }
498 }
499
500- BLI_movelisttolist(&seqbase, &effbase);
501- *(ed->seqbasep) = seqbase;
502+ BLI_movelisttolist(seqbase, &inputbase);
503+ BLI_movelisttolist(seqbase, &effbase);
504+}
505+
506+void SEQ_sort(Scene *scene)
507+{
508+ Editing *ed = SEQ_editing_get(scene, false);
509+
510+ if (ed == NULL) {
511+ return;
512+ }
513+
514+ seq_sort_ex(SEQ_active_seqbase_get(ed));
515 }
516
517 typedef struct SeqUniqueInfo {
518 Sequence *seq;
519 char name_src[SEQ_NAME_MAXSTR];
520 char name_dest[SEQ_NAME_MAXSTR];
521 int count;
522 int match;
523 } SeqUniqueInfo;
524
525@@ -605,10 +608,21 @@ int SEQ_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void
526 if (ret == -1) {
527 return -1; /* bail out */
528 }
529
530 if (ret && seq->seqbase.first) {
531 ret = SEQ_seqbase_recursive_apply(&seq->seqbase, apply_fn, arg);
532 }
533
534 return ret;
535 }
536+
537+int SEQ_apply_unique_name_fn(Sequence *seq, void *arg_pt)
538+{
539+ Scene *scene = (Scene *)arg_pt;
540+ char name[sizeof(seq->name) - 2];
541+
542+ BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
543+ SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
544+ SEQ_dupe_animdata(scene, name, seq->name + 2);
545+ return 1;
546+}
547diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h
548index 97f33bb3ae0..0413681afcf 100644
549--- a/source/blender/sequencer/intern/utils.h
550+++ b/source/blender/sequencer/intern/utils.h
551@@ -27,14 +27,15 @@
552 extern "C" {
553 #endif
554
555 struct Scene;
556
557 bool sequencer_seq_generates_image(struct Sequence *seq);
558 void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
559 struct Sequence *seq_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
560 struct Sequence *meta /* = NULL */,
561 struct Sequence *seq);
562+void seq_sort_ex(ListBase *seqbase);
563
564 #ifdef __cplusplus
565 }
566 #endif

Use iterator to get effect chain of strip that has to be split.

Richard Antalik (ISS) edited the summary of this revision. (Show Details)May 9 2021, 2:51 AM

Do you have a simple .blend file where one can easily check behavior before and after? If so, please attach it in the description. Will make testing so much easier and more efficient :)

source/blender/sequencer/intern/strip_edit.c
430

Declaration of seq here shadows a parameter.

source/blender/sequencer/intern/utils.c
634

Think there is some documentation needed.

For example, it is unclear to me why in some cases ensuring uniqueness of strips will handle animation data (which happens here) and in some cases it will not (in the case of SEQ_sequence_base_unique_name_recursive).

It also seems that this function is always used as a callback for SEQ_recursive_apply. So would suggest making the entire call of SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene); handled here, under a nice clear name :)

637

It can be SEQ_NAME_MAXSTR.

Richard Antalik (ISS) marked 2 inline comments as done.
  • Address inlines
Richard Antalik (ISS) marked an inline comment as done.May 17 2021, 10:29 PM
Richard Antalik (ISS) added inline comments.
source/blender/sequencer/intern/utils.c
634

Think there is some documentation needed.

I will add docs.

For example, it is unclear to me why in some cases ensuring uniqueness of strips will handle animation data (which happens here) and in some cases it will not (in the case of SEQ_sequence_base_unique_name_recursive).

It also seems that this function is always used as a callback for SEQ_recursive_apply. So would suggest making the entire call of SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene); handled here, under a nice clear name :)

I think there are few things here that would make this change better for separate patch:
SEQ_sequence_base_unique_name_recursive does same thing as SEQ_apply_unique_name_fn, but with no concern for strip animation. From API perspective I don't think that this function should be public. Looking at other places for usage of SEQ_sequence_base_unique_name_recursive, in strip_add.c it is used incorrectly, and in versioning_280.c I think animation handling is missing.

So I would argue, that usage of SEQ_sequence_base_unique_name_recursive should be replaced by SEQ_apply_unique_name_fn after facelift as you proposed with exception of sequencer.c file.

Perhaps seq_sequence_base_unique_name_recursive should be even static and functionality could be provided by same function that does handle animdata, but handling animdata would be optional. So there would be more cleanup.

Here would be my starting point:

1diff --cc source/blender/sequencer/intern/utils.c
2index ea53b7dcf00,f8e313e43f5..00000000000
3--- a/source/blender/sequencer/intern/utils.c
4+++ b/source/blender/sequencer/intern/utils.c
5@@@ -132,50 -132,51 +132,72 @@@ static void seqbase_unique_name(ListBas
6 }
7
8 static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
9 {
10 if (seq->seqbase.first) {
11 seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
12 }
13 return 1;
14 }
15
16- void SEQ_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
17 -static void seq_sequence_base_unique_name_recursive(Scene *scene, Sequence *seq)
18++void seq_sequence_base_unique_name_recursive(Scene *scene, Sequence *seq)
19 {
20 SeqUniqueInfo sui;
21 char *dot;
22 sui.seq = seq;
23 BLI_strncpy(sui.name_src, seq->name + 2, sizeof(sui.name_src));
24 BLI_strncpy(sui.name_dest, seq->name + 2, sizeof(sui.name_dest));
25
26 sui.count = 1;
27 sui.match = 1; /* assume the worst to start the loop */
28
29 /* Strip off the suffix */
30 if ((dot = strrchr(sui.name_src, '.'))) {
31 *dot = '\0';
32 dot++;
33
34 if (*dot) {
35 sui.count = atoi(dot) + 1;
36 }
37 }
38
39+ ListBase *seqbase = &scene->ed->seqbase;
40 while (sui.match) {
41 sui.match = 0;
42- seqbase_unique_name(seqbasep, &sui);
43- SEQ_seqbase_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
44+ seqbase_unique_name(seqbase, &sui);
45+ SEQ_seqbase_recursive_apply(seqbase, seqbase_unique_name_recursive_fn, &sui);
46 }
47
48 BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
49 }
50
51++/**
52++ * Ensure, that provided Sequence has unique name.
53++ *
54++ * \param seq: Sequence which name will be ensured to be unique
55++ * \param scene: Scene in which name must be unique
56++ */
57++void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
58++{
59++ char name[SEQ_NAME_MAXSTR];
60++
61++ BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
62++ seq_sequence_base_unique_name_recursive(scene, seq);
63++ SEQ_dupe_animdata(scene, name, seq->name + 2);
64++
65++ if (seq->type == SEQ_TYPE_META) {
66++ LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
67++ SEQ_ensure_unique_name(seq_child, scene);
68++ }
69++ }
70++}
71++
72 static const char *give_seqname_by_type(int type)
73 {
74 switch (type) {
75 case SEQ_TYPE_META:
76 return "Meta";
77 case SEQ_TYPE_IMAGE:
78 return "Image";
79 case SEQ_TYPE_SCENE:
80 return "Scene";
81 case SEQ_TYPE_MOVIE:
82@@@ -608,28 -609,25 +630,10 @@@ int SEQ_recursive_apply(Sequence *seq,
83 if (ret == -1) {
84 return -1; /* bail out */
85 }
86
87 if (ret && seq->seqbase.first) {
88 ret = SEQ_seqbase_recursive_apply(&seq->seqbase, apply_fn, arg);
89 }
90
91 return ret;
92 }
93--
94- /**
95- * Ensure, that provided Sequence has unique name. Use as callback for SEQ_recursive_apply()
96- *
97- * \param seq: Sequence which name will be ensured to be unique
98- * \param arg_pt: Scene in which name must be unique
99- * \return always 1, so SEQ_recursive_apply() wont terminate execution prematurely
100- */
101- int SEQ_apply_unique_name_fn(Sequence *seq, void *arg_pt)
102 -void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
103--{
104- Scene *scene = (Scene *)arg_pt;
105-- char name[SEQ_NAME_MAXSTR];
106--
107-- BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
108- SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
109 - seq_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
110-- SEQ_dupe_animdata(scene, name, seq->name + 2);
111- return 1;
112 -
113 - if (seq->type == SEQ_TYPE_META) {
114 - LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
115 - SEQ_ensure_unique_name(seq_child, scene);
116 - }
117 - }
118--}
119diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
120index d129f257962..dacf1df462c 100644
121--- a/source/blender/sequencer/SEQ_utils.h
122+++ b/source/blender/sequencer/SEQ_utils.h
123@@ -52,14 +52,14 @@ void SEQ_set_scale_to_fit(const struct Sequence *seq,
124 const int image_height,
125 const int preview_width,
126 const int preview_height,
127 const eSeqImageFitMethod fit_method);
128 int SEQ_seqbase_recursive_apply(struct ListBase *seqbase,
129 int (*apply_fn)(struct Sequence *seq, void *),
130 void *arg);
131 int SEQ_recursive_apply(struct Sequence *seq,
132 int (*apply_fn)(struct Sequence *, void *),
133 void *arg);
134-void SEQ_ensure_unique_name(struct Sequence *seq, Scene *scene, bool handle_animation);
135+void SEQ_ensure_unique_name(struct Sequence *seq, Scene *scene);
136 #ifdef __cplusplus
137 }
138 #endif

Richard Antalik (ISS) edited the summary of this revision. (Show Details)May 17 2021, 10:31 PM
Richard Antalik (ISS) marked an inline comment as done.May 17 2021, 10:37 PM

Oops, I must have screwed up diff in P2120. It looks like unfinished merge?

In any case my point was that I would rather follow this up in separate patch, because there will be number of unrelated changes.

Thing is, you have the following calls:

  • SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene);
  • SEQ_recursive_apply(iseq, SEQ_apply_unique_name_fn, scene);

And the change makes some low-level callback function SEQ_apply_unique_name_fn public.
So question is, why to expose a low-level callback instead of something like this:

/* Make sure sequence's name is unique. (And state explicitly what happens with the animation) */
SEQ_recursive_apply_unique_name(Scene *scene, Sequence *seq)
{
  SEQ_recursive_apply(iseq, seq_apply_unique_name_fn, scene);
}
  • Convert callback SEQ_apply_unique_name_fn to standalone function SEQ_ensure_unique_name

Thing is, you have the following calls:

  • SEQ_recursive_apply(seq, SEQ_apply_unique_name_fn, scene);
  • SEQ_recursive_apply(iseq, SEQ_apply_unique_name_fn, scene);

And the change makes some low-level callback function SEQ_apply_unique_name_fn public.
So question is, why to expose a low-level callback instead of something like this:

/* Make sure sequence's name is unique. (And state explicitly what happens with the animation) */
SEQ_recursive_apply_unique_name(Scene *scene, Sequence *seq)
{
  SEQ_recursive_apply(iseq, seq_apply_unique_name_fn, scene);
}

I thought that this change would fit much better into broader cleanup in this area. But overall it doesn't matter that much.

The remaining bit is about the sorting. One confusing part is why SEQ_sort is capitalized and seq_sort_ex is not?
Maybe call it SEQ_sort_list/SEQ_sort_scene() ? And add a comment what exactly they are doing.

The remaining bit is about the sorting. One confusing part is why SEQ_sort is capitalized and seq_sort_ex is not?

Because SEQ_ is extern API (for operators, other modules), seq_ is intern.
I have been trying to make all code aware of seqbase that is being operated on so I should have changed SEQ_sort. This is because RNA functions don't always use active seqbase which is implicitly used by SEQ_sort

I will check code and how this function was used. I haven't thought about this aspect when I split the function.

I see.
I would avoid name seq_sort_ex as it is not an extended version of the SEQ_sort. Usually we use _ex suffix for functions which receive an extended list of arguments (instead of deducting them from a context, i.e.). seq_sort_seqbase with a comment (saying that it sorts in the order of dependencies) is easy to do and clear enough for this patch. More thorough refactor can happen aftewards.

  • Document SEQ_sort and seq_sort_seqbase
This revision is now accepted and ready to land.May 18 2021, 6:24 PM