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
This commit is contained in:
Richard Antalik 2021-08-24 00:52:24 +02:00
parent 24a3446787
commit 709ce44617
Notes: blender-bot 2023-02-14 08:45:12 +01:00
Referenced by issue #90407, VSE: Strip attached to transition effect, when cut outside transition, creates a mess of strips
4 changed files with 123 additions and 20 deletions

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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,

View File

@ -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;
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);
}
SEQ_time_update_sequence(scene, left_seq);
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;
}