[Bf-blender-cvs] [709ce44617b] master: Fix T90407: Split fails on transition strips

Richard Antalik noreply at git.blender.org
Tue Aug 24 00:55:22 CEST 2021


Commit: 709ce44617bf8c41b5bfe9a93aa58e9140323428
Author: Richard Antalik
Date:   Tue Aug 24 00:52:24 2021 +0200
Branches: master
https://developer.blender.org/rB709ce44617bf8c41b5bfe9a93aa58e9140323428

Fix T90407: Split fails on transition strips

When splitting strips, first they are duplicated and then offsets
adjusted. This can fail on cross transitions, because some strips don't
overlap with split frame.

All strips, that relate to each other must be duplicated to ensure
correct relations after splitting, so solution is to delete non
overlapping strips from left or right side respectively.

Since cross transition don't have to overlap with source strips,
splitting such strips would lead to effect being deleted, which
could cause crash when iterating over strips in python. Therefore
splitting of such strips is now forbidden and will generate error.

Splitting of transition will also generate error solely because such
operation is illogical.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D12121

===================================================================

M	source/blender/editors/space_sequencer/sequencer_edit.c
M	source/blender/makesrna/intern/rna_sequencer_api.c
M	source/blender/sequencer/SEQ_edit.h
M	source/blender/sequencer/intern/strip_edit.c

===================================================================

diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 9a2225a44c5..694e5fbb41d 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1446,9 +1446,14 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
     }
 
     if (ignore_selection || seq->flag & SELECT) {
-      if (SEQ_edit_strip_split(bmain, scene, ed->seqbasep, seq, split_frame, method) != NULL) {
+      const char *error_msg = NULL;
+      if (SEQ_edit_strip_split(bmain, scene, ed->seqbasep, seq, split_frame, method, &error_msg) !=
+          NULL) {
         changed = true;
       }
+      if (error_msg != NULL) {
+        BKE_report(op->reports, RPT_ERROR, error_msg);
+      }
     }
   }
 
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 264ccccd350..d98e03785d1 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -102,13 +102,18 @@ static void rna_Sequences_move_strip_to_meta(
 }
 
 static Sequence *rna_Sequence_split(
-    ID *id, Sequence *seq, Main *bmain, int frame, int split_method)
+    ID *id, Sequence *seq, Main *bmain, ReportList *reports, int frame, int split_method)
 {
   Scene *scene = (Scene *)id;
   Editing *ed = SEQ_editing_get(scene, false);
   ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
 
-  Sequence *r_seq = SEQ_edit_strip_split(bmain, scene, seqbase, seq, frame, split_method);
+  const char *error_msg = NULL;
+  Sequence *r_seq = SEQ_edit_strip_split(
+      bmain, scene, seqbase, seq, frame, split_method, &error_msg);
+  if (error_msg != NULL) {
+    BKE_report(reports, RPT_ERROR, error_msg);
+  }
 
   /* Update depsgraph. */
   DEG_relations_tag_update(bmain);
@@ -705,7 +710,7 @@ void RNA_api_sequence_strip(StructRNA *srna)
   RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
 
   func = RNA_def_function(srna, "split", "rna_Sequence_split");
-  RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+  RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN);
   RNA_def_function_ui_description(func, "Split Sequence");
   parm = RNA_def_int(
       func, "frame", 0, INT_MIN, INT_MAX, "", "Frame where to split the strip", INT_MIN, INT_MAX);
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index 6d043dffe72..fbbf4bc53ea 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -53,7 +53,8 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
                                       struct ListBase *seqbase,
                                       struct Sequence *seq,
                                       const int timeline_frame,
-                                      const eSeqSplitMethod method);
+                                      const eSeqSplitMethod method,
+                                      const char **r_error);
 bool SEQ_edit_remove_gaps(struct Scene *scene,
                           struct ListBase *seqbase,
                           const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index b83ee92f117..17ff1c90be8 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -351,6 +351,11 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame)
   SEQ_transform_set_left_handle_frame(seq, timeline_frame);
 }
 
+static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame)
+{
+  return timeline_frame > seq->startdisp && timeline_frame < seq->enddisp;
+}
+
 static void seq_edit_split_handle_strip_offsets(Main *bmain,
                                                 Scene *scene,
                                                 Sequence *left_seq,
@@ -358,20 +363,82 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain,
                                                 const int timeline_frame,
                                                 const eSeqSplitMethod method)
 {
-  switch (method) {
-    case SEQ_SPLIT_SOFT:
-      seq_split_set_left_offset(right_seq, timeline_frame);
-      seq_split_set_right_offset(left_seq, timeline_frame);
-      break;
-    case SEQ_SPLIT_HARD:
-      seq_split_set_right_hold_offset(left_seq, timeline_frame);
-      seq_split_set_left_hold_offset(right_seq, timeline_frame);
-      SEQ_add_reload_new_file(bmain, scene, left_seq, false);
-      SEQ_add_reload_new_file(bmain, scene, right_seq, false);
-      break;
-  }
-  SEQ_time_update_sequence(scene, left_seq);
-  SEQ_time_update_sequence(scene, right_seq);
+  if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) {
+    switch (method) {
+      case SEQ_SPLIT_SOFT:
+        seq_split_set_left_offset(right_seq, timeline_frame);
+        break;
+      case SEQ_SPLIT_HARD:
+        seq_split_set_left_hold_offset(right_seq, timeline_frame);
+        SEQ_add_reload_new_file(bmain, scene, right_seq, false);
+        break;
+    }
+    SEQ_time_update_sequence(scene, right_seq);
+  }
+
+  if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) {
+    switch (method) {
+      case SEQ_SPLIT_SOFT:
+        seq_split_set_right_offset(left_seq, timeline_frame);
+        break;
+      case SEQ_SPLIT_HARD:
+        seq_split_set_right_hold_offset(left_seq, timeline_frame);
+        SEQ_add_reload_new_file(bmain, scene, left_seq, false);
+        break;
+    }
+    SEQ_time_update_sequence(scene, left_seq);
+  }
+}
+
+static bool seq_edit_split_effect_inputs_intersect(const Sequence *seq, const int timeline_frame)
+{
+  bool input_does_intersect = false;
+  if (seq->seq1) {
+    input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq1, timeline_frame);
+    if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
+      input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq1, timeline_frame);
+    }
+  }
+  if (seq->seq2) {
+    input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq2, timeline_frame);
+    if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
+      input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq2, timeline_frame);
+    }
+  }
+  if (seq->seq3) {
+    input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq3, timeline_frame);
+    if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
+      input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq3, timeline_frame);
+    }
+  }
+  return input_does_intersect;
+}
+
+static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
+                                                     const int timeline_frame,
+                                                     const char **r_error)
+{
+  Sequence *seq;
+  SEQ_ITERATOR_FOREACH (seq, strips) {
+    if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
+      continue;
+    }
+    if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) {
+      continue;
+    }
+    if (SEQ_effect_get_num_inputs(seq->type) <= 1) {
+      continue;
+    }
+    if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
+      *r_error = "Splitting transition effect is not permitted.";
+      return false;
+    }
+    if (!seq_edit_split_effect_inputs_intersect(seq, timeline_frame)) {
+      *r_error = "Effect inputs don't overlap. Can not split such effect.";
+      return false;
+    }
+  }
+  return true;
 }
 
 /**
@@ -390,16 +457,23 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
                                ListBase *seqbase,
                                Sequence *seq,
                                const int timeline_frame,
-                               const eSeqSplitMethod method)
+                               const eSeqSplitMethod method,
+                               const char **r_error)
 {
-  if (timeline_frame <= seq->startdisp || timeline_frame >= seq->enddisp) {
+  if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) {
     return NULL;
   }
 
+  /* Whole strip chain must be duplicated in order to preserve relationships. */
   SeqCollection *collection = SEQ_collection_create(__func__);
   SEQ_collection_append_strip(seq, collection);
   SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
 
+  if (!seq_edit_split_operation_permitted_check(collection, timeline_frame, r_error)) {
+    SEQ_collection_free(collection);
+    return NULL;
+  }
+
   /* Move strips in collection from seqbase to new ListBase. */
   ListBase left_strips = {NULL, NULL};
   SEQ_ITERATOR_FOREACH (seq, collection) {
@@ -421,7 +495,19 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
   Sequence *left_seq = left_strips.first;
   Sequence *right_seq = right_strips.first;
   Sequence *return_seq = right_strips.first;
+
+  /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be
+   * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */
+  SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
   while (left_seq && right_seq) {
+    if (left_seq->startdisp >= timeline_frame) {
+      SEQ_collection_append_strip(left_seq, strips_to_delete);
+    }
+    if (right_seq->enddisp <= timeline_frame) {
+      SEQ_collection_append_strip(right_seq, strips_to_delete);
+    }
+
     seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
     left_seq = left_seq->next;
     right_seq = right_seq->next;
@@ -435,6 +521,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
     SEQ_ensure_unique_name(seq, scene);
   }
 
+  Sequence *seq_delete;
+  SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) {
+    SEQ_edit_flag_for_removal(scene, seqbase, seq_delete);
+  }
+  SEQ_edit_remove_flagged_sequences(scene, seqbase);
+  SEQ_collection_free(strips_to_delete);
   return return_seq;
 }



More information about the Bf-blender-cvs mailing list