Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/sequencer/intern')
-rw-r--r--source/blender/sequencer/intern/effects.c5
-rw-r--r--source/blender/sequencer/intern/image_cache.c13
-rw-r--r--source/blender/sequencer/intern/iterator.c286
-rw-r--r--source/blender/sequencer/intern/render.c181
-rw-r--r--source/blender/sequencer/intern/render.h4
-rw-r--r--source/blender/sequencer/intern/sequencer.c4
-rw-r--r--source/blender/sequencer/intern/strip_add.c2
-rw-r--r--source/blender/sequencer/intern/strip_edit.c114
-rw-r--r--source/blender/sequencer/intern/strip_time.c65
-rw-r--r--source/blender/sequencer/intern/utils.c61
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);
+ }
+ }
+}