diff options
Diffstat (limited to 'source/blender/sequencer/intern')
-rw-r--r-- | source/blender/sequencer/intern/effects.c | 5 | ||||
-rw-r--r-- | source/blender/sequencer/intern/image_cache.c | 13 | ||||
-rw-r--r-- | source/blender/sequencer/intern/iterator.c | 286 | ||||
-rw-r--r-- | source/blender/sequencer/intern/render.c | 181 | ||||
-rw-r--r-- | source/blender/sequencer/intern/render.h | 4 | ||||
-rw-r--r-- | source/blender/sequencer/intern/sequencer.c | 4 | ||||
-rw-r--r-- | source/blender/sequencer/intern/strip_add.c | 2 | ||||
-rw-r--r-- | source/blender/sequencer/intern/strip_edit.c | 114 | ||||
-rw-r--r-- | source/blender/sequencer/intern/strip_time.c | 65 | ||||
-rw-r--r-- | source/blender/sequencer/intern/utils.c | 61 |
10 files changed, 514 insertions, 221 deletions
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index 278320d873e..d41a2c19d55 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -3033,10 +3033,9 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl i = seq_render_give_ibuf_seqbase(context, timeline_frame, seq->machine - 1, seqbasep); } - /* found nothing? so let's work the way up the metastrip stack, so + /* Found nothing? so let's work the way up the meta-strip stack, so * that it is possible to group a bunch of adjustment strips into - * a metastrip and have that work on everything below the metastrip - */ + * a meta-strip and have that work on everything below the meta-strip. */ if (!i) { Sequence *meta; diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 089bb5a6bec..a0c95c1c197 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -352,15 +352,18 @@ static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path) } /* Path format: - * <cache dir>/<project name>/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT + * <cache dir>/<project name>_seq_cache/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT */ static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len) { - char main_name[FILE_MAX]; - BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), main_name, sizeof(main_name)); + char cache_dir[FILE_MAX]; + BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), cache_dir, sizeof(cache_dir)); + /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */ + const char *suffix = "_seq_cache"; + strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1); BLI_strncpy(path, seq_disk_cache_base_dir(), path_len); - BLI_path_append(path, path_len, main_name); + BLI_path_append(path, path_len, cache_dir); } static void seq_disk_cache_get_dir( @@ -421,7 +424,7 @@ static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache) BLI_strncpy(path_version_file, path, sizeof(path_version_file)); BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version"); - if (BLI_exists(path)) { + if (BLI_exists(path) && BLI_is_dir(path)) { FILE *file = BLI_fopen(path_version_file, "r"); if (file) { diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 356f5db45e8..9bbc5362f18 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -31,110 +31,268 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BKE_scene.h" #include "SEQ_iterator.h" -/* ************************* iterator ************************** */ -/* *************** (replaces old WHILE_SEQ) ********************* */ -/* **************** use now SEQ_ALL_BEGIN () SEQ_ALL_END ***************** */ +/* -------------------------------------------------------------------- */ +/** \Iterator API + * \{ */ -/* sequence strip iterator: - * - builds a full array, recursively into meta strips +/** + * Utility function for SEQ_ITERATOR_FOREACH macro. + * Ensure, that iterator is initialized. During initialization return pointer to collection element + * and step gset iterator. When this function is called after iterator has been initialized, it + * will do nothing and return true. + * + * \param collection: collection to iterate + * \param iterator: iterator to be initialized + * \param r_seq: pointer to Sequence pointer + * + * \return false when iterator can not be initialized, true otherwise */ - -static void seq_count(ListBase *seqbase, int *tot) +bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Sequence **r_seq) { - Sequence *seq; - - for (seq = seqbase->first; seq; seq = seq->next) { - (*tot)++; + if (iterator->iterator_initialized) { + return true; + } - if (seq->seqbase.first) { - seq_count(&seq->seqbase, tot); - } + if (BLI_gset_len(collection->set) == 0) { + return false; } + + iterator->collection = collection; + BLI_gsetIterator_init(&iterator->gsi, iterator->collection->set); + iterator->iterator_initialized = true; + + *r_seq = BLI_gsetIterator_getKey(&iterator->gsi); + BLI_gsetIterator_step(&iterator->gsi); + + return true; } -static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth) +/** + * Utility function for SEQ_ITERATOR_FOREACH macro. + * Yield collection element + * + * \param iterator: iterator to be initialized + * + * \return collection element or NULL when iteration has ended + */ +Sequence *SEQ_iterator_yield(SeqIterator *iterator) { - Sequence *seq; + Sequence *seq = BLI_gsetIterator_done(&iterator->gsi) ? NULL : + BLI_gsetIterator_getKey(&iterator->gsi); + BLI_gsetIterator_step(&iterator->gsi); + return seq; +} - for (seq = seqbase->first; seq; seq = seq->next) { - seq->depth = depth; +/** + * Free strip collection. + * + * \param collection: collection to be freed + */ +void SEQ_collection_free(SeqCollection *collection) +{ + BLI_gset_free(collection->set, NULL); + MEM_freeN(collection); +} - if (seq->seqbase.first) { - seq_build_array(&seq->seqbase, array, depth + 1); - } +/** + * Create new empty strip collection. + * + * \return empty strip collection. + */ +SeqCollection *SEQ_collection_create(void) +{ + SeqCollection *collection = MEM_callocN(sizeof(SeqCollection), "SeqCollection"); + collection->set = BLI_gset_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "SeqCollection GSet"); + return collection; +} - **array = seq; - (*array)++; +/** + * Query strips from seqbase. seq_reference is used by query function as filter condition. + * + * \param seq_reference: reference strip for query function + * \param seqbase: ListBase in which strips are queried + * \param seq_query_func: query function callback + * \return strip collection + */ +SeqCollection *SEQ_query_by_reference(Sequence *seq_reference, + ListBase *seqbase, + void seq_query_func(Sequence *seq_reference, + ListBase *seqbase, + SeqCollection *collection)) +{ + SeqCollection *collection = SEQ_collection_create(); + seq_query_func(seq_reference, seqbase, collection); + return collection; +} +/** + * Add strip to collection. + * + * \param seq: strip to be added + * \param collection: collection to which strip will be added + * \return false if strip is already in set, otherwise true + */ +bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection) +{ + if (BLI_gset_lookup(collection->set, seq) != NULL) { + return false; } + BLI_gset_insert(collection->set, seq); + return true; } -static void seq_array(Editing *ed, - const bool use_current_sequences, - Sequence ***r_seqarray, - int *r_seqarray_len) +/** + * Remove strip from collection. + * + * \param seq: strip to be removed + * \param collection: collection from which strip will be removed + * \return true if strip exists in set and it was removed from set, otherwise false + */ +bool SEQ_collection_remove_strip(Sequence *seq, SeqCollection *collection) { - Sequence **array; - - *r_seqarray = NULL; - *r_seqarray_len = 0; + return BLI_gset_remove(collection->set, seq, NULL); +} - if (ed == NULL) { - return; +/** + * Move strips from collection_src to collection_dst. Source collection will be freed. + * + * \param collection_dst: destination collection + * \param collection_src: source collection + */ +void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection_src) { + SEQ_collection_append_strip(seq, collection_dst); } + SEQ_collection_free(collection_src); +} - if (use_current_sequences) { - seq_count(ed->seqbasep, r_seqarray_len); - } - else { - seq_count(&ed->seqbase, r_seqarray_len); - } +/** + * Expand collection by running SEQ_query() for each strip, which will be used as reference. + * Results of these queries will be merged into provided collection. + * + * \param seqbase: ListBase in which strips are queried + * \param collection: SeqCollection to be expanded + * \param seq_query_func: query function callback + */ +void SEQ_collection_expand(ListBase *seqbase, + SeqCollection *collection, + void seq_query_func(Sequence *seq_reference, + ListBase *seqbase, + SeqCollection *collection)) +{ + /* Collect expanded results for each sequence in provided SeqIteratorCollection. */ + ListBase expand_collections = {0}; - if (*r_seqarray_len == 0) { - return; + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + SeqCollection *expand_collection = SEQ_query_by_reference(seq, seqbase, seq_query_func); + BLI_addtail(&expand_collections, expand_collection); } - *r_seqarray = array = MEM_mallocN(sizeof(Sequence *) * (*r_seqarray_len), "SeqArray"); - if (use_current_sequences) { - seq_build_array(ed->seqbasep, &array, 0); - } - else { - seq_build_array(&ed->seqbase, &array, 0); + /* Merge all expanded results in provided SeqIteratorCollection. */ + LISTBASE_FOREACH_MUTABLE (SeqCollection *, expand_collection, &expand_collections) { + BLI_remlink(&expand_collections, expand_collection); + SEQ_collection_merge(collection, expand_collection); } } -void SEQ_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences) -{ - memset(iter, 0, sizeof(*iter)); - seq_array(ed, use_current_sequences, &iter->array, &iter->tot); +/** \} */ - if (iter->tot) { - iter->cur = 0; - iter->seq = iter->array[iter->cur]; - iter->valid = 1; +/** + * Query all strips in seqbase and nested meta strips. + * + * \param seqbase: ListBase in which strips are queried + * \return strip collection + */ +SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase) +{ + SeqCollection *collection = SEQ_collection_create(); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type == SEQ_TYPE_META) { + SEQ_collection_merge(collection, SEQ_query_all_strips_recursive(&seq->seqbase)); + } + SEQ_collection_append_strip(seq, collection); } + return collection; } -void SEQ_iterator_next(SeqIterator *iter) +/** + * Query all strips in seqbase. This does not include strips nested in meta strips. + * + * \param seqbase: ListBase in which strips are queried + * \return strip collection + */ +SeqCollection *SEQ_query_all_strips(ListBase *seqbase) { - if (++iter->cur < iter->tot) { - iter->seq = iter->array[iter->cur]; + SeqCollection *collection = SEQ_collection_create(); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + SEQ_collection_append_strip(seq, collection); } - else { - iter->valid = 0; + return collection; +} + +/** + * Query all selected strips in seqbase. + * + * \param seqbase: ListBase in which strips are queried + * \return strip collection + */ +SeqCollection *SEQ_query_selected_strips(ListBase *seqbase) +{ + SeqCollection *collection = SEQ_collection_create(); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if ((seq->flag & SELECT) == 0) { + continue; + } + SEQ_collection_append_strip(seq, collection); } + return collection; } -void SEQ_iterator_end(SeqIterator *iter) +/** + * Query all effect strips that are directly or indirectly connected to seq_reference. + * This includes all effects of seq_reference, strips used by another inputs and their effects, so + * that whole chain is fully independent of other strips. + * + * \param seq_reference: reference strip + * \param seqbase: ListBase in which strips are queried + * \param collection: collection to be filled + */ +void SEQ_query_strip_effect_chain(Sequence *seq_reference, + ListBase *seqbase, + SeqCollection *collection) { - if (iter->array) { - MEM_freeN(iter->array); + if (!SEQ_collection_append_strip(seq_reference, collection)) { + return; /* Strip is already in set, so all effects connected to it are as well. */ + } + + /* Find all strips that seq_reference is connected to. */ + if (seq_reference->type & SEQ_TYPE_EFFECT) { + if (seq_reference->seq1) { + SEQ_query_strip_effect_chain(seq_reference->seq1, seqbase, collection); + } + if (seq_reference->seq2) { + SEQ_query_strip_effect_chain(seq_reference->seq2, seqbase, collection); + } + if (seq_reference->seq3) { + SEQ_query_strip_effect_chain(seq_reference->seq3, seqbase, collection); + } } - iter->valid = 0; + /* Find all strips connected to seq_reference. */ + LISTBASE_FOREACH (Sequence *, seq_test, seqbase) { + if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference || + seq_test->seq3 == seq_reference) { + SEQ_query_strip_effect_chain(seq_test, seqbase, collection); + } + } } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index f892f1c1b41..e8e600f910c 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -65,6 +65,7 @@ #include "RE_pipeline.h" #include "SEQ_effects.h" +#include "SEQ_iterator.h" #include "SEQ_modifier.h" #include "SEQ_proxy.h" #include "SEQ_render.h" @@ -259,120 +260,132 @@ StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame) return se; } -static int evaluate_seq_frame_gen(Sequence **seq_arr, - ListBase *seqbase, - int timeline_frame, - int chanshown) +static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input) { - /* Use arbitrary sized linked list, the size could be over MAXSEQ. */ - LinkNodePair effect_inputs = {NULL, NULL}; - int totseq = 0; + if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input || + seq_effect->seq3 == possibly_input) { + return true; + } + return false; +} - memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1)); +/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself. + * Order of applying these conditions is important. */ +static bool must_render_strip(const Sequence *seq, SeqCollection *strips_under_playhead) +{ + /* Sound strips are not rendered. */ + if (seq->type == SEQ_TYPE_SOUND_RAM) { + return false; + } + /* Muted strips are not rendered. */ + if ((seq->flag & SEQ_MUTE) != 0) { + return false; + } - LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if ((seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame)) { - if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) { + bool seq_have_effect_in_stack = false; + Sequence *seq_iter; + SEQ_ITERATOR_FOREACH (seq_iter, strips_under_playhead) { + /* Strips is below another strip with replace blending are not rendered. */ + if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) { + return false; + } - if (seq->seq1) { - BLI_linklist_append_alloca(&effect_inputs, seq->seq1); - } + if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) { + /* Strips in same channel or higher than its effect are rendered. */ + if (seq->machine >= seq_iter->machine) { + return true; + } + /* Mark that this strip has effect in stack, that is above the strip. */ + seq_have_effect_in_stack = true; + } + } - if (seq->seq2) { - BLI_linklist_append_alloca(&effect_inputs, seq->seq2); - } + /* All effects are rendered (with respect to conditions above). */ + if ((seq->type & SEQ_TYPE_EFFECT) != 0) { + return true; + } - if (seq->seq3) { - BLI_linklist_append_alloca(&effect_inputs, seq->seq3); - } - } + /* If strip has effects in stack, and all effects are above this strip, it it not rendered. */ + if (seq_have_effect_in_stack) { + return false; + } + + return true; +} - seq_arr[seq->machine] = seq; - totseq++; +static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame) +{ + SeqCollection *collection = SEQ_collection_create(); + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if ((seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame)) { + SEQ_collection_append_strip(seq, collection); } } + return collection; +} - /* Drop strips which are used for effect inputs, we don't want - * them to blend into render stack in any other way than effect - * string rendering. */ - for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) { - Sequence *seq = seq_item->link; - /* It's possible that effect strip would be placed to the same - * 'machine' as its inputs. We don't want to clear such strips - * from the stack. */ - if (seq_arr[seq->machine] && seq_arr[seq->machine]->type & SEQ_TYPE_EFFECT) { - continue; - } - /* If we're shown a specified channel, then we want to see the strips - * which belongs to this machine. */ - if (chanshown != 0 && chanshown <= seq->machine) { +static void collection_filter_channel_up_to_incl(SeqCollection *collection, const int channel) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + if (seq->machine <= channel) { continue; } - seq_arr[seq->machine] = NULL; + SEQ_collection_remove_strip(seq, collection); } - - return totseq; } -/** - * Count number of strips in timeline at timeline_frame - * - * \param seqbase: ListBase in which strips are located - * \param timeline_frame: frame on timeline from where gaps are searched for - * \return number of strips - */ -int SEQ_render_evaluate_frame(ListBase *seqbase, int timeline_frame) +/* Remove strips we don't want to render from collection. */ +static void collection_filter_rendered_strips(SeqCollection *collection) { - Sequence *seq_arr[MAXSEQ + 1]; - return evaluate_seq_frame_gen(seq_arr, seqbase, timeline_frame, 0); + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + if (must_render_strip(seq, collection)) { + continue; + } + SEQ_collection_remove_strip(seq, collection); + } } -static bool video_seq_is_rendered(Sequence *seq) +static int seq_channel_cmp_fn(const void *a, const void *b) { - return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM); + return (*(Sequence **)a)->machine - (*(Sequence **)b)->machine; } -int seq_get_shown_sequences(ListBase *seqbasep, - int timeline_frame, - int chanshown, - Sequence **seq_arr_out) +int seq_get_shown_sequences(ListBase *seqbase, + const int timeline_frame, + const int chanshown, + Sequence **r_seq_arr) { - Sequence *seq_arr[MAXSEQ + 1]; - int b = chanshown; - int cnt = 0; + SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame); - if (b > MAXSEQ) { - return 0; - } - - if (evaluate_seq_frame_gen(seq_arr, seqbasep, timeline_frame, chanshown)) { - if (b == 0) { - b = MAXSEQ; - } - for (; b > 0; b--) { - if (video_seq_is_rendered(seq_arr[b])) { - break; - } - } + if (chanshown != 0) { + collection_filter_channel_up_to_incl(collection, chanshown); } + collection_filter_rendered_strips(collection); - chanshown = b; + const int strip_count = BLI_gset_len(collection->set); - for (; b > 0; b--) { - if (video_seq_is_rendered(seq_arr[b])) { - if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) { - break; - } - } + if (strip_count > MAXSEQ) { + BLI_assert(!"Too many strips, this shouldn't happen"); + return 0; } - for (; b <= chanshown && b >= 0; b++) { - if (video_seq_is_rendered(seq_arr[b])) { - seq_arr_out[cnt++] = seq_arr[b]; - } + /* Copy collection elements into array. */ + memset(r_seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1)); + Sequence *seq; + int index = 0; + SEQ_ITERATOR_FOREACH (seq, collection) { + r_seq_arr[index] = seq; + index++; } + SEQ_collection_free(collection); + + /* Sort array by channel. */ + qsort(r_seq_arr, strip_count, sizeof(Sequence *), seq_channel_cmp_fn); - return cnt; + return strip_count; } /** \} */ diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index 1147516b8ec..a0cdf24d84b 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -60,10 +60,10 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, struct ImBuf *ibuf2, struct ImBuf *ibuf3); void seq_imbuf_to_sequencer_space(struct Scene *scene, struct ImBuf *ibuf, bool make_float); -int seq_get_shown_sequences(struct ListBase *seqbasep, +int seq_get_shown_sequences(struct ListBase *seqbase, int timeline_frame, int chanshown, - struct Sequence **seq_arr_out); + struct Sequence **r_seq_arr); struct ImBuf *seq_render_strip(const struct SeqRenderData *context, struct SeqRenderState *state, struct Sequence *seq, diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index cc11796496c..55c14944a23 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -448,8 +448,8 @@ static Sequence *seq_dupli(const Scene *scene_src, seqn->strip->stripdata = NULL; BLI_listbase_clear(&seqn->seqbase); - /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ - /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/ + /* WARNING: This meta-strip is not recursively duplicated here - do this after! */ + // seq_dupli_recursive(&seq->seqbase, &seqn->seqbase); } else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 1106f47c477..5ec2269b993 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -100,7 +100,7 @@ static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *se { SEQ_sequence_base_unique_name_recursive(seqbase, seq); SEQ_time_update_sequence_bounds(scene, seq); - SEQ_sort(scene); + SEQ_sort(seqbase); SEQ_relations_invalidate_cache_composite(scene, seq); } diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 4a27fb3a087..4de6ec3583c 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -39,10 +39,12 @@ #include "BKE_sound.h" #include "strip_time.h" +#include "utils.h" #include "SEQ_add.h" #include "SEQ_edit.h" #include "SEQ_effects.h" +#include "SEQ_iterator.h" #include "SEQ_relations.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" @@ -149,7 +151,7 @@ void SEQ_edit_update_muting(Editing *ed) static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq) { LISTBASE_FOREACH (Sequence *, user_seq, seqbase) { - /* Look in metas for usage of seq. */ + /* Look in meta-strips for usage of seq. */ if (user_seq->type == SEQ_TYPE_META) { sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq); } @@ -251,22 +253,26 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, return false; } - /* Remove users of src_seq. Ideally these could be moved into meta as well, but this would be - * best to do with generalized iterator as described in D10337. */ - sequencer_flag_users_for_removal(scene, seqbase, src_seq); - SEQ_edit_remove_flagged_sequences(scene, seqbase); + SeqCollection *collection = SEQ_collection_create(); + SEQ_collection_append_strip(src_seq, collection); + SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain); - /* Move to meta. */ - BLI_remlink(seqbase, src_seq); - BLI_addtail(&dst_seqm->seqbase, src_seq); - SEQ_relations_invalidate_cache_preprocessed(scene, src_seq); - - /* Update meta. */ - SEQ_time_update_sequence(scene, dst_seqm); - if (SEQ_transform_test_overlap(&dst_seqm->seqbase, src_seq)) { - SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, src_seq, scene); + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + /* Move to meta. */ + BLI_remlink(seqbase, seq); + BLI_addtail(&dst_seqm->seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + + /* Update meta. */ + SEQ_time_update_sequence(scene, dst_seqm); + if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) { + SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene); + } } + SEQ_collection_free(collection); + return true; } @@ -343,6 +349,29 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) SEQ_transform_set_left_handle_frame(seq, timeline_frame); } +static void seq_edit_split_handle_strip_offsets(Main *bmain, + Scene *scene, + Sequence *left_seq, + Sequence *right_seq, + 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); +} + /** * Split Sequence at timeline_frame in two. * @@ -365,33 +394,44 @@ Sequence *SEQ_edit_strip_split(Main *bmain, return NULL; } - if (method == SEQ_SPLIT_HARD) { - /* Precaution, needed because the length saved on-disk may not match the length saved in the - * blend file, or our code may have minor differences reading file length between versions. - * This causes hard-split to fail, see: T47862. */ - SEQ_add_reload_new_file(bmain, scene, seq, true); - SEQ_time_update_sequence(scene, seq); + SeqCollection *collection = SEQ_collection_create(); + SEQ_collection_append_strip(seq, collection); + SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain); + + /* Move strips in collection from seqbase to new ListBase. */ + ListBase left_strips = {NULL, NULL}; + SEQ_ITERATOR_FOREACH (seq, collection) { + BLI_remlink(seqbase, seq); + BLI_addtail(&left_strips, seq); } - Sequence *left_seq = seq; - Sequence *right_seq = SEQ_sequence_dupli_recursive( - scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + /* Sort list, so that no strip can depend on next strip in list. + * This is important for SEQ_time_update_sequence functionality. */ + SEQ_sort(&left_strips); + + /* Duplicate ListBase. */ + ListBase right_strips = {NULL, NULL}; + SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0); + + /* Split strips. */ + Sequence *left_seq = left_strips.first; + Sequence *right_seq = right_strips.first; + Sequence *return_seq = right_strips.first; + while (left_seq && right_seq) { + 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; + } - 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 = right_strips.first; + BLI_movelisttolist(seqbase, &left_strips); + BLI_movelisttolist(seqbase, &right_strips); + + for (; seq; seq = seq->next) { + SEQ_ensure_unique_name(seq, scene); } - SEQ_time_update_sequence(scene, left_seq); - SEQ_time_update_sequence(scene, right_seq); - return right_seq; + + return return_seq; } /** diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 21dc9aa2cdd..40d7fade308 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -36,9 +36,11 @@ #include "IMB_imbuf.h" +#include "SEQ_iterator.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" +#include "SEQ_transform.h" #include "strip_time.h" #include "utils.h" @@ -161,11 +163,41 @@ void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq) } } +static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta) +{ + if (BLI_listbase_is_empty(&seq_meta->seqbase)) { + return; + } + + int min = MAXFRAME * 2; + int max = -MAXFRAME * 2; + LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) { + min = min_ii(seq->startdisp, min); + max = max_ii(seq->enddisp, max); + } + + seq_meta->start = min + seq_meta->anim_startofs; + seq_meta->len = max - min; + seq_meta->len -= seq_meta->anim_startofs; + seq_meta->len -= seq_meta->anim_endofs; + + seq_update_sound_bounds_recursive(scene, seq_meta); +} + +static void seq_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) +{ + seq_time_update_meta_strip(scene, seq_meta); + + /* Prevent meta-strip to move in timeline. */ + SEQ_transform_set_left_handle_frame(seq_meta, seq_meta->startdisp); + SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp); +} + void SEQ_time_update_sequence(Scene *scene, Sequence *seq) { Sequence *seqm; - /* check all metas recursively */ + /* Check all meta-strips recursively. */ seqm = seq->seqbase.first; while (seqm) { if (seqm->seqbase.first) { @@ -211,6 +243,16 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq) } } else { + if (seq->type == SEQ_TYPE_META) { + seq_time_update_meta_strip(scene, seq); + } + + Editing *ed = SEQ_editing_get(scene, false); + MetaStack *ms = SEQ_meta_stack_active_get(ed); + if (ms != NULL) { + seq_time_update_meta_strip_range(scene, ms->parseq); + } + SEQ_time_update_sequence_bounds(scene, seq); } } @@ -363,6 +405,17 @@ void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *re } } +static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, all_strips) { + if ((seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame)) { + return true; + } + } + return false; +} + /** * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info * @@ -384,10 +437,12 @@ void seq_time_gap_info_get(const Scene *scene, int timeline_frame = initial_frame; r_gap_info->gap_exists = false; - if (SEQ_render_evaluate_frame(seqbase, initial_frame) == 0) { + SeqCollection *collection = SEQ_query_all_strips(seqbase); + + if (!strip_exists_at_frame(collection, initial_frame)) { /* Search backward for gap_start_frame. */ for (; timeline_frame >= sfra; timeline_frame--) { - if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + if (strip_exists_at_frame(collection, timeline_frame)) { break; } } @@ -397,7 +452,7 @@ void seq_time_gap_info_get(const Scene *scene, else { /* Search forward for gap_start_frame. */ for (; timeline_frame <= efra; timeline_frame++) { - if (SEQ_render_evaluate_frame(seqbase, timeline_frame) == 0) { + if (!strip_exists_at_frame(collection, timeline_frame)) { r_gap_info->gap_start_frame = timeline_frame; break; } @@ -405,7 +460,7 @@ void seq_time_gap_info_get(const Scene *scene, } /* Search forward for gap_end_frame. */ for (; timeline_frame <= efra; timeline_frame++) { - if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + if (strip_exists_at_frame(collection, timeline_frame)) { const int gap_end_frame = timeline_frame; r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame; r_gap_info->gap_exists = true; diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 6d5332b2b15..cf1d7d66476 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -33,10 +33,7 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" -#include "BLI_listbase.h" -#include "BLI_path_util.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" +#include "BLI_blenlib.h" #include "BKE_image.h" #include "BKE_main.h" @@ -55,21 +52,27 @@ #include "proxy.h" #include "utils.h" -void SEQ_sort(Scene *scene) +/** + * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by + * channel position as well. + * This is important for SEQ_time_update_sequence to work properly + * + * \param seqbase: ListBase with strips + */ +void SEQ_sort(ListBase *seqbase) { - /* all strips together per kind, and in order of y location ("machine") */ - ListBase seqbase, effbase; - Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *seqt; - - if (ed == NULL) { + if (seqbase == NULL) { return; } - BLI_listbase_clear(&seqbase); + /* all strips together per kind, and in order of y location ("machine") */ + ListBase inputbase, effbase; + Sequence *seq, *seqt; + + BLI_listbase_clear(&inputbase); BLI_listbase_clear(&effbase); - while ((seq = BLI_pophead(ed->seqbasep))) { + while ((seq = BLI_pophead(seqbase))) { if (seq->type & SEQ_TYPE_EFFECT) { seqt = effbase.first; @@ -85,22 +88,22 @@ void SEQ_sort(Scene *scene) } } else { - seqt = seqbase.first; + seqt = inputbase.first; while (seqt) { if (seqt->machine >= seq->machine) { - BLI_insertlinkbefore(&seqbase, seqt, seq); + BLI_insertlinkbefore(&inputbase, seqt, seq); break; } seqt = seqt->next; } if (seqt == NULL) { - BLI_addtail(&seqbase, seq); + BLI_addtail(&inputbase, seq); } } } - BLI_movelisttolist(&seqbase, &effbase); - *(ed->seqbasep) = seqbase; + BLI_movelisttolist(seqbase, &inputbase); + BLI_movelisttolist(seqbase, &effbase); } typedef struct SeqUniqueInfo { @@ -612,3 +615,25 @@ int SEQ_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void return ret; } + +/** + * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it + * will be duplicated and mapped onto new name + * + * \param seq: Sequence which name will be ensured to be unique + * \param scene: Scene in which name must be unique + */ +void SEQ_ensure_unique_name(Sequence *seq, Scene *scene) +{ + char name[SEQ_NAME_MAXSTR]; + + BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_dupe_animdata(scene, name, seq->name + 2); + + if (seq->type == SEQ_TYPE_META) { + LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) { + SEQ_ensure_unique_name(seq_child, scene); + } + } +} |