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:
authorRichard Antalik <richardantalik@gmail.com>2020-11-16 07:02:30 +0300
committerRichard Antalik <richardantalik@gmail.com>2020-11-16 07:02:30 +0300
commit01db805a82129a27b1408d62417c40b0717228dc (patch)
tree53645581058b7d15db1aab11f684edbd0fb655fc
parent52a189936b697164db7349fdc1de017108f0a9eb (diff)
Cleanup: split sequencer.c file
Move most functions into separate files. File sequencer.c is reserved for alloc, free and duplicating functions. There should be no functional changes.
-rw-r--r--source/blender/sequencer/CMakeLists.txt17
-rw-r--r--source/blender/sequencer/intern/clipboard.c179
-rw-r--r--source/blender/sequencer/intern/effects.c4
-rw-r--r--source/blender/sequencer/intern/effects.h50
-rw-r--r--source/blender/sequencer/intern/image_cache.c5
-rw-r--r--source/blender/sequencer/intern/image_cache.h72
-rw-r--r--source/blender/sequencer/intern/iterator.c168
-rw-r--r--source/blender/sequencer/intern/modifier.c1
-rw-r--r--source/blender/sequencer/intern/multiview.c67
-rw-r--r--source/blender/sequencer/intern/multiview.h57
-rw-r--r--source/blender/sequencer/intern/prefetch.c3
-rw-r--r--source/blender/sequencer/intern/prefetch.h53
-rw-r--r--source/blender/sequencer/intern/proxy.c26
-rw-r--r--source/blender/sequencer/intern/proxy.h3
-rw-r--r--source/blender/sequencer/intern/render.c56
-rw-r--r--source/blender/sequencer/intern/render.h6
-rw-r--r--source/blender/sequencer/intern/sequencer.c2998
-rw-r--r--source/blender/sequencer/intern/sequencer.h102
-rw-r--r--source/blender/sequencer/intern/sound.c163
-rw-r--r--source/blender/sequencer/intern/strip_add.c551
-rw-r--r--source/blender/sequencer/intern/strip_edit.c196
-rw-r--r--source/blender/sequencer/intern/strip_relations.c468
-rw-r--r--source/blender/sequencer/intern/strip_select.c81
-rw-r--r--source/blender/sequencer/intern/strip_time.c353
-rw-r--r--source/blender/sequencer/intern/strip_time.h38
-rw-r--r--source/blender/sequencer/intern/strip_transform.c397
-rw-r--r--source/blender/sequencer/intern/utils.c549
-rw-r--r--source/blender/sequencer/intern/utils.h41
28 files changed, 3681 insertions, 3023 deletions
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index 9efe23dd8c4..18755e7e6bc 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -46,16 +46,33 @@ set(INC_SYS
set(SRC
SEQ_sequencer.h
+ intern/clipboard.c
intern/effects.c
+ intern/effects.h
intern/image_cache.c
+ intern/image_cache.h
+ intern/iterator.c
intern/modifier.c
+ intern/multiview.c
+ intern/multiview.h
intern/prefetch.c
+ intern/prefetch.h
intern/proxy.c
intern/proxy.h
intern/render.c
intern/render.h
intern/sequencer.c
intern/sequencer.h
+ intern/sound.c
+ intern/strip_add.c
+ intern/strip_edit.c
+ intern/strip_relations.c
+ intern/strip_select.c
+ intern/strip_time.c
+ intern/strip_time.h
+ intern/strip_transform.c
+ intern/utils.c
+ intern/utils.h
)
set(LIB
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
new file mode 100644
index 00000000000..7d37dab93dd
--- /dev/null
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -0,0 +1,179 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_main.h"
+#include "BKE_movieclip.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "SEQ_sequencer.h"
+
+#include "sequencer.h"
+
+#ifdef WITH_AUDASPACE
+# include <AUD_Special.h>
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Manage pointers in the clipboard.
+ * note that these pointers should _never_ be access in the sequencer,
+ * they are only for storage while in the clipboard
+ * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
+ * since those data-blocks are fully out of Main lists).
+ */
+
+ListBase seqbase_clipboard;
+int seqbase_clipboard_frame;
+
+void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
+
+void BKE_sequencer_free_clipboard(void)
+{
+ Sequence *seq, *nseq;
+
+ BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard);
+
+ for (seq = seqbase_clipboard.first; seq; seq = nseq) {
+ nseq = seq->next;
+ seq_free_sequence_recurse(NULL, seq, false);
+ }
+ BLI_listbase_clear(&seqbase_clipboard);
+}
+
+#define ID_PT (*id_pt)
+static void seqclipboard_ptr_free(Main *UNUSED(bmain), ID **id_pt)
+{
+ if (ID_PT) {
+ BLI_assert(ID_PT->newid != NULL);
+ MEM_freeN(ID_PT);
+ ID_PT = NULL;
+ }
+}
+static void seqclipboard_ptr_store(Main *UNUSED(bmain), ID **id_pt)
+{
+ if (ID_PT) {
+ ID *id_prev = ID_PT;
+ ID_PT = MEM_dupallocN(ID_PT);
+ ID_PT->newid = id_prev;
+ }
+}
+static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
+{
+ if (ID_PT) {
+ const ListBase *lb = which_libbase(bmain, GS(ID_PT->name));
+ void *id_restore;
+
+ BLI_assert(ID_PT->newid != NULL);
+ if (BLI_findindex(lb, (ID_PT)->newid) != -1) {
+ /* the pointer is still valid */
+ id_restore = (ID_PT)->newid;
+ }
+ else {
+ /* the pointer of the same name still exists */
+ id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2);
+ }
+
+ if (id_restore == NULL) {
+ /* check for a data with the same filename */
+ switch (GS(ID_PT->name)) {
+ case ID_SO: {
+ id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->filepath, offsetof(bSound, filepath));
+ if (id_restore == NULL) {
+ id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->filepath);
+ (ID_PT)->newid = id_restore; /* reuse next time */
+ }
+ break;
+ }
+ case ID_MC: {
+ id_restore = BLI_findstring(
+ lb, ((MovieClip *)ID_PT)->filepath, offsetof(MovieClip, filepath));
+ if (id_restore == NULL) {
+ id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->filepath);
+ (ID_PT)->newid = id_restore; /* reuse next time */
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Replace with pointer to actual data-block. */
+ seqclipboard_ptr_free(bmain, id_pt);
+ ID_PT = id_restore;
+ }
+}
+#undef ID_PT
+
+static void sequence_clipboard_pointers(Main *bmain,
+ Sequence *seq,
+ void (*callback)(Main *, ID **))
+{
+ callback(bmain, (ID **)&seq->scene);
+ callback(bmain, (ID **)&seq->scene_camera);
+ callback(bmain, (ID **)&seq->clip);
+ callback(bmain, (ID **)&seq->mask);
+ callback(bmain, (ID **)&seq->sound);
+
+ if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
+ TextVars *text_data = seq->effectdata;
+ callback(bmain, (ID **)&text_data->text_font);
+ }
+}
+
+/* recursive versions of functions above */
+void BKE_sequencer_base_clipboard_pointers_free(ListBase *seqbase)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(NULL, seq, seqclipboard_ptr_free);
+ BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase);
+ }
+}
+void BKE_sequencer_base_clipboard_pointers_store(Main *bmain, ListBase *seqbase)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store);
+ BKE_sequencer_base_clipboard_pointers_store(bmain, &seq->seqbase);
+ }
+}
+void BKE_sequencer_base_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore);
+ BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain);
+ }
+}
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 5412914e0f6..1d323426cc3 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -62,8 +62,10 @@
#include "BLF_api.h"
+#include "effects.h"
#include "render.h"
-#include "sequencer.h"
+#include "strip_time.h"
+#include "utils.h"
static struct SeqEffectHandle get_sequence_effect_impl(int seq_type);
diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h
new file mode 100644
index 00000000000..58e0a97d4c5
--- /dev/null
+++ b/source/blender/sequencer/intern/effects.h
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Scene;
+struct Sequence;
+struct SeqRenderData;
+
+/* **********************************************************************
+ * sequencer.c
+ *
+ * Sequencer editing functions
+ * **********************************************************************
+ */
+
+struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq);
+void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force);
+float BKE_sequencer_speed_effect_target_frame_get(const struct SeqRenderData *context,
+ struct Sequence *seq,
+ float timeline_frame,
+ int input);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index be6a640dd3f..d515a13cdee 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -50,8 +50,9 @@
#include "SEQ_sequencer.h"
-#include "render.h"
-#include "sequencer.h"
+#include "image_cache.h"
+#include "prefetch.h"
+#include "strip_time.h"
/**
* Sequencer Cache Design Notes
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
new file mode 100644
index 00000000000..0fcf0548628
--- /dev/null
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ImBuf;
+struct Main;
+struct Scene;
+struct Sequence;
+struct SeqRenderData;
+
+#ifdef __cplusplus
+}
+#endif
+
+struct ImBuf *BKE_sequencer_cache_get(const struct SeqRenderData *context,
+ struct Sequence *seq,
+ float timeline_frame,
+ int type,
+ bool skip_disk_cache);
+void BKE_sequencer_cache_put(const struct SeqRenderData *context,
+ struct Sequence *seq,
+ float timeline_frame,
+ int type,
+ struct ImBuf *i,
+ float cost,
+ bool skip_disk_cache);
+bool BKE_sequencer_cache_put_if_possible(const struct SeqRenderData *context,
+ struct Sequence *seq,
+ float timeline_frame,
+ int type,
+ struct ImBuf *nval,
+ float cost,
+ bool skip_disk_cache);
+bool BKE_sequencer_cache_recycle_item(struct Scene *scene);
+void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
+void BKE_sequencer_cache_destruct(struct Scene *scene);
+void BKE_sequencer_cache_cleanup_all(struct Main *bmain);
+void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene,
+ struct Sequence *seq,
+ struct Sequence *seq_changed,
+ int invalidate_types,
+ bool force_seq_changed_range);
+bool BKE_sequencer_cache_is_full(struct Scene *scene);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
new file mode 100644
index 00000000000..fe6f4184ab1
--- /dev/null
+++ b/source/blender/sequencer/intern/iterator.c
@@ -0,0 +1,168 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_scene.h"
+
+#include "SEQ_sequencer.h"
+
+/* ************************* iterator ************************** */
+/* *************** (replaces old WHILE_SEQ) ********************* */
+/* **************** use now SEQ_ALL_BEGIN () SEQ_ALL_END ***************** */
+
+/* sequence strip iterator:
+ * - builds a full array, recursively into meta strips
+ */
+
+static void seq_count(ListBase *seqbase, int *tot)
+{
+ Sequence *seq;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ (*tot)++;
+
+ if (seq->seqbase.first) {
+ seq_count(&seq->seqbase, tot);
+ }
+ }
+}
+
+static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth)
+{
+ Sequence *seq;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ seq->depth = depth;
+
+ if (seq->seqbase.first) {
+ seq_build_array(&seq->seqbase, array, depth + 1);
+ }
+
+ **array = seq;
+ (*array)++;
+ }
+}
+
+static void seq_array(Editing *ed,
+ Sequence ***seqarray,
+ int *tot,
+ const bool use_current_sequences)
+{
+ Sequence **array;
+
+ *seqarray = NULL;
+ *tot = 0;
+
+ if (ed == NULL) {
+ return;
+ }
+
+ if (use_current_sequences) {
+ seq_count(ed->seqbasep, tot);
+ }
+ else {
+ seq_count(&ed->seqbase, tot);
+ }
+
+ if (*tot == 0) {
+ return;
+ }
+
+ *seqarray = array = MEM_mallocN(sizeof(Sequence *) * (*tot), "SeqArray");
+ if (use_current_sequences) {
+ seq_build_array(ed->seqbasep, &array, 0);
+ }
+ else {
+ seq_build_array(&ed->seqbase, &array, 0);
+ }
+}
+
+void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences)
+{
+ memset(iter, 0, sizeof(*iter));
+ seq_array(ed, &iter->array, &iter->tot, use_current_sequences);
+
+ if (iter->tot) {
+ iter->cur = 0;
+ iter->seq = iter->array[iter->cur];
+ iter->valid = 1;
+ }
+}
+
+void BKE_sequence_iterator_next(SeqIterator *iter)
+{
+ if (++iter->cur < iter->tot) {
+ iter->seq = iter->array[iter->cur];
+ }
+ else {
+ iter->valid = 0;
+ }
+}
+
+void BKE_sequence_iterator_end(SeqIterator *iter)
+{
+ if (iter->array) {
+ MEM_freeN(iter->array);
+ }
+
+ iter->valid = 0;
+}
+
+int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
+ int (*apply_fn)(Sequence *seq, void *),
+ void *arg)
+{
+ Sequence *iseq;
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (BKE_sequencer_recursive_apply(iseq, apply_fn, arg) == -1) {
+ return -1; /* bail out */
+ }
+ }
+ return 1;
+}
+
+int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg)
+{
+ int ret = apply_fn(seq, arg);
+
+ if (ret == -1) {
+ return -1; /* bail out */
+ }
+
+ if (ret && seq->seqbase.first) {
+ ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_fn, arg);
+ }
+
+ return ret;
+}
diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c
index ae5aae4f412..2c37ecf1910 100644
--- a/source/blender/sequencer/intern/modifier.c
+++ b/source/blender/sequencer/intern/modifier.c
@@ -49,7 +49,6 @@
#include "BLO_read_write.h"
#include "render.h"
-#include "sequencer.h"
static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
static bool modifierTypesInit = false;
diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c
new file mode 100644
index 00000000000..e120234ed8b
--- /dev/null
+++ b/source/blender/sequencer/intern/multiview.c
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+
+#include "BLI_string.h"
+
+#include "BKE_scene.h"
+
+#include "IMB_imbuf.h"
+
+#include "multiview.h"
+
+void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ IMB_suffix_anim(anim, suffix);
+}
+
+/* the number of files will vary according to the stereo format */
+int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+{
+ if (!is_multiview) {
+ return 1;
+ }
+ if (views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+
+ return BKE_scene_multiview_num_views_get(&scene->r);
+}
+
+void seq_multiview_name(Scene *scene,
+ const int view_id,
+ const char *prefix,
+ const char *ext,
+ char *r_path,
+ size_t r_size)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_assert(ext != NULL && suffix != NULL && prefix != NULL);
+ BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
+}
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
new file mode 100644
index 00000000000..e1f998d18e2
--- /dev/null
+++ b/source/blender/sequencer/intern/multiview.h
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Editing;
+struct ImBuf;
+struct Main;
+struct Mask;
+struct Scene;
+struct Sequence;
+struct StripColorBalance;
+struct StripElem;
+
+/* **********************************************************************
+ * sequencer.c
+ *
+ * Sequencer editing functions
+ * **********************************************************************
+ */
+
+void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, const int view_id);
+void seq_multiview_name(struct Scene *scene,
+ const int view_id,
+ const char *prefix,
+ const char *ext,
+ char *r_path,
+ size_t r_size);
+int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 694feb5e952..33354fb9e6d 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -55,8 +55,9 @@
#include "SEQ_sequencer.h"
+#include "image_cache.h"
+#include "prefetch.h"
#include "render.h"
-#include "sequencer.h"
typedef struct PrefetchJob {
struct PrefetchJob *next, *prev;
diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h
new file mode 100644
index 00000000000..aa47a9dbcfc
--- /dev/null
+++ b/source/blender/sequencer/intern/prefetch.h
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ImBuf;
+struct Main;
+struct Scene;
+struct Sequence;
+struct SeqRenderData;
+
+#ifdef __cplusplus
+}
+#endif
+
+void BKE_sequencer_prefetch_start(const struct SeqRenderData *context,
+ float timeline_frame,
+ float cost);
+void BKE_sequencer_prefetch_free(struct Scene *scene);
+bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene);
+void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+struct SeqRenderData *BKE_sequencer_prefetch_get_original_context(
+ const struct SeqRenderData *context);
+struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq,
+ struct Scene *scene);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 398a9a3e072..ff65216d987 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -49,16 +49,19 @@
#include "DEG_depsgraph.h"
-#include "SEQ_sequencer.h"
-
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
+#include "SEQ_sequencer.h"
+
+#include "multiview.h"
#include "proxy.h"
#include "render.h"
#include "sequencer.h"
+#include "strip_time.h"
+#include "utils.h"
typedef struct SeqIndexBuildContext {
struct IndexBuildContext *index_context;
@@ -569,3 +572,22 @@ void SEQ_proxy_set(struct Sequence *seq, bool value)
seq->flag &= ~SEQ_USE_PROXY;
}
}
+
+void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
+{
+ char dir[FILE_MAX];
+ char fname[FILE_MAXFILE];
+
+ IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
+ BLI_strncpy(dir, base_dir, sizeof(dir));
+ BLI_path_append(dir, sizeof(dir), fname);
+ IMB_anim_set_index_dir(anim, dir);
+}
+
+void free_proxy_seq(Sequence *seq)
+{
+ if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) {
+ IMB_free_anim(seq->strip->proxy->anim);
+ seq->strip->proxy->anim = NULL;
+ }
+}
diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h
index a2a94f036b1..a362a318a5a 100644
--- a/source/blender/sequencer/intern/proxy.h
+++ b/source/blender/sequencer/intern/proxy.h
@@ -27,6 +27,7 @@
extern "C" {
#endif
+struct anim;
struct ImBuf;
struct SeqRenderData;
struct Sequence;
@@ -36,6 +37,8 @@ struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context,
struct Sequence *seq,
int timeline_frame);
bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, const int view_id);
+void free_proxy_seq(Sequence *seq);
+void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index ecfd230be18..008ea1cd3a0 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -66,9 +66,14 @@
#include "SEQ_sequencer.h"
+#include "effects.h"
+#include "image_cache.h"
+#include "multiview.h"
+#include "prefetch.h"
#include "proxy.h"
#include "render.h"
-#include "sequencer.h"
+#include "strip_time.h"
+#include "utils.h"
static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
SeqRenderState *state,
@@ -257,55 +262,6 @@ void seq_render_state_init(SeqRenderState *state)
state->scene_parents = NULL;
}
-float seq_give_frame_index(Sequence *seq, float timeline_frame)
-{
- float frame_index;
- int sta = seq->start;
- int end = seq->start + seq->len - 1;
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- end = seq->enddisp;
- }
-
- if (end < sta) {
- return -1;
- }
-
- if (seq->flag & SEQ_REVERSE_FRAMES) {
- /*reverse frame in this sequence */
- if (timeline_frame <= sta) {
- frame_index = end - sta;
- }
- else if (timeline_frame >= end) {
- frame_index = 0;
- }
- else {
- frame_index = end - timeline_frame;
- }
- }
- else {
- if (timeline_frame <= sta) {
- frame_index = 0;
- }
- else if (timeline_frame >= end) {
- frame_index = end - sta;
- }
- else {
- frame_index = timeline_frame - sta;
- }
- }
-
- if (seq->strobe < 1.0f) {
- seq->strobe = 1.0f;
- }
-
- if (seq->strobe > 1.0f) {
- frame_index -= fmodf((double)frame_index, (double)seq->strobe);
- }
-
- return frame_index;
-}
-
StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame)
{
StripElem *se = seq->strip->stripdata;
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index 2d0365d74e9..d5affeb547b 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -34,6 +34,11 @@ struct Scene;
struct SeqRenderData;
struct Sequence;
+#define EARLY_NO_INPUT -1
+#define EARLY_DO_EFFECT 0
+#define EARLY_USE_INPUT_1 1
+#define EARLY_USE_INPUT_2 2
+
/* mutable state for sequencer */
typedef struct SeqRenderState {
struct LinkNode *scene_parents;
@@ -55,7 +60,6 @@ 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);
-float seq_give_frame_index(struct Sequence *seq, float timeline_frame);
int seq_get_shown_sequences(struct ListBase *seqbasep,
int timeline_frame,
int chanshown,
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 67b3b9f5fbd..155c35c2491 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -24,131 +24,52 @@
* \ingroup bke
*/
-#include <math.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_space_types.h"
-#include "DNA_windowmanager_types.h"
-#include "BLI_fileops.h"
-#include "BLI_linklist.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_path_util.h"
-#include "BLI_session_uuid.h"
#include "BLI_string.h"
-#include "BLI_string_utf8.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#else
-# include <unistd.h>
-#endif
-
-#include "BLT_translation.h"
-#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
-#include "BKE_global.h"
#include "BKE_idprop.h"
-#include "BKE_image.h"
-#include "BKE_layer.h"
#include "BKE_lib_id.h"
-#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_movieclip.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_sequencer_offscreen.h"
+#include "BKE_sound.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "RNA_access.h"
-
-#include "RE_pipeline.h"
-
-#include "SEQ_sequencer.h"
-
-#include <pthread.h>
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_metadata.h"
-
-#include "BKE_context.h"
-#include "BKE_sound.h"
-#include "RE_engine.h"
+#include "SEQ_sequencer.h"
+#include "image_cache.h"
+#include "prefetch.h"
#include "sequencer.h"
-
-#ifdef WITH_AUDASPACE
-# include <AUD_Special.h>
-#endif
+#include "utils.h"
static void seq_free_animdata(Scene *scene, Sequence *seq);
-static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id);
-
-/* **** XXX ******** */
-#define SELECT 1
-ListBase seqbase_clipboard;
-int seqbase_clipboard_frame;
-int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
- int (*apply_fn)(Sequence *seq, void *),
- void *arg)
-{
- Sequence *iseq;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (BKE_sequencer_recursive_apply(iseq, apply_fn, arg) == -1) {
- return -1; /* bail out */
- }
- }
- return 1;
-}
+/* -------------------------------------------------------------------- */
+/** \name Alloc / free functions
+ * \{ */
-int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg)
+static Strip *seq_strip_alloc(int type)
{
- int ret = apply_fn(seq, arg);
-
- if (ret == -1) {
- return -1; /* bail out */
- }
+ Strip *strip = MEM_callocN(sizeof(Strip), "strip");
- if (ret && seq->seqbase.first) {
- ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_fn, arg);
+ if (ELEM(type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) {
+ strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
+ strip->transform->scale_x = 1;
+ strip->transform->scale_y = 1;
+ strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
}
- return ret;
-}
-
-/*********************** alloc / free functions *************************/
-
-/* free */
-
-static void free_proxy_seq(Sequence *seq)
-{
- if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) {
- IMB_free_anim(seq->strip->proxy->anim);
- seq->strip->proxy->anim = NULL;
- }
+ strip->us = 1;
+ return strip;
}
static void seq_free_strip(Strip *strip)
@@ -183,6 +104,36 @@ static void seq_free_strip(Strip *strip)
MEM_freeN(strip);
}
+Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type)
+{
+ Sequence *seq;
+
+ seq = MEM_callocN(sizeof(Sequence), "addseq");
+ BLI_addtail(lb, seq);
+
+ *((short *)seq->name) = ID_SEQ;
+ seq->name[2] = 0;
+
+ seq->flag = SELECT;
+ seq->start = timeline_frame;
+ seq->machine = machine;
+ seq->sat = 1.0;
+ seq->mul = 1.0;
+ seq->blend_opacity = 100.0;
+ seq->volume = 1.0f;
+ seq->pitch = 1.0f;
+ seq->scene_sound = NULL;
+ seq->type = type;
+
+ seq->strip = seq_strip_alloc(type);
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+ seq->cache_flag = SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE;
+
+ BKE_sequence_session_uuid_generate(seq);
+
+ return seq;
+}
+
/* only give option to skip cache locally (static func) */
static void BKE_sequence_free_ex(Scene *scene,
Sequence *seq,
@@ -259,22 +210,6 @@ void BKE_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata
BKE_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
}
-/* Function to free imbuf and anim data on changes */
-void BKE_sequence_free_anim(Sequence *seq)
-{
- while (seq->anims.last) {
- StripAnim *sanim = seq->anims.last;
-
- if (sanim->anim) {
- IMB_free_anim(sanim->anim);
- sanim->anim = NULL;
- }
-
- BLI_freelinkN(&seq->anims, sanim);
- }
- BLI_listbase_clear(&seq->anims);
-}
-
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
@@ -297,135 +232,6 @@ Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
return scene->ed;
}
-void BKE_sequencer_free_clipboard(void)
-{
- Sequence *seq, *nseq;
-
- BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard);
-
- for (seq = seqbase_clipboard.first; seq; seq = nseq) {
- nseq = seq->next;
- seq_free_sequence_recurse(NULL, seq, false);
- }
- BLI_listbase_clear(&seqbase_clipboard);
-}
-
-/* -------------------------------------------------------------------- */
-/* Manage pointers in the clipboard.
- * note that these pointers should _never_ be access in the sequencer,
- * they are only for storage while in the clipboard
- * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
- * since those data-blocks are fully out of Main lists).
- */
-#define ID_PT (*id_pt)
-static void seqclipboard_ptr_free(Main *UNUSED(bmain), ID **id_pt)
-{
- if (ID_PT) {
- BLI_assert(ID_PT->newid != NULL);
- MEM_freeN(ID_PT);
- ID_PT = NULL;
- }
-}
-static void seqclipboard_ptr_store(Main *UNUSED(bmain), ID **id_pt)
-{
- if (ID_PT) {
- ID *id_prev = ID_PT;
- ID_PT = MEM_dupallocN(ID_PT);
- ID_PT->newid = id_prev;
- }
-}
-static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
-{
- if (ID_PT) {
- const ListBase *lb = which_libbase(bmain, GS(ID_PT->name));
- void *id_restore;
-
- BLI_assert(ID_PT->newid != NULL);
- if (BLI_findindex(lb, (ID_PT)->newid) != -1) {
- /* the pointer is still valid */
- id_restore = (ID_PT)->newid;
- }
- else {
- /* the pointer of the same name still exists */
- id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2);
- }
-
- if (id_restore == NULL) {
- /* check for a data with the same filename */
- switch (GS(ID_PT->name)) {
- case ID_SO: {
- id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->filepath, offsetof(bSound, filepath));
- if (id_restore == NULL) {
- id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->filepath);
- (ID_PT)->newid = id_restore; /* reuse next time */
- }
- break;
- }
- case ID_MC: {
- id_restore = BLI_findstring(
- lb, ((MovieClip *)ID_PT)->filepath, offsetof(MovieClip, filepath));
- if (id_restore == NULL) {
- id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->filepath);
- (ID_PT)->newid = id_restore; /* reuse next time */
- }
- break;
- }
- default:
- break;
- }
- }
-
- /* Replace with pointer to actual data-block. */
- seqclipboard_ptr_free(bmain, id_pt);
- ID_PT = id_restore;
- }
-}
-#undef ID_PT
-
-static void sequence_clipboard_pointers(Main *bmain,
- Sequence *seq,
- void (*callback)(Main *, ID **))
-{
- callback(bmain, (ID **)&seq->scene);
- callback(bmain, (ID **)&seq->scene_camera);
- callback(bmain, (ID **)&seq->clip);
- callback(bmain, (ID **)&seq->mask);
- callback(bmain, (ID **)&seq->sound);
-
- if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
- TextVars *text_data = seq->effectdata;
- callback(bmain, (ID **)&text_data->text_font);
- }
-}
-
-/* recursive versions of functions above */
-void BKE_sequencer_base_clipboard_pointers_free(ListBase *seqbase)
-{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(NULL, seq, seqclipboard_ptr_free);
- BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase);
- }
-}
-void BKE_sequencer_base_clipboard_pointers_store(Main *bmain, ListBase *seqbase)
-{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store);
- BKE_sequencer_base_clipboard_pointers_store(bmain, &seq->seqbase);
- }
-}
-void BKE_sequencer_base_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
-{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore);
- BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain);
- }
-}
-
-/* end clipboard pointer mess */
-
Editing *BKE_sequencer_editing_ensure(Scene *scene)
{
if (scene->ed == NULL) {
@@ -467,2362 +273,39 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
scene->ed = NULL;
}
-/* ************************* iterator ************************** */
-/* *************** (replaces old WHILE_SEQ) ********************* */
-/* **************** use now SEQ_ALL_BEGIN () SEQ_ALL_END ***************** */
-
-/* sequence strip iterator:
- * - builds a full array, recursively into meta strips
- */
-
-static void seq_count(ListBase *seqbase, int *tot)
-{
- Sequence *seq;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- (*tot)++;
-
- if (seq->seqbase.first) {
- seq_count(&seq->seqbase, tot);
- }
- }
-}
-
-static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth)
-{
- Sequence *seq;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- seq->depth = depth;
-
- if (seq->seqbase.first) {
- seq_build_array(&seq->seqbase, array, depth + 1);
- }
-
- **array = seq;
- (*array)++;
- }
-}
-
-static void seq_array(Editing *ed,
- Sequence ***seqarray,
- int *tot,
- const bool use_current_sequences)
-{
- Sequence **array;
-
- *seqarray = NULL;
- *tot = 0;
-
- if (ed == NULL) {
- return;
- }
-
- if (use_current_sequences) {
- seq_count(ed->seqbasep, tot);
- }
- else {
- seq_count(&ed->seqbase, tot);
- }
-
- if (*tot == 0) {
- return;
- }
-
- *seqarray = array = MEM_mallocN(sizeof(Sequence *) * (*tot), "SeqArray");
- if (use_current_sequences) {
- seq_build_array(ed->seqbasep, &array, 0);
- }
- else {
- seq_build_array(&ed->seqbase, &array, 0);
- }
-}
-
-void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences)
-{
- memset(iter, 0, sizeof(*iter));
- seq_array(ed, &iter->array, &iter->tot, use_current_sequences);
-
- if (iter->tot) {
- iter->cur = 0;
- iter->seq = iter->array[iter->cur];
- iter->valid = 1;
- }
-}
-
-void BKE_sequence_iterator_next(SeqIterator *iter)
-{
- if (++iter->cur < iter->tot) {
- iter->seq = iter->array[iter->cur];
- }
- else {
- iter->valid = 0;
- }
-}
-
-void BKE_sequence_iterator_end(SeqIterator *iter)
-{
- if (iter->array) {
- MEM_freeN(iter->array);
- }
-
- iter->valid = 0;
-}
-
-static int metaseq_start(Sequence *metaseq)
-{
- return metaseq->start + metaseq->startofs;
-}
-
-static int metaseq_end(Sequence *metaseq)
-{
- return metaseq->start + metaseq->len - metaseq->endofs;
-}
-
-static void seq_update_sound_bounds_recursive_impl(Scene *scene,
- Sequence *metaseq,
- int start,
- int end)
-{
- Sequence *seq;
-
- /* for sound we go over full meta tree to update bounds of the sound strips,
- * since sound is played outside of evaluating the imbufs, */
- for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive_impl(
- scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- if (seq->scene_sound) {
- int startofs = seq->startofs;
- int endofs = seq->endofs;
- if (seq->startofs + seq->start < start) {
- startofs = start - seq->start;
- }
-
- if (seq->start + seq->len - seq->endofs > end) {
- endofs = seq->start + seq->len - end;
- }
-
- BKE_sound_move_scene_sound(scene,
- seq->scene_sound,
- seq->start + startofs,
- seq->start + seq->len - endofs,
- startofs + seq->anim_startofs);
- }
- }
- }
-}
-
-static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
-{
- seq_update_sound_bounds_recursive_impl(
- scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
-}
-
-void BKE_sequence_calc_disp(Scene *scene, Sequence *seq)
-{
- if (seq->startofs && seq->startstill) {
- seq->startstill = 0;
- }
- if (seq->endofs && seq->endstill) {
- seq->endstill = 0;
- }
-
- seq->startdisp = seq->start + seq->startofs - seq->startstill;
- seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
-
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
- }
-}
-
-void BKE_sequence_calc(Scene *scene, Sequence *seq)
+static void seq_new_fix_links_recursive(Sequence *seq)
{
- Sequence *seqm;
- int min, max;
-
- /* check all metas recursively */
- seqm = seq->seqbase.first;
- while (seqm) {
- if (seqm->seqbase.first) {
- BKE_sequence_calc(scene, seqm);
- }
- seqm = seqm->next;
- }
+ SequenceModifierData *smd;
- /* effects and meta: automatic start and end */
if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1) {
- seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
- if (seq->seq3) {
- seq->start = seq->startdisp = max_iii(
- seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
- seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
- }
- else if (seq->seq2) {
- seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
- seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
- }
- else {
- seq->start = seq->startdisp = seq->seq1->startdisp;
- seq->enddisp = seq->seq1->enddisp;
- }
- /* we cant help if strips don't overlap, it wont give useful results.
- * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
- if (seq->enddisp < seq->startdisp) {
- /* simple start/end swap */
- seq->start = seq->enddisp;
- seq->enddisp = seq->startdisp;
- seq->startdisp = seq->start;
- seq->flag |= SEQ_INVALID_EFFECT;
- }
- else {
- seq->flag &= ~SEQ_INVALID_EFFECT;
- }
-
- seq->len = seq->enddisp - seq->startdisp;
- }
- else {
- BKE_sequence_calc_disp(scene, seq);
- }
- }
- else {
- if (seq->type == SEQ_TYPE_META) {
- seqm = seq->seqbase.first;
- if (seqm) {
- min = MAXFRAME * 2;
- max = -MAXFRAME * 2;
- while (seqm) {
- if (seqm->startdisp < min) {
- min = seqm->startdisp;
- }
- if (seqm->enddisp > max) {
- max = seqm->enddisp;
- }
- seqm = seqm->next;
- }
- seq->start = min + seq->anim_startofs;
- seq->len = max - min;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- }
- seq_update_sound_bounds_recursive(scene, seq);
- }
- BKE_sequence_calc_disp(scene, seq);
- }
-}
-
-void seq_multiview_name(Scene *scene,
- const int view_id,
- const char *prefix,
- const char *ext,
- char *r_path,
- size_t r_size)
-{
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
- BLI_assert(ext != NULL && suffix != NULL && prefix != NULL);
- BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
-}
-
-/* note: caller should run BKE_sequence_calc(scene, seq) after */
-void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
-{
- char path[FILE_MAX];
- int prev_startdisp = 0, prev_enddisp = 0;
- /* note: don't rename the strip, will break animation curves */
-
- if (ELEM(seq->type,
- SEQ_TYPE_MOVIE,
- SEQ_TYPE_IMAGE,
- SEQ_TYPE_SOUND_RAM,
- SEQ_TYPE_SCENE,
- SEQ_TYPE_META,
- SEQ_TYPE_MOVIECLIP,
- SEQ_TYPE_MASK) == 0) {
- return;
- }
-
- if (lock_range) {
- /* keep so we don't have to move the actual start and end points (only the data) */
- BKE_sequence_calc_disp(scene, seq);
- prev_startdisp = seq->startdisp;
- prev_enddisp = seq->enddisp;
- }
-
- switch (seq->type) {
- case SEQ_TYPE_IMAGE: {
- /* Hack? */
- size_t olen = MEM_allocN_len(seq->strip->stripdata) / sizeof(StripElem);
-
- seq->len = olen;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- case SEQ_TYPE_MOVIE: {
- StripAnim *sanim;
- bool is_multiview_loaded = false;
- const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (scene->r.scemode & R_MULTIVIEW) != 0;
-
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
-
- BKE_sequence_free_anim(seq);
-
- if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- char prefix[FILE_MAX];
- const char *ext = NULL;
- const int totfiles = seq_num_files(scene, seq->views_format, true);
- int i = 0;
-
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
-
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- struct anim *anim;
- char str[FILE_MAX];
-
- seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
- anim = openanim(str,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
-
- if (anim) {
- seq_anim_add_suffix(scene, anim, i);
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim;
- }
- }
- is_multiview_loaded = true;
- }
- }
-
- if (is_multiview_loaded == false) {
- struct anim *anim;
- anim = openanim(path,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- if (anim) {
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim;
- }
- }
-
- /* use the first video as reference for everything */
- sanim = seq->anims.first;
-
- if ((!sanim) || (!sanim->anim)) {
- return;
- }
-
- IMB_anim_load_metadata(sanim->anim);
-
- seq->len = IMB_anim_get_duration(
- sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
-
- seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
-
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- case SEQ_TYPE_MOVIECLIP:
- if (seq->clip == NULL) {
- return;
- }
-
- seq->len = BKE_movieclip_get_duration(seq->clip);
-
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- case SEQ_TYPE_MASK:
- if (seq->mask == NULL) {
- return;
- }
- seq->len = BKE_mask_get_duration(seq->mask);
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- case SEQ_TYPE_SOUND_RAM:
-#ifdef WITH_AUDASPACE
- if (!seq->sound) {
- return;
- }
- seq->len = ceil((double)BKE_sound_get_length(bmain, seq->sound) * FPS);
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
-#else
- UNUSED_VARS(bmain);
- return;
-#endif
- break;
- case SEQ_TYPE_SCENE: {
- seq->len = (seq->scene) ? seq->scene->r.efra - seq->scene->r.sfra + 1 : 0;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- }
-
- free_proxy_seq(seq);
-
- if (lock_range) {
- BKE_sequence_tx_set_final_left(seq, prev_startdisp);
- BKE_sequence_tx_set_final_right(seq, prev_enddisp);
- BKE_sequence_single_fix(seq);
- }
-
- BKE_sequence_calc(scene, seq);
-}
-
-void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
- struct Scene *scene,
- struct Sequence *seq,
- bool *r_was_reloaded,
- bool *r_can_produce_frames)
-{
- BLI_assert(seq->type == SEQ_TYPE_MOVIE ||
- !"This function is only implemented for movie strips.");
-
- bool must_reload = false;
-
- /* The Sequence struct allows for multiple anim structs to be associated with one strip. This
- * function will return true only if there is at least one 'anim' AND all anims can produce
- * frames. */
-
- if (BLI_listbase_is_empty(&seq->anims)) {
- /* No anim present, so reloading is always necessary. */
- must_reload = true;
- }
- else {
- LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
- if (!IMB_anim_can_produce_frames(sanim->anim)) {
- /* Anim cannot produce frames, try reloading. */
- must_reload = true;
- break;
- }
- };
- }
-
- if (!must_reload) {
- /* There are one or more anims, and all can produce frames. */
- *r_was_reloaded = false;
- *r_can_produce_frames = true;
- return;
- }
-
- BKE_sequence_reload_new_file(bmain, scene, seq, true);
- *r_was_reloaded = true;
-
- if (BLI_listbase_is_empty(&seq->anims)) {
- /* No anims present after reloading => no frames can be produced. */
- *r_can_produce_frames = false;
- return;
- }
-
- /* Check if there are still anims that cannot produce frames. */
- LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
- if (!IMB_anim_can_produce_frames(sanim->anim)) {
- /* There still is an anim that cannot produce frames. */
- *r_can_produce_frames = false;
- return;
- }
- };
-
- /* There are one or more anims, and all can produce frames. */
- *r_can_produce_frames = true;
-}
-
-void BKE_sequencer_sort(Scene *scene)
-{
- /* all strips together per kind, and in order of y location ("machine") */
- ListBase seqbase, effbase;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq, *seqt;
-
- if (ed == NULL) {
- return;
- }
-
- BLI_listbase_clear(&seqbase);
- BLI_listbase_clear(&effbase);
-
- while ((seq = BLI_pophead(ed->seqbasep))) {
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- seqt = effbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&effbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&effbase, seq);
- }
- }
- else {
- seqt = seqbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&seqbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&seqbase, seq);
- }
- }
- }
-
- BLI_movelisttolist(&seqbase, &effbase);
- *(ed->seqbasep) = seqbase;
-}
-
-/** Comparison function suitable to be used with BLI_listbase_sort()... */
-int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
-{
- const Sequence *seq_a = a;
- const Sequence *seq_b = b;
-
- return (seq_a->startdisp > seq_b->startdisp);
-}
-
-typedef struct SeqUniqueInfo {
- Sequence *seq;
- char name_src[SEQ_NAME_MAXSTR];
- char name_dest[SEQ_NAME_MAXSTR];
- int count;
- int match;
-} SeqUniqueInfo;
-
-static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
-{
- Sequence *seq;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
- /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */
- BLI_snprintf(sui->name_dest,
- sizeof(sui->name_dest),
- "%.*s.%03d",
- SEQ_NAME_MAXSTR - 4 - 1 - 2,
- sui->name_src,
- sui->count++);
- sui->match = 1; /* be sure to re-scan */
- }
- }
-}
-
-static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
-{
- if (seq->seqbase.first) {
- seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
- }
- return 1;
-}
-
-void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
-{
- SeqUniqueInfo sui;
- char *dot;
- sui.seq = seq;
- BLI_strncpy(sui.name_src, seq->name + 2, sizeof(sui.name_src));
- BLI_strncpy(sui.name_dest, seq->name + 2, sizeof(sui.name_dest));
-
- sui.count = 1;
- sui.match = 1; /* assume the worst to start the loop */
-
- /* Strip off the suffix */
- if ((dot = strrchr(sui.name_src, '.'))) {
- *dot = '\0';
- dot++;
-
- if (*dot) {
- sui.count = atoi(dot) + 1;
- }
- }
-
- while (sui.match) {
- sui.match = 0;
- seqbase_unique_name(seqbasep, &sui);
- BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
- }
-
- BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
-}
-
-static const char *give_seqname_by_type(int type)
-{
- switch (type) {
- case SEQ_TYPE_META:
- return "Meta";
- case SEQ_TYPE_IMAGE:
- return "Image";
- case SEQ_TYPE_SCENE:
- return "Scene";
- case SEQ_TYPE_MOVIE:
- return "Movie";
- case SEQ_TYPE_MOVIECLIP:
- return "Clip";
- case SEQ_TYPE_MASK:
- return "Mask";
- case SEQ_TYPE_SOUND_RAM:
- return "Audio";
- case SEQ_TYPE_CROSS:
- return "Cross";
- case SEQ_TYPE_GAMCROSS:
- return "Gamma Cross";
- case SEQ_TYPE_ADD:
- return "Add";
- case SEQ_TYPE_SUB:
- return "Sub";
- case SEQ_TYPE_MUL:
- return "Mul";
- case SEQ_TYPE_ALPHAOVER:
- return "Alpha Over";
- case SEQ_TYPE_ALPHAUNDER:
- return "Alpha Under";
- case SEQ_TYPE_OVERDROP:
- return "Over Drop";
- case SEQ_TYPE_COLORMIX:
- return "Color Mix";
- case SEQ_TYPE_WIPE:
- return "Wipe";
- case SEQ_TYPE_GLOW:
- return "Glow";
- case SEQ_TYPE_TRANSFORM:
- return "Transform";
- case SEQ_TYPE_COLOR:
- return "Color";
- case SEQ_TYPE_MULTICAM:
- return "Multicam";
- case SEQ_TYPE_ADJUSTMENT:
- return "Adjustment";
- case SEQ_TYPE_SPEED:
- return "Speed";
- case SEQ_TYPE_GAUSSIAN_BLUR:
- return "Gaussian Blur";
- case SEQ_TYPE_TEXT:
- return "Text";
- default:
- return NULL;
- }
-}
-
-const char *BKE_sequence_give_name(Sequence *seq)
-{
- const char *name = give_seqname_by_type(seq->type);
-
- if (!name) {
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- return seq->strip->dir;
- }
-
- return "Effect";
- }
- return name;
-}
-
-ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
-{
- ListBase *seqbase = NULL;
-
- switch (seq->type) {
- case SEQ_TYPE_META: {
- seqbase = &seq->seqbase;
- *r_offset = seq->start;
- break;
- }
- case SEQ_TYPE_SCENE: {
- if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
- Editing *ed = BKE_sequencer_editing_get(seq->scene, false);
- if (ed) {
- seqbase = &ed->seqbase;
- *r_offset = seq->scene->r.sfra;
- }
- }
- break;
- }
- }
-
- return seqbase;
-}
-
-/* the number of files will vary according to the stereo format */
-int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
-{
- if (!is_multiview) {
- return 1;
- }
- if (views_format == R_IMF_VIEWS_STEREO_3D) {
- return 1;
- }
- /* R_IMF_VIEWS_INDIVIDUAL */
-
- return BKE_scene_multiview_num_views_get(&scene->r);
-}
-
-void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
-{
- char dir[FILE_MAX];
- char fname[FILE_MAXFILE];
-
- IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
- BLI_strncpy(dir, base_dir, sizeof(dir));
- BLI_path_append(dir, sizeof(dir), fname);
- IMB_anim_set_index_dir(anim, dir);
-}
-
-void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
-{
- char dir[FILE_MAX];
- char name[FILE_MAX];
- StripProxy *proxy;
- bool use_proxy;
- bool is_multiview_loaded = false;
- Editing *ed = scene->ed;
- const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (scene->r.scemode & R_MULTIVIEW) != 0;
-
- if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
- return;
- }
-
- /* reset all the previously created anims */
- BKE_sequence_free_anim(seq);
-
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
-
- proxy = seq->strip->proxy;
-
- use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
- (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
-
- if (use_proxy) {
- if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
- if (ed->proxy_dir[0] == 0) {
- BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
- }
- else {
- BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
- }
- }
- else {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
- }
-
- if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
- int totfiles = seq_num_files(scene, seq->views_format, true);
- char prefix[FILE_MAX];
- const char *ext = NULL;
- int i;
-
- BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
-
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
- char str[FILE_MAX];
- StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
-
- BLI_addtail(&seq->anims, sanim);
-
- BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
-
- if (openfile) {
- sanim->anim = openanim(str,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(str,
- IB_rect |
- ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
-
- if (sanim->anim) {
- /* we already have the suffix */
- IMB_suffix_anim(sanim->anim, suffix);
- }
- else {
- if (openfile) {
- sanim->anim = openanim(name,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(name,
- IB_rect |
- ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
-
- /* No individual view files - monoscopic, stereo 3d or EXR multi-view. */
- totfiles = 1;
- }
-
- if (sanim->anim && use_proxy) {
- seq_proxy_index_dir_set(sanim->anim, dir);
- }
- }
- is_multiview_loaded = true;
- }
- }
-
- if (is_multiview_loaded == false) {
- StripAnim *sanim;
-
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
-
- if (openfile) {
- sanim->anim = openanim(name,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(name,
- IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex,
- seq->strip->colorspace_settings.name);
- }
-
- if (sanim->anim && use_proxy) {
- seq_proxy_index_dir_set(sanim->anim, dir);
- }
- }
-}
-
-/* check whether sequence cur depends on seq */
-static bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
-{
- if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq) {
- return true;
- }
-
- /* sequences are not intersecting in time, assume no dependency exists between them */
- if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp) {
- return false;
- }
-
- /* checking sequence is below reference one, not dependent on it */
- if (cur->machine < seq->machine) {
- return false;
- }
-
- /* sequence is not blending with lower machines, no dependency here occurs
- * check for non-effects only since effect could use lower machines as input
- */
- if ((cur->type & SEQ_TYPE_EFFECT) == 0 &&
- ((cur->blend_mode == SEQ_BLEND_REPLACE) ||
- (cur->blend_mode == SEQ_TYPE_CROSS && cur->blend_opacity == 100.0f))) {
- return false;
- }
-
- return true;
-}
-
-static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBase *seqbase)
-{
- Sequence *cur;
-
- for (cur = seqbase->first; cur; cur = cur->next) {
- if (cur == seq) {
- continue;
- }
-
- if (BKE_sequence_check_depend(seq, cur)) {
- /* Effect must be invalidated completely if they depend on invalidated seq. */
- if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
- BKE_sequencer_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
- }
- else {
- /* In case of alpha over for example only invalidate composite image */
- BKE_sequencer_cache_cleanup_sequence(
- scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT, false);
- }
- }
-
- if (cur->seqbase.first) {
- sequence_do_invalidate_dependent(scene, seq, &cur->seqbase);
- }
- }
-}
-
-static void sequence_invalidate_cache(Scene *scene,
- Sequence *seq,
- bool invalidate_self,
- int invalidate_types)
-{
- Editing *ed = scene->ed;
-
- if (invalidate_self) {
- BKE_sequence_free_anim(seq);
- BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false);
- }
-
- if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) {
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- }
-
- sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
- DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
- BKE_sequencer_prefetch_stop(scene);
-}
-
-void BKE_sequence_invalidate_cache_in_range(Scene *scene,
- Sequence *seq,
- Sequence *range_mask,
- int invalidate_types)
-{
- BKE_sequencer_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
-}
-
-void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
-{
- sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
-}
-
-void BKE_sequence_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
-{
- sequence_invalidate_cache(scene,
- seq,
- true,
- SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE |
- SEQ_CACHE_STORE_FINAL_OUT);
-}
-
-void BKE_sequence_invalidate_cache_composite(Scene *scene, Sequence *seq)
-{
- if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
- return;
- }
-
- sequence_invalidate_cache(
- scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
-}
-
-void BKE_sequence_invalidate_dependent(Scene *scene, Sequence *seq)
-{
- if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
- return;
- }
-
- sequence_invalidate_cache(
- scene, seq, false, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
-}
-
-static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase)
-{
- for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (seq->scene == scene_target) {
- BKE_sequence_invalidate_cache_raw(scene, seq);
- }
-
- if (seq->seqbase.first != NULL) {
- invalidate_scene_strips(scene, scene_target, &seq->seqbase);
- }
- }
-}
-
-void BKE_sequence_invalidate_scene_strips(Main *bmain, Scene *scene_target)
-{
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (scene->ed != NULL) {
- invalidate_scene_strips(scene, scene_target, &scene->ed->seqbase);
- }
- }
-}
-
-static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
-{
- for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (seq->clip == clip_target) {
- BKE_sequence_invalidate_cache_raw(scene, seq);
- }
-
- if (seq->seqbase.first != NULL) {
- invalidate_movieclip_strips(scene, clip_target, &seq->seqbase);
- }
- }
-}
-
-void BKE_sequence_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target)
-{
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (scene->ed != NULL) {
- invalidate_movieclip_strips(scene, clip_target, &scene->ed->seqbase);
- }
- }
-}
-
-void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
-{
- if (scene->ed == NULL) {
- return;
- }
-
- Sequence *seq;
-
- BKE_sequencer_cache_cleanup(scene);
- BKE_sequencer_prefetch_stop(scene);
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
- continue;
- }
-
- if (seq->strip) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- BKE_sequence_free_anim(seq);
- }
- if (seq->type == SEQ_TYPE_SPEED) {
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- }
- }
- if (seq->type == SEQ_TYPE_META) {
- BKE_sequencer_free_imbuf(scene, &seq->seqbase, for_render);
- }
- if (seq->type == SEQ_TYPE_SCENE) {
- /* FIXME: recurse downwards,
- * but do recurse protection somehow! */
- }
- }
-}
-
-static bool update_changed_seq_recurs(
- Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
-{
- Sequence *subseq;
- bool free_imbuf = false;
-
- /* recurse downwards to see if this seq depends on the changed seq */
-
- if (seq == NULL) {
- return false;
- }
-
- if (seq == changed_seq) {
- free_imbuf = true;
- }
-
- for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) {
- if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
-
- if (seq->seq1) {
- if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
- if (seq->seq2 && (seq->seq2 != seq->seq1)) {
- if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
- if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) {
- if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
-
- if (free_imbuf) {
- if (ibuf_change) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- BKE_sequence_free_anim(seq);
- }
- else if (seq->type == SEQ_TYPE_SPEED) {
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- }
- }
-
- if (len_change) {
- BKE_sequence_calc(scene, seq);
- }
- }
-
- return free_imbuf;
-}
-
-void BKE_sequencer_update_changed_seq_and_deps(Scene *scene,
- Sequence *changed_seq,
- int len_change,
- int ibuf_change)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
-
- if (ed == NULL) {
- return;
- }
-
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
- }
-}
-
-/* seq funcs's for transforming internally
- * notice the difference between start/end and left/right.
- *
- * left and right are the bounds at which the sequence is rendered,
- * start and end are from the start and fixed length of the sequence.
- */
-static int seq_tx_get_start(Sequence *seq)
-{
- return seq->start;
-}
-static int seq_tx_get_end(Sequence *seq)
-{
- return seq->start + seq->len;
-}
-
-int BKE_sequence_tx_get_final_left(Sequence *seq, bool metaclip)
-{
- if (metaclip && seq->tmp) {
- /* return the range clipped by the parents range */
- return max_ii(BKE_sequence_tx_get_final_left(seq, false),
- BKE_sequence_tx_get_final_left((Sequence *)seq->tmp, true));
- }
-
- return (seq->start - seq->startstill) + seq->startofs;
-}
-int BKE_sequence_tx_get_final_right(Sequence *seq, bool metaclip)
-{
- if (metaclip && seq->tmp) {
- /* return the range clipped by the parents range */
- return min_ii(BKE_sequence_tx_get_final_right(seq, false),
- BKE_sequence_tx_get_final_right((Sequence *)seq->tmp, true));
- }
-
- return ((seq->start + seq->len) + seq->endstill) - seq->endofs;
-}
-
-void BKE_sequence_tx_set_final_left(Sequence *seq, int val)
-{
- if (val < (seq)->start) {
- seq->startstill = abs(val - (seq)->start);
- seq->startofs = 0;
- }
- else {
- seq->startofs = abs(val - (seq)->start);
- seq->startstill = 0;
- }
-}
-
-void BKE_sequence_tx_set_final_right(Sequence *seq, int val)
-{
- if (val > (seq)->start + (seq)->len) {
- seq->endstill = abs(val - (seq->start + (seq)->len));
- seq->endofs = 0;
- }
- else {
- seq->endofs = abs(val - ((seq)->start + (seq)->len));
- seq->endstill = 0;
- }
-}
-
-/* used so we can do a quick check for single image seq
- * since they work a bit differently to normal image seq's (during transform) */
-bool BKE_sequence_single_check(Sequence *seq)
-{
- return ((seq->len == 1) &&
- (seq->type == SEQ_TYPE_IMAGE ||
- ((seq->type & SEQ_TYPE_EFFECT) && BKE_sequence_effect_get_num_inputs(seq->type) == 0)));
-}
-
-/* check if the selected seq's reference unselected seq's */
-bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase)
-{
- Sequence *seq;
- /* is there more than 1 select */
- bool ok = false;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (seq->flag & SELECT) {
- ok = true;
- break;
- }
- }
-
- if (ok == false) {
- return false;
- }
-
- /* test relationships */
- for (seq = seqbase->first; seq; seq = seq->next) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
- continue;
- }
-
- if (seq->flag & SELECT) {
- if ((seq->seq1 && (seq->seq1->flag & SELECT) == 0) ||
- (seq->seq2 && (seq->seq2->flag & SELECT) == 0) ||
- (seq->seq3 && (seq->seq3->flag & SELECT) == 0)) {
- return false;
- }
- }
- else {
- if ((seq->seq1 && (seq->seq1->flag & SELECT)) || (seq->seq2 && (seq->seq2->flag & SELECT)) ||
- (seq->seq3 && (seq->seq3->flag & SELECT))) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-/* use to impose limits when dragging/extending - so impossible situations don't happen
- * Cant use the SEQ_LEFTSEL and SEQ_LEFTSEL directly because the strip may be in a metastrip */
-void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
-{
- if (leftflag) {
- if (BKE_sequence_tx_get_final_left(seq, false) >=
- BKE_sequence_tx_get_final_right(seq, false)) {
- BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_right(seq, false) - 1);
- }
-
- if (BKE_sequence_single_check(seq) == 0) {
- if (BKE_sequence_tx_get_final_left(seq, false) >= seq_tx_get_end(seq)) {
- BKE_sequence_tx_set_final_left(seq, seq_tx_get_end(seq) - 1);
- }
-
- /* doesn't work now - TODO */
-#if 0
- if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
- int ofs;
- ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
- seq->start -= ofs;
- seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs);
- }
-#endif
- }
- }
-
- if (rightflag) {
- if (BKE_sequence_tx_get_final_right(seq, false) <=
- BKE_sequence_tx_get_final_left(seq, false)) {
- BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + 1);
- }
-
- if (BKE_sequence_single_check(seq) == 0) {
- if (BKE_sequence_tx_get_final_right(seq, false) <= seq_tx_get_start(seq)) {
- BKE_sequence_tx_set_final_right(seq, seq_tx_get_start(seq) + 1);
- }
- }
- }
-
- /* sounds cannot be extended past their endpoints */
- if (seq->type == SEQ_TYPE_SOUND_RAM) {
- seq->startstill = 0;
- seq->endstill = 0;
- }
-}
-
-void BKE_sequence_single_fix(Sequence *seq)
-{
- int left, start, offset;
- if (!BKE_sequence_single_check(seq)) {
- return;
- }
-
- /* make sure the image is always at the start since there is only one,
- * adjusting its start should be ok */
- left = BKE_sequence_tx_get_final_left(seq, false);
- start = seq->start;
- if (start != left) {
- offset = left - start;
- BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_left(seq, false) - offset);
- BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_right(seq, false) - offset);
- seq->start += offset;
- }
-}
-
-bool BKE_sequence_tx_test(Sequence *seq)
-{
- return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0);
-}
-
-/**
- * Return \a true if given \a seq needs a complete cleanup of its cache when it is transformed.
- *
- * Some (effect) strip types need a complete recache of themselves when they are transformed,
- * because they do not 'contain' anything and do not have any explicit relations to other strips.
- */
-bool BKE_sequence_tx_fullupdate_test(Sequence *seq)
-{
- return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM);
-}
-
-static bool seq_overlap(Sequence *seq1, Sequence *seq2)
-{
- return (seq1 != seq2 && seq1->machine == seq2->machine &&
- ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
-}
-
-bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test)
-{
- Sequence *seq;
-
- seq = seqbasep->first;
- while (seq) {
- if (seq_overlap(test, seq)) {
- return true;
- }
-
- seq = seq->next;
- }
- return false;
-}
-
-void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta)
-{
- if (delta == 0) {
- return;
- }
-
- BKE_sequencer_offset_animdata(evil_scene, seq, delta);
- seq->start += delta;
-
- if (seq->type == SEQ_TYPE_META) {
- Sequence *seq_child;
- for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
- BKE_sequence_translate(evil_scene, seq_child, delta);
- }
- }
-
- BKE_sequence_calc_disp(evil_scene, seq);
-}
-
-void BKE_sequence_sound_init(Scene *scene, Sequence *seq)
-{
- if (seq->type == SEQ_TYPE_META) {
- Sequence *seq_child;
- for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
- BKE_sequence_sound_init(scene, seq_child);
- }
- }
- else {
- if (seq->sound) {
- seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
- }
- if (seq->scene) {
- seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
- }
- }
-}
-
-const Sequence *BKE_sequencer_foreground_frame_get(const Scene *scene, int frame)
-{
- const Editing *ed = scene->ed;
- const Sequence *seq, *best_seq = NULL;
- int best_machine = -1;
-
- if (!ed) {
- return NULL;
- }
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) {
- continue;
- }
- /* Only use strips that generate an image, not ones that combine
- * other strips or apply some effect. */
- if (ELEM(seq->type,
- SEQ_TYPE_IMAGE,
- SEQ_TYPE_META,
- SEQ_TYPE_SCENE,
- SEQ_TYPE_MOVIE,
- SEQ_TYPE_COLOR,
- SEQ_TYPE_TEXT)) {
- if (seq->machine > best_machine) {
- best_seq = seq;
- best_machine = seq->machine;
- }
- }
- }
- return best_seq;
-}
-
-/* return 0 if there weren't enough space */
-bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep,
- Sequence *test,
- Scene *evil_scene,
- int channel_delta)
-{
- const int orig_machine = test->machine;
- BLI_assert(ELEM(channel_delta, -1, 1));
-
- test->machine += channel_delta;
- BKE_sequence_calc(evil_scene, test);
- while (BKE_sequence_test_overlap(seqbasep, test)) {
- if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
- break;
- }
-
- test->machine += channel_delta;
- BKE_sequence_calc(
- evil_scene,
- test); // XXX - I don't think this is needed since were only moving vertically, Campbell.
- }
-
- if ((test->machine < 1) || (test->machine > MAXSEQ)) {
- /* Blender 2.4x would remove the strip.
- * nicer to move it to the end */
-
- Sequence *seq;
- int new_frame = test->enddisp;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->machine == orig_machine) {
- new_frame = max_ii(new_frame, seq->enddisp);
- }
- }
-
- test->machine = orig_machine;
- new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
- BKE_sequence_translate(evil_scene, test, new_frame - test->start);
-
- BKE_sequence_calc(evil_scene, test);
- return false;
- }
-
- return true;
-}
-
-bool BKE_sequence_base_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
-{
- return BKE_sequence_base_shuffle_ex(seqbasep, test, evil_scene, 1);
-}
-
-static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir)
-{
- int offset = 0;
- Sequence *seq, *seq_other;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
- if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
- if (dir == 'L') {
- offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
- }
- else {
- offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
- }
- }
- }
- }
- }
- return offset;
-}
-
-static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
-{
- int ofs = 0;
- int tot_ofs = 0;
- Sequence *seq;
- while ((ofs = shuffle_seq_time_offset_test(seqbasep, dir))) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- /* seq_test_overlap only tests display values */
- seq->startdisp += ofs;
- seq->enddisp += ofs;
- }
- }
-
- tot_ofs += ofs;
- }
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- BKE_sequence_calc_disp(scene, seq); /* corrects dummy startdisp/enddisp values */
- }
- }
-
- return tot_ofs;
-}
-
-bool BKE_sequence_base_shuffle_time(ListBase *seqbasep,
- Scene *evil_scene,
- ListBase *markers,
- const bool use_sync_markers)
-{
- /* note: seq->tmp is used to tag strips to move */
-
- Sequence *seq;
-
- int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
- int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
- int offset = (-offset_l < offset_r) ? offset_l : offset_r;
-
- if (offset) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- BKE_sequence_translate(evil_scene, seq, offset);
- seq->flag &= ~SEQ_OVERLAP;
- }
- }
-
- if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
- TimeMarker *marker;
- /* affect selected markers - it's unlikely that we will want to affect all in this way? */
- for (marker = markers->first; marker; marker = marker->next) {
- if (marker->flag & SELECT) {
- marker->frame += offset;
- }
- }
- }
- }
-
- return offset ? false : true;
-}
-
-/* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */
-#ifdef WITH_AUDASPACE
-static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, ListBase *seqbase)
-{
- Sequence *seq;
- bool changed = false;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) {
- BKE_sequence_calc(scene, seq);
- changed = true;
- }
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
- const float length = BKE_sound_get_length(bmain, seq->sound);
- int old = seq->len;
- float fac;
-
- seq->len = (int)ceil((double)length * FPS);
- fac = (float)seq->len / (float)old;
- old = seq->startofs;
- seq->startofs *= fac;
- seq->endofs *= fac;
- seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
-
- BKE_sequence_calc(scene, seq);
- changed = true;
- }
- }
- return changed;
-}
-#endif
-
-void BKE_sequencer_refresh_sound_length(Main *bmain, Scene *scene)
-{
-#ifdef WITH_AUDASPACE
- if (scene->ed) {
- sequencer_refresh_sound_length_recursive(bmain, scene, &scene->ed->seqbase);
- }
-#else
- UNUSED_VARS(bmain, scene);
-#endif
-}
-
-void BKE_sequencer_update_sound_bounds_all(Scene *scene)
-{
- Editing *ed = scene->ed;
-
- if (ed) {
- Sequence *seq;
-
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- BKE_sequencer_update_sound_bounds(scene, seq);
- }
- }
- }
-}
-
-void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq)
-{
- if (seq->type == SEQ_TYPE_SCENE) {
- if (seq->scene && seq->scene_sound) {
- /* We have to take into account start frame of the sequence's scene! */
- int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
-
- BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
- }
- }
- else {
- BKE_sound_move_scene_sound_defaults(scene, seq);
- }
- /* mute is set in seq_update_muting_recursive */
-}
-
-static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute)
-{
- Sequence *seq;
- int seqmute;
-
- /* for sound we go over full meta tree to update muted state,
- * since sound is played outside of evaluating the imbufs, */
- for (seq = seqbasep->first; seq; seq = seq->next) {
- seqmute = (mute || (seq->flag & SEQ_MUTE));
-
- if (seq->type == SEQ_TYPE_META) {
- /* if this is the current meta sequence, unmute because
- * all sequences above this were set to mute */
- if (seq == metaseq) {
- seqmute = 0;
- }
-
- seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- if (seq->scene_sound) {
- BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
- }
- }
- }
-}
-
-void BKE_sequencer_update_muting(Editing *ed)
-{
- if (ed) {
- /* mute all sounds up to current metastack list */
- MetaStack *ms = ed->metastack.last;
-
- if (ms) {
- seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
- }
- else {
- seq_update_muting_recursive(&ed->seqbase, NULL, 0);
- }
- }
-}
-
-static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound *sound)
-{
- Sequence *seq;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_recursive(scene, &seq->seqbase, sound);
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->scene_sound && sound == seq->sound) {
- BKE_sound_update_scene_sound(seq->scene_sound, sound);
- }
- }
- }
-}
-
-void BKE_sequencer_update_sound(Scene *scene, bSound *sound)
-{
- if (scene->ed) {
- seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
- }
-}
-
-/* in cases where we done know the sequence's listbase */
-ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq)
-{
- Sequence *iseq;
- ListBase *lb = NULL;
-
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (seq == iseq) {
- return seqbase;
- }
- if (iseq->seqbase.first && (lb = BKE_sequence_seqbase(&iseq->seqbase, seq))) {
- return lb;
- }
- }
-
- return NULL;
-}
-
-Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *seq)
-{
- Sequence *iseq;
-
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- Sequence *rval;
-
- if (seq == iseq) {
- return meta;
- }
- if (iseq->seqbase.first && (rval = BKE_sequence_metastrip(&iseq->seqbase, iseq, seq))) {
- return rval;
- }
- }
-
- return NULL;
-}
-
-int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
-{
- char name[sizeof(seq_a->name)];
-
- if (seq_a->len != seq_b->len) {
- *error_str = N_("Strips must be the same length");
- return 0;
- }
-
- /* type checking, could be more advanced but disallow sound vs non-sound copy */
- if (seq_a->type != seq_b->type) {
- if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) {
- *error_str = N_("Strips were not compatible");
- return 0;
- }
-
- /* disallow effects to swap with non-effects strips */
- if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) {
- *error_str = N_("Strips were not compatible");
- return 0;
- }
-
- if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) {
- if (BKE_sequence_effect_get_num_inputs(seq_a->type) !=
- BKE_sequence_effect_get_num_inputs(seq_b->type)) {
- *error_str = N_("Strips must have the same number of inputs");
- return 0;
- }
- }
- }
-
- SWAP(Sequence, *seq_a, *seq_b);
-
- /* swap back names so animation fcurves don't get swapped */
- BLI_strncpy(name, seq_a->name + 2, sizeof(name));
- BLI_strncpy(seq_a->name + 2, seq_b->name + 2, sizeof(seq_b->name) - 2);
- BLI_strncpy(seq_b->name + 2, name, sizeof(seq_b->name) - 2);
-
- /* swap back opacity, and overlay mode */
- SWAP(int, seq_a->blend_mode, seq_b->blend_mode);
- SWAP(float, seq_a->blend_opacity, seq_b->blend_opacity);
-
- SWAP(Sequence *, seq_a->prev, seq_b->prev);
- SWAP(Sequence *, seq_a->next, seq_b->next);
- SWAP(int, seq_a->start, seq_b->start);
- SWAP(int, seq_a->startofs, seq_b->startofs);
- SWAP(int, seq_a->endofs, seq_b->endofs);
- SWAP(int, seq_a->startstill, seq_b->startstill);
- SWAP(int, seq_a->endstill, seq_b->endstill);
- SWAP(int, seq_a->machine, seq_b->machine);
- SWAP(int, seq_a->startdisp, seq_b->startdisp);
- SWAP(int, seq_a->enddisp, seq_b->enddisp);
-
- return 1;
-}
-
-/* r_prefix + [" + escaped_name + "] + \0 */
-#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
-
-static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
-{
- char name_esc[SEQ_NAME_MAXSTR * 2];
-
- BLI_strescape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf_rlen(
- str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
-}
-
-/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
-void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
-{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- unsigned int i;
- if (fcu->bezt) {
- for (i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
- bezt->vec[0][0] += ofs;
- bezt->vec[1][0] += ofs;
- bezt->vec[2][0] += ofs;
- }
- }
- if (fcu->fpt) {
- for (i = 0; i < fcu->totvert; i++) {
- FPoint *fpt = &fcu->fpt[i];
- fpt->vec[0] += ofs;
- }
- }
- }
- }
-
- DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
-}
-
-void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
-{
- char str_from[SEQ_RNAPATH_MAXSTR];
- size_t str_from_len;
- FCurve *fcu;
- FCurve *fcu_last;
- FCurve *fcu_cpy;
- ListBase lb = {NULL, NULL};
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_from_len = sequencer_rna_path_prefix(str_from, name_src);
-
- fcu_last = scene->adt->action->curves.last;
-
- for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = BKE_fcurve_copy(fcu);
- BLI_addtail(&lb, fcu_cpy);
- }
- }
-
- /* notice validate is 0, keep this because the seq may not be added to the scene yet */
- BKE_animdata_fix_paths_rename(
- &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
-
- /* add the original fcurves back */
- BLI_movelisttolist(&scene->adt->action->curves, &lb);
-}
-
-/* XXX - hackish function needed to remove all fcurves belonging to a sequencer strip */
-static void seq_free_animdata(Scene *scene, Sequence *seq)
-{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- fcu = scene->adt->action->curves.first;
-
- while (fcu) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- FCurve *next_fcu = fcu->next;
-
- BLI_remlink(&scene->adt->action->curves, fcu);
- BKE_fcurve_free(fcu);
-
- fcu = next_fcu;
- }
- else {
- fcu = fcu->next;
- }
- }
-}
-
-#undef SEQ_RNAPATH_MAXSTR
-
-Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool recursive)
-{
- Sequence *iseq = NULL;
- Sequence *rseq = NULL;
-
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (STREQ(name, iseq->name + 2)) {
- return iseq;
- }
- if (recursive && (iseq->seqbase.first) &&
- (rseq = BKE_sequence_get_by_name(&iseq->seqbase, name, 1))) {
- return rseq;
- }
- }
-
- return NULL;
-}
-
-/**
- * Only use as last resort when the StripElem is available but no the Sequence.
- * (needed for RNA)
- */
-Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se)
-{
- Sequence *iseq;
-
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- Sequence *seq_found;
- if ((iseq->strip && iseq->strip->stripdata) &&
- (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))) {
- break;
- }
- if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) {
- iseq = seq_found;
- break;
- }
- }
-
- return iseq;
-}
-
-Sequence *BKE_sequencer_active_get(Scene *scene)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- if (ed == NULL) {
- return NULL;
- }
-
- return ed->act_seq;
-}
-
-void BKE_sequencer_active_set(Scene *scene, Sequence *seq)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- if (ed == NULL) {
- return;
- }
-
- ed->act_seq = seq;
-}
-
-int BKE_sequencer_active_get_pair(Scene *scene, Sequence **seq_act, Sequence **seq_other)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- *seq_act = BKE_sequencer_active_get(scene);
-
- if (*seq_act == NULL) {
- return 0;
- }
-
- Sequence *seq;
-
- *seq_other = NULL;
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT && (seq != (*seq_act))) {
- if (*seq_other) {
- return 0;
- }
-
- *seq_other = seq;
- }
- }
-
- return (*seq_other != NULL);
-}
-
-Mask *BKE_sequencer_mask_get(Scene *scene)
-{
- Sequence *seq_act = BKE_sequencer_active_get(scene);
-
- if (seq_act && seq_act->type == SEQ_TYPE_MASK) {
- return seq_act->mask;
- }
-
- return NULL;
-}
-
-/* api like funcs for adding */
-
-static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
-{
- if (seq) {
- BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
- BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
-
- if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) {
- seq_load->start_frame += (seq->enddisp - seq->startdisp);
- }
-
- if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) {
- seq_load->flag |= SELECT;
- BKE_sequencer_active_set(scene, seq);
- }
-
- if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
- seq->sound->flags |= SOUND_FLAGS_MONO;
- BKE_sound_load(bmain, seq->sound);
- }
-
- if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
- if (seq->sound) {
- seq->sound->flags |= SOUND_FLAGS_CACHING;
- }
+ if (seq->seq1 && seq->seq1->tmp) {
+ seq->seq1 = seq->seq1->tmp;
}
-
- seq_load->tot_success++;
- }
- else {
- seq_load->tot_error++;
- }
-}
-
-static Strip *seq_strip_alloc(int type)
-{
- Strip *strip = MEM_callocN(sizeof(Strip), "strip");
-
- if (ELEM(type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) {
- strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
- strip->transform->scale_x = 1;
- strip->transform->scale_y = 1;
- strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
- }
-
- strip->us = 1;
- return strip;
-}
-
-Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type)
-{
- Sequence *seq;
-
- seq = MEM_callocN(sizeof(Sequence), "addseq");
- BLI_addtail(lb, seq);
-
- *((short *)seq->name) = ID_SEQ;
- seq->name[2] = 0;
-
- seq->flag = SELECT;
- seq->start = timeline_frame;
- seq->machine = machine;
- seq->sat = 1.0;
- seq->mul = 1.0;
- seq->blend_opacity = 100.0;
- seq->volume = 1.0f;
- seq->pitch = 1.0f;
- seq->scene_sound = NULL;
- seq->type = type;
-
- seq->strip = seq_strip_alloc(type);
- seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
- seq->cache_flag = SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE;
-
- BKE_sequence_session_uuid_generate(seq);
-
- return seq;
-}
-
-void BKE_sequence_session_uuid_generate(struct Sequence *sequence)
-{
- sequence->runtime.session_uuid = BLI_session_uuid_generate();
-}
-
-void BKE_sequence_alpha_mode_from_extension(Sequence *seq)
-{
- if (seq->strip && seq->strip->stripdata) {
- const char *filename = seq->strip->stripdata->name;
- seq->alpha_mode = BKE_image_alpha_mode_from_extension_ex(filename);
- }
-}
-
-float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
-{
- switch (seq->type) {
- case SEQ_TYPE_MOVIE: {
- seq_open_anim_file(scene, seq, true);
- if (BLI_listbase_is_empty(&seq->anims)) {
- return 0.0f;
- }
- StripAnim *strip_anim = seq->anims.first;
- if (strip_anim->anim == NULL) {
- return 0.0f;
- }
- short frs_sec;
- float frs_sec_base;
- if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
- return (float)frs_sec / frs_sec_base;
- }
- break;
+ if (seq->seq2 && seq->seq2->tmp) {
+ seq->seq2 = seq->seq2->tmp;
}
- case SEQ_TYPE_MOVIECLIP:
- if (seq->clip != NULL) {
- return BKE_movieclip_get_fps(seq->clip);
- }
- break;
- case SEQ_TYPE_SCENE:
- if (seq->scene != NULL) {
- return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
- }
- break;
- }
- return 0.0f;
-}
-
-/* NOTE: this function doesn't fill in image names */
-Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
-{
- Scene *scene = CTX_data_scene(C); /* only for active seq */
- Sequence *seq;
- Strip *strip;
-
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
- /* basic defaults */
- seq->len = seq_load->len ? seq_load->len : 1;
-
- strip = seq->strip;
- strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
- BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
-
- if (seq_load->stereo3d_format) {
- *seq->stereo3d_format = *seq_load->stereo3d_format;
- }
-
- seq->views_format = seq_load->views_format;
- seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
-
- seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
- BKE_sequence_invalidate_cache_composite(scene, seq);
-
- return seq;
-}
-
-#ifdef WITH_AUDASPACE
-Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C); /* only for sound */
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- bSound *sound;
-
- Sequence *seq; /* generic strip vars */
- Strip *strip;
- StripElem *se;
-
- sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
-
- SoundInfo info;
- if (!BKE_sound_info_get(bmain, sound, &info)) {
- BKE_id_free(bmain, sound);
- return NULL;
- }
-
- if (info.specs.channels == SOUND_CHANNELS_INVALID) {
- BKE_id_free(bmain, sound);
- return NULL;
- }
-
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM);
- seq->sound = sound;
- BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2);
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
-
- /* basic defaults */
- /* We add a very small negative offset here, because
- * ceil(132.0) == 133.0, not nice with videos, see T47135. */
- seq->len = (int)ceil((double)info.length * FPS - 1e-4);
- strip = seq->strip;
-
- /* we only need 1 element to store the filename */
- strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
-
- BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
-
- seq->scene_sound = NULL;
-
- BKE_sequence_calc_disp(scene, seq);
-
- /* last active name */
- BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
-
- seq_load_apply(bmain, scene, seq, seq_load);
-
- /* TODO(sergey): Shall we tag here or in the operator? */
- DEG_relations_tag_update(bmain);
-
- return seq;
-}
-#else // WITH_AUDASPACE
-Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
-{
- (void)C;
- (void)seqbasep;
- (void)seq_load;
- return NULL;
-}
-#endif // WITH_AUDASPACE
-
-static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
-{
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
- IMB_suffix_anim(anim, suffix);
-}
-
-Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C); /* only for sound */
- char path[sizeof(seq_load->path)];
-
- Sequence *seq; /* generic strip vars */
- Strip *strip;
- StripElem *se;
- char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
- bool is_multiview_loaded = false;
- const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
- const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
- struct anim **anim_arr;
- int i;
-
- BLI_strncpy(path, seq_load->path, sizeof(path));
- BLI_path_abs(path, BKE_main_blendfile_path(bmain));
-
- anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
-
- if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- char prefix[FILE_MAX];
- const char *ext = NULL;
- size_t j = 0;
-
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
-
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- char str[FILE_MAX];
-
- seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
- anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
-
- if (anim_arr[j]) {
- seq_anim_add_suffix(scene, anim_arr[j], i);
- j++;
- }
- }
-
- if (j == 0) {
- MEM_freeN(anim_arr);
- return NULL;
- }
- is_multiview_loaded = true;
+ if (seq->seq3 && seq->seq3->tmp) {
+ seq->seq3 = seq->seq3->tmp;
}
}
-
- if (is_multiview_loaded == false) {
- anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
-
- if (anim_arr[0] == NULL) {
- MEM_freeN(anim_arr);
- return NULL;
+ else if (seq->type == SEQ_TYPE_META) {
+ Sequence *seqn;
+ for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
+ seq_new_fix_links_recursive(seqn);
}
}
- if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
- seq_load->channel++;
- }
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE);
-
- /* multiview settings */
- if (seq_load->stereo3d_format) {
- *seq->stereo3d_format = *seq_load->stereo3d_format;
- seq->views_format = seq_load->views_format;
- }
- seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
-
- seq->type = SEQ_TYPE_MOVIE;
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
- for (i = 0; i < totfiles; i++) {
- if (anim_arr[i]) {
- StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim_arr[i];
- }
- else {
- break;
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence && smd->mask_sequence->tmp) {
+ smd->mask_sequence = smd->mask_sequence->tmp;
}
}
-
- IMB_anim_load_metadata(anim_arr[0]);
-
- seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
- BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
-
- /* adjust scene's frame rate settings to match */
- if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
- IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
- }
-
- /* basic defaults */
- seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
- strip = seq->strip;
-
- BLI_strncpy(seq->strip->colorspace_settings.name,
- colorspace,
- sizeof(seq->strip->colorspace_settings.name));
-
- /* we only need 1 element for MOVIE strips */
- strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
-
- BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
-
- BKE_sequence_calc_disp(scene, seq);
-
- if (seq_load->name[0] == '\0') {
- BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name));
- }
-
- if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
- int start_frame_back = seq_load->start_frame;
- seq_load->channel--;
- seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
- seq_load->start_frame = start_frame_back;
- }
-
- /* can be NULL */
- seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
- BKE_sequence_invalidate_cache_composite(scene, seq);
-
- MEM_freeN(anim_arr);
- return seq;
}
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Duplicate functions
+ * \{ */
static Sequence *seq_dupli(const Scene *scene_src,
Scene *scene_dst,
ListBase *new_seq_list,
@@ -2936,35 +419,6 @@ static Sequence *seq_dupli(const Scene *scene_src,
return seqn;
}
-static void seq_new_fix_links_recursive(Sequence *seq)
-{
- SequenceModifierData *smd;
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->tmp) {
- seq->seq1 = seq->seq1->tmp;
- }
- if (seq->seq2 && seq->seq2->tmp) {
- seq->seq2 = seq->seq2->tmp;
- }
- if (seq->seq3 && seq->seq3->tmp) {
- seq->seq3 = seq->seq3->tmp;
- }
- }
- else if (seq->type == SEQ_TYPE_META) {
- Sequence *seqn;
- for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
- seq_new_fix_links_recursive(seqn);
- }
- }
-
- for (smd = seq->modifiers.first; smd; smd = smd->next) {
- if (smd->mask_sequence && smd->mask_sequence->tmp) {
- smd->mask_sequence = smd->mask_sequence->tmp;
- }
- }
-}
-
static Sequence *sequence_dupli_recursive_do(const Scene *scene_src,
Scene *scene_dst,
ListBase *new_seq_list,
@@ -3044,297 +498,115 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
seq_new_fix_links_recursive(seq);
}
}
+/* r_prefix + [" + escaped_name + "] + \0 */
+#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
-/* called on draw, needs to be fast,
- * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
-bool BKE_sequence_is_valid_check(Sequence *seq)
+static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
{
- switch (seq->type) {
- case SEQ_TYPE_MASK:
- return (seq->mask != NULL);
- case SEQ_TYPE_MOVIECLIP:
- return (seq->clip != NULL);
- case SEQ_TYPE_SCENE:
- return (seq->scene != NULL);
- case SEQ_TYPE_SOUND_RAM:
- return (seq->sound != NULL);
- }
+ char name_esc[SEQ_NAME_MAXSTR * 2];
- return true;
+ BLI_strescape(name_esc, name, sizeof(name_esc));
+ return BLI_snprintf_rlen(
+ str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
-int BKE_sequencer_find_next_prev_edit(Scene *scene,
- int timeline_frame,
- const short side,
- const bool do_skip_mute,
- const bool do_center,
- const bool do_unselected)
+/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
+void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
-
- int dist, best_dist, best_frame = timeline_frame;
- int seq_frames[2], seq_frames_tot;
-
- /* In case where both is passed,
- * frame just finds the nearest end while frame_left the nearest start. */
-
- best_dist = MAXFRAME * 2;
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
+ FCurve *fcu;
- if (ed == NULL) {
- return timeline_frame;
+ if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) {
+ return;
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- int i;
-
- if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
- continue;
- }
-
- if (do_unselected && (seq->flag & SELECT)) {
- continue;
- }
-
- if (do_center) {
- seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
- seq_frames_tot = 1;
- }
- else {
- seq_frames[0] = seq->startdisp;
- seq_frames[1] = seq->enddisp;
-
- seq_frames_tot = 2;
- }
-
- for (i = 0; i < seq_frames_tot; i++) {
- const int seq_frame = seq_frames[i];
-
- dist = MAXFRAME * 2;
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
- switch (side) {
- case SEQ_SIDE_LEFT:
- if (seq_frame < timeline_frame) {
- dist = timeline_frame - seq_frame;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (seq_frame > timeline_frame) {
- dist = seq_frame - timeline_frame;
- }
- break;
- case SEQ_SIDE_BOTH:
- dist = abs(seq_frame - timeline_frame);
- break;
+ for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
+ unsigned int i;
+ if (fcu->bezt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][0] += ofs;
+ bezt->vec[1][0] += ofs;
+ bezt->vec[2][0] += ofs;
+ }
}
-
- if (dist < best_dist) {
- best_frame = seq_frame;
- best_dist = dist;
+ if (fcu->fpt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ FPoint *fpt = &fcu->fpt[i];
+ fpt->vec[0] += ofs;
+ }
}
}
}
- return best_frame;
+ DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
}
-static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame)
+void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
{
- for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (seq->enddisp < timeline_frame || seq->startdisp > timeline_frame) {
- BKE_sequence_free_anim(seq);
- }
- if (seq->type == SEQ_TYPE_META) {
- sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame);
- }
- }
-}
+ char str_from[SEQ_RNAPATH_MAXSTR];
+ size_t str_from_len;
+ FCurve *fcu;
+ FCurve *fcu_last;
+ FCurve *fcu_cpy;
+ ListBase lb = {NULL, NULL};
-void BKE_sequencer_all_free_anim_ibufs(Scene *scene, int timeline_frame)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- if (ed == NULL) {
+ if (scene->adt == NULL || scene->adt->action == NULL) {
return;
}
- sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame);
- BKE_sequencer_cache_cleanup(scene);
-}
-
-static bool sequencer_seq_generates_image(Sequence *seq)
-{
- switch (seq->type) {
- case SEQ_TYPE_IMAGE:
- case SEQ_TYPE_SCENE:
- case SEQ_TYPE_MOVIE:
- case SEQ_TYPE_MOVIECLIP:
- case SEQ_TYPE_MASK:
- case SEQ_TYPE_COLOR:
- case SEQ_TYPE_TEXT:
- return true;
- }
- return false;
-}
-static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
-{
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (seq->type == SEQ_TYPE_SCENE && seq->scene == scene) {
- return seq;
- }
-
- if (seq->type == SEQ_TYPE_SCENE && (seq->flag & SEQ_SCENE_STRIPS)) {
- if (sequencer_check_scene_recursion(scene, &seq->scene->ed->seqbase)) {
- return seq;
- }
- }
-
- if (seq->type == SEQ_TYPE_META && sequencer_check_scene_recursion(scene, &seq->seqbase)) {
- return seq;
- }
- }
-
- return NULL;
-}
-
-bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- if (ed == NULL) {
- return false;
- }
-
- Sequence *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
+ str_from_len = sequencer_rna_path_prefix(str_from, name_src);
- if (recursive_seq != NULL) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
- recursive_seq->name + 2,
- recursive_seq->startdisp);
+ fcu_last = scene->adt->action->curves.last;
- LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
- if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
- /* There are other strips to render, so render them. */
- return false;
- }
+ for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
+ if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
+ fcu_cpy = BKE_fcurve_copy(fcu);
+ BLI_addtail(&lb, fcu_cpy);
}
- /* No other strips to render - cancel operator. */
- return true;
}
- return false;
-}
-
-/* Check if "seq_main" (indirectly) uses strip "seq". */
-bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq)
-{
- if (seq_main == NULL || seq == NULL) {
- return false;
- }
-
- if (seq_main == seq) {
- return true;
- }
-
- if ((seq_main->seq1 && BKE_sequencer_render_loop_check(seq_main->seq1, seq)) ||
- (seq_main->seq2 && BKE_sequencer_render_loop_check(seq_main->seq2, seq)) ||
- (seq_main->seq3 && BKE_sequencer_render_loop_check(seq_main->seq3, seq))) {
- return true;
- }
-
- SequenceModifierData *smd;
- for (smd = seq_main->modifiers.first; smd; smd = smd->next) {
- if (smd->mask_sequence && BKE_sequencer_render_loop_check(smd->mask_sequence, seq)) {
- return true;
- }
- }
+ /* notice validate is 0, keep this because the seq may not be added to the scene yet */
+ BKE_animdata_fix_paths_rename(
+ &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
- return false;
+ /* add the original fcurves back */
+ BLI_movelisttolist(&scene->adt->action->curves, &lb);
}
-static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
+/* XXX - hackish function needed to remove all fcurves belonging to a sequencer strip */
+static void seq_free_animdata(Scene *scene, Sequence *seq)
{
- LISTBASE_FOREACH (Sequence *, user_seq, seqbase) {
- /* Look in metas for usage of seq. */
- if (user_seq->type == SEQ_TYPE_META) {
- sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq);
- }
-
- /* Clear seq from modifiers. */
- SequenceModifierData *smd;
- for (smd = user_seq->modifiers.first; smd; smd = smd->next) {
- if (smd->mask_sequence == seq) {
- smd->mask_sequence = NULL;
- }
- }
-
- /* Remove effects, that use seq. */
- if ((user_seq->seq1 && user_seq->seq1 == seq) || (user_seq->seq2 && user_seq->seq2 == seq) ||
- (user_seq->seq3 && user_seq->seq3 == seq)) {
- user_seq->flag |= SEQ_FLAG_DELETE;
- /* Strips can be used as mask even if not in same seqbase. */
- sequencer_flag_users_for_removal(scene, &scene->ed->seqbase, user_seq);
- }
- }
-}
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
+ FCurve *fcu;
-/* Flag seq and its users (effects) for removal. */
-void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
-{
- if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
+ if (scene->adt == NULL || scene->adt->action == NULL) {
return;
}
- /* Flag and remove meta children. */
- if (seq->type == SEQ_TYPE_META) {
- LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
- BKE_sequencer_flag_for_removal(scene, &seq->seqbase, meta_child);
- }
- }
-
- seq->flag |= SEQ_FLAG_DELETE;
- sequencer_flag_users_for_removal(scene, seqbase, seq);
-}
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-/* Remove all flagged sequences, return true if sequence is removed. */
-void BKE_sequencer_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
-{
- LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
- if (seq->flag & SEQ_FLAG_DELETE) {
- if (seq->type == SEQ_TYPE_META) {
- BKE_sequencer_remove_flagged_sequences(scene, &seq->seqbase);
- }
- BLI_remlink(seqbase, seq);
- BKE_sequence_free(scene, seq, true);
- }
- }
-}
+ fcu = scene->adt->action->curves.first;
-void BKE_sequencer_check_uuids_unique_and_report(const Scene *scene)
-{
- if (scene->ed == NULL) {
- return;
- }
+ while (fcu) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
+ FCurve *next_fcu = fcu->next;
- struct GSet *used_uuids = BLI_gset_new(
- BLI_session_uuid_ghash_hash, BLI_session_uuid_ghash_compare, "sequencer used uuids");
+ BLI_remlink(&scene->adt->action->curves, fcu);
+ BKE_fcurve_free(fcu);
- const Sequence *sequence;
- SEQ_ALL_BEGIN (scene->ed, sequence) {
- const SessionUUID *session_uuid = &sequence->runtime.session_uuid;
- if (!BLI_session_uuid_is_generated(session_uuid)) {
- printf("Sequence %s does not have UUID generated.\n", sequence->name);
- continue;
+ fcu = next_fcu;
}
-
- if (BLI_gset_lookup(used_uuids, session_uuid) != NULL) {
- printf("Sequence %s has duplicate UUID generated.\n", sequence->name);
- continue;
+ else {
+ fcu = fcu->next;
}
-
- BLI_gset_insert(used_uuids, (void *)session_uuid);
}
- SEQ_ALL_END;
-
- BLI_gset_free(used_uuids, NULL);
}
+
+#undef SEQ_RNAPATH_MAXSTR
+/** \} */
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index 9033d522e9b..928b3edd728 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -27,112 +27,10 @@
extern "C" {
#endif
-struct Editing;
-struct ImBuf;
-struct Main;
-struct Mask;
struct Scene;
struct Sequence;
-struct StripColorBalance;
-struct StripElem;
-#define EARLY_NO_INPUT -1
-#define EARLY_DO_EFFECT 0
-#define EARLY_USE_INPUT_1 1
-#define EARLY_USE_INPUT_2 2
-
-/* **********************************************************************
- * sequencer.c
- *
- * sequencer scene functions
- * ********************************************************************** */
-
-void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
-/* **********************************************************************
- * image_cache.c
- *
- * Sequencer memory cache management functions
- * ********************************************************************** */
-
-struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
- struct Sequence *seq,
- float timeline_frame,
- int type,
- bool skip_disk_cache);
-void BKE_sequencer_cache_put(const SeqRenderData *context,
- struct Sequence *seq,
- float timeline_frame,
- int type,
- struct ImBuf *i,
- float cost,
- bool skip_disk_cache);
-bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
- struct Sequence *seq,
- float timeline_frame,
- int type,
- struct ImBuf *nval,
- float cost,
- bool skip_disk_cache);
-bool BKE_sequencer_cache_recycle_item(struct Scene *scene);
-void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
-void BKE_sequencer_cache_destruct(struct Scene *scene);
-void BKE_sequencer_cache_cleanup_all(struct Main *bmain);
-void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene,
- struct Sequence *seq,
- struct Sequence *seq_changed,
- int invalidate_types,
- bool force_seq_changed_range);
-bool BKE_sequencer_cache_is_full(struct Scene *scene);
-
-/* **********************************************************************
- * prefetch.c
- *
- * Sequencer frame prefetching
- * ********************************************************************** */
-
-void BKE_sequencer_prefetch_start(const SeqRenderData *context, float timeline_frame, float cost);
-void BKE_sequencer_prefetch_free(struct Scene *scene);
-bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene);
-void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
-SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context);
-struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq,
- struct Scene *scene);
-
-/* **********************************************************************
- * seqeffects.c
- *
- * Sequencer effect strip management functions
- * **********************************************************************
- */
-
-struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq);
-void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force);
-float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
- struct Sequence *seq,
- float timeline_frame,
- int input);
-
-/* **********************************************************************
- * sequencer.c
- *
- * Sequencer editing functions
- * **********************************************************************
- */
-
-void BKE_sequence_sound_init(struct Scene *scene, struct Sequence *seq);
-struct Sequence *BKE_sequence_metastrip(ListBase *seqbase /* = ed->seqbase */,
- struct Sequence *meta /* = NULL */,
- struct Sequence *seq);
void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, const bool do_id_user);
-void seq_multiview_name(struct Scene *scene,
- const int view_id,
- const char *prefix,
- const char *ext,
- char *r_path,
- size_t r_size);
-int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview);
-void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
-void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
new file mode 100644
index 00000000000..9549938abee
--- /dev/null
+++ b/source/blender/sequencer/intern/sound.c
@@ -0,0 +1,163 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <math.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "SEQ_sequencer.h"
+
+#include "strip_time.h"
+
+void BKE_sequence_sound_init(Scene *scene, Sequence *seq);
+
+void BKE_sequence_sound_init(Scene *scene, Sequence *seq)
+{
+ if (seq->type == SEQ_TYPE_META) {
+ Sequence *seq_child;
+ for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
+ BKE_sequence_sound_init(scene, seq_child);
+ }
+ }
+ else {
+ if (seq->sound) {
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
+ }
+ if (seq->scene) {
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
+ }
+ }
+}
+
+/* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */
+#ifdef WITH_AUDASPACE
+static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, ListBase *seqbase)
+{
+ Sequence *seq;
+ bool changed = false;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) {
+ BKE_sequence_calc(scene, seq);
+ changed = true;
+ }
+ }
+ else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
+ const float length = BKE_sound_get_length(bmain, seq->sound);
+ int old = seq->len;
+ float fac;
+
+ seq->len = (int)ceil((double)length * FPS);
+ fac = (float)seq->len / (float)old;
+ old = seq->startofs;
+ seq->startofs *= fac;
+ seq->endofs *= fac;
+ seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
+
+ BKE_sequence_calc(scene, seq);
+ changed = true;
+ }
+ }
+ return changed;
+}
+#endif
+
+void BKE_sequencer_refresh_sound_length(Main *bmain, Scene *scene)
+{
+#ifdef WITH_AUDASPACE
+ if (scene->ed) {
+ sequencer_refresh_sound_length_recursive(bmain, scene, &scene->ed->seqbase);
+ }
+#else
+ UNUSED_VARS(bmain, scene);
+#endif
+}
+
+void BKE_sequencer_update_sound_bounds_all(Scene *scene)
+{
+ Editing *ed = scene->ed;
+
+ if (ed) {
+ Sequence *seq;
+
+ for (seq = ed->seqbase.first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ BKE_sequencer_update_sound_bounds(scene, seq);
+ }
+ }
+ }
+}
+
+void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq)
+{
+ if (seq->type == SEQ_TYPE_SCENE) {
+ if (seq->scene && seq->scene_sound) {
+ /* We have to take into account start frame of the sequence's scene! */
+ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
+
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
+ }
+ }
+ else {
+ BKE_sound_move_scene_sound_defaults(scene, seq);
+ }
+ /* mute is set in seq_update_muting_recursive */
+}
+
+static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound *sound)
+{
+ Sequence *seq;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_recursive(scene, &seq->seqbase, sound);
+ }
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->scene_sound && sound == seq->sound) {
+ BKE_sound_update_scene_sound(seq->scene_sound, sound);
+ }
+ }
+ }
+}
+
+void BKE_sequencer_update_sound(Scene *scene, bSound *sound)
+{
+ if (scene->ed) {
+ seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
+ }
+}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
new file mode 100644
index 00000000000..d2e4025bdfc
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -0,0 +1,551 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mask.h"
+#include "BKE_movieclip.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
+
+#include "SEQ_sequencer.h"
+
+#include "multiview.h"
+#include "proxy.h"
+#include "utils.h"
+
+static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
+{
+ if (seq) {
+ BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
+ BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+
+ if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) {
+ seq_load->start_frame += (seq->enddisp - seq->startdisp);
+ }
+
+ if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) {
+ seq_load->flag |= SELECT;
+ BKE_sequencer_active_set(scene, seq);
+ }
+
+ if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
+ seq->sound->flags |= SOUND_FLAGS_MONO;
+ BKE_sound_load(bmain, seq->sound);
+ }
+
+ if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
+ if (seq->sound) {
+ seq->sound->flags |= SOUND_FLAGS_CACHING;
+ }
+ }
+
+ seq_load->tot_success++;
+ }
+ else {
+ seq_load->tot_error++;
+ }
+}
+
+/* NOTE: this function doesn't fill in image names */
+Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
+{
+ Scene *scene = CTX_data_scene(C); /* only for active seq */
+ Sequence *seq;
+ Strip *strip;
+
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+
+ /* basic defaults */
+ seq->len = seq_load->len ? seq_load->len : 1;
+
+ strip = seq->strip;
+ strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
+ BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
+
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ }
+
+ seq->views_format = seq_load->views_format;
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+
+ return seq;
+}
+
+#ifdef WITH_AUDASPACE
+Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C); /* only for sound */
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ bSound *sound;
+
+ Sequence *seq; /* generic strip vars */
+ Strip *strip;
+ StripElem *se;
+
+ sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
+
+ SoundInfo info;
+ if (!BKE_sound_info_get(bmain, sound, &info)) {
+ BKE_id_free(bmain, sound);
+ return NULL;
+ }
+
+ if (info.specs.channels == SOUND_CHANNELS_INVALID) {
+ BKE_id_free(bmain, sound);
+ return NULL;
+ }
+
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM);
+ seq->sound = sound;
+ BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2);
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+
+ /* basic defaults */
+ /* We add a very small negative offset here, because
+ * ceil(132.0) == 133.0, not nice with videos, see T47135. */
+ seq->len = (int)ceil((double)info.length * FPS - 1e-4);
+ strip = seq->strip;
+
+ /* we only need 1 element to store the filename */
+ strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
+
+ BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
+
+ seq->scene_sound = NULL;
+
+ BKE_sequence_calc_disp(scene, seq);
+
+ /* last active name */
+ BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
+
+ seq_load_apply(bmain, scene, seq, seq_load);
+
+ /* TODO(sergey): Shall we tag here or in the operator? */
+ DEG_relations_tag_update(bmain);
+
+ return seq;
+}
+#else // WITH_AUDASPACE
+Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
+{
+ (void)C;
+ (void)seqbasep;
+ (void)seq_load;
+ return NULL;
+}
+#endif // WITH_AUDASPACE
+
+Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C); /* only for sound */
+ char path[sizeof(seq_load->path)];
+
+ Sequence *seq; /* generic strip vars */
+ Strip *strip;
+ StripElem *se;
+ char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
+ const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ struct anim **anim_arr;
+ int i;
+
+ BLI_strncpy(path, seq_load->path, sizeof(path));
+ BLI_path_abs(path, BKE_main_blendfile_path(bmain));
+
+ anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
+
+ if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ size_t j = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
+
+ if (anim_arr[j]) {
+ seq_anim_add_suffix(scene, anim_arr[j], i);
+ j++;
+ }
+ }
+
+ if (j == 0) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
+
+ if (anim_arr[0] == NULL) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ }
+
+ if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
+ seq_load->channel++;
+ }
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE);
+
+ /* multiview settings */
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ seq->views_format = seq_load->views_format;
+ }
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
+ seq->type = SEQ_TYPE_MOVIE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+
+ for (i = 0; i < totfiles; i++) {
+ if (anim_arr[i]) {
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim_arr[i];
+ }
+ else {
+ break;
+ }
+ }
+
+ IMB_anim_load_metadata(anim_arr[0]);
+
+ seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
+ BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+
+ /* adjust scene's frame rate settings to match */
+ if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
+ IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
+ }
+
+ /* basic defaults */
+ seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
+ strip = seq->strip;
+
+ BLI_strncpy(seq->strip->colorspace_settings.name,
+ colorspace,
+ sizeof(seq->strip->colorspace_settings.name));
+
+ /* we only need 1 element for MOVIE strips */
+ strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
+
+ BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
+
+ BKE_sequence_calc_disp(scene, seq);
+
+ if (seq_load->name[0] == '\0') {
+ BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name));
+ }
+
+ if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
+ int start_frame_back = seq_load->start_frame;
+ seq_load->channel--;
+ seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
+ seq_load->start_frame = start_frame_back;
+ }
+
+ /* can be NULL */
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+
+ MEM_freeN(anim_arr);
+ return seq;
+}
+
+/* note: caller should run BKE_sequence_calc(scene, seq) after */
+void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
+{
+ char path[FILE_MAX];
+ int prev_startdisp = 0, prev_enddisp = 0;
+ /* note: don't rename the strip, will break animation curves */
+
+ if (ELEM(seq->type,
+ SEQ_TYPE_MOVIE,
+ SEQ_TYPE_IMAGE,
+ SEQ_TYPE_SOUND_RAM,
+ SEQ_TYPE_SCENE,
+ SEQ_TYPE_META,
+ SEQ_TYPE_MOVIECLIP,
+ SEQ_TYPE_MASK) == 0) {
+ return;
+ }
+
+ if (lock_range) {
+ /* keep so we don't have to move the actual start and end points (only the data) */
+ BKE_sequence_calc_disp(scene, seq);
+ prev_startdisp = seq->startdisp;
+ prev_enddisp = seq->enddisp;
+ }
+
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE: {
+ /* Hack? */
+ size_t olen = MEM_allocN_len(seq->strip->stripdata) / sizeof(StripElem);
+
+ seq->len = olen;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIE: {
+ StripAnim *sanim;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+
+ BKE_sequence_free_anim(seq);
+
+ if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ const int totfiles = seq_num_files(scene, seq->views_format, true);
+ int i = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ struct anim *anim;
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim = openanim(str,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+
+ if (anim) {
+ seq_anim_add_suffix(scene, anim, i);
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ struct anim *anim;
+ anim = openanim(path,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+
+ /* use the first video as reference for everything */
+ sanim = seq->anims.first;
+
+ if ((!sanim) || (!sanim->anim)) {
+ return;
+ }
+
+ IMB_anim_load_metadata(sanim->anim);
+
+ seq->len = IMB_anim_get_duration(
+ sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
+
+ seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
+
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIECLIP:
+ if (seq->clip == NULL) {
+ return;
+ }
+
+ seq->len = BKE_movieclip_get_duration(seq->clip);
+
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ case SEQ_TYPE_MASK:
+ if (seq->mask == NULL) {
+ return;
+ }
+ seq->len = BKE_mask_get_duration(seq->mask);
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ case SEQ_TYPE_SOUND_RAM:
+#ifdef WITH_AUDASPACE
+ if (!seq->sound) {
+ return;
+ }
+ seq->len = ceil((double)BKE_sound_get_length(bmain, seq->sound) * FPS);
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+#else
+ UNUSED_VARS(bmain);
+ return;
+#endif
+ break;
+ case SEQ_TYPE_SCENE: {
+ seq->len = (seq->scene) ? seq->scene->r.efra - seq->scene->r.sfra + 1 : 0;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ }
+
+ free_proxy_seq(seq);
+
+ if (lock_range) {
+ BKE_sequence_tx_set_final_left(seq, prev_startdisp);
+ BKE_sequence_tx_set_final_right(seq, prev_enddisp);
+ BKE_sequence_single_fix(seq);
+ }
+
+ BKE_sequence_calc(scene, seq);
+}
+
+void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
+ struct Scene *scene,
+ struct Sequence *seq,
+ bool *r_was_reloaded,
+ bool *r_can_produce_frames)
+{
+ BLI_assert(seq->type == SEQ_TYPE_MOVIE ||
+ !"This function is only implemented for movie strips.");
+
+ bool must_reload = false;
+
+ /* The Sequence struct allows for multiple anim structs to be associated with one strip. This
+ * function will return true only if there is at least one 'anim' AND all anims can produce
+ * frames. */
+
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ /* No anim present, so reloading is always necessary. */
+ must_reload = true;
+ }
+ else {
+ LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
+ if (!IMB_anim_can_produce_frames(sanim->anim)) {
+ /* Anim cannot produce frames, try reloading. */
+ must_reload = true;
+ break;
+ }
+ };
+ }
+
+ if (!must_reload) {
+ /* There are one or more anims, and all can produce frames. */
+ *r_was_reloaded = false;
+ *r_can_produce_frames = true;
+ return;
+ }
+
+ BKE_sequence_reload_new_file(bmain, scene, seq, true);
+ *r_was_reloaded = true;
+
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ /* No anims present after reloading => no frames can be produced. */
+ *r_can_produce_frames = false;
+ return;
+ }
+
+ /* Check if there are still anims that cannot produce frames. */
+ LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
+ if (!IMB_anim_can_produce_frames(sanim->anim)) {
+ /* There still is an anim that cannot produce frames. */
+ *r_can_produce_frames = false;
+ return;
+ }
+ };
+
+ /* There are one or more anims, and all can produce frames. */
+ *r_can_produce_frames = true;
+}
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
new file mode 100644
index 00000000000..46a4ee0c03f
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -0,0 +1,196 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_movieclip.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "SEQ_sequencer.h"
+
+int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
+{
+ char name[sizeof(seq_a->name)];
+
+ if (seq_a->len != seq_b->len) {
+ *error_str = N_("Strips must be the same length");
+ return 0;
+ }
+
+ /* type checking, could be more advanced but disallow sound vs non-sound copy */
+ if (seq_a->type != seq_b->type) {
+ if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) {
+ *error_str = N_("Strips were not compatible");
+ return 0;
+ }
+
+ /* disallow effects to swap with non-effects strips */
+ if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) {
+ *error_str = N_("Strips were not compatible");
+ return 0;
+ }
+
+ if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) {
+ if (BKE_sequence_effect_get_num_inputs(seq_a->type) !=
+ BKE_sequence_effect_get_num_inputs(seq_b->type)) {
+ *error_str = N_("Strips must have the same number of inputs");
+ return 0;
+ }
+ }
+ }
+
+ SWAP(Sequence, *seq_a, *seq_b);
+
+ /* swap back names so animation fcurves don't get swapped */
+ BLI_strncpy(name, seq_a->name + 2, sizeof(name));
+ BLI_strncpy(seq_a->name + 2, seq_b->name + 2, sizeof(seq_b->name) - 2);
+ BLI_strncpy(seq_b->name + 2, name, sizeof(seq_b->name) - 2);
+
+ /* swap back opacity, and overlay mode */
+ SWAP(int, seq_a->blend_mode, seq_b->blend_mode);
+ SWAP(float, seq_a->blend_opacity, seq_b->blend_opacity);
+
+ SWAP(Sequence *, seq_a->prev, seq_b->prev);
+ SWAP(Sequence *, seq_a->next, seq_b->next);
+ SWAP(int, seq_a->start, seq_b->start);
+ SWAP(int, seq_a->startofs, seq_b->startofs);
+ SWAP(int, seq_a->endofs, seq_b->endofs);
+ SWAP(int, seq_a->startstill, seq_b->startstill);
+ SWAP(int, seq_a->endstill, seq_b->endstill);
+ SWAP(int, seq_a->machine, seq_b->machine);
+ SWAP(int, seq_a->startdisp, seq_b->startdisp);
+ SWAP(int, seq_a->enddisp, seq_b->enddisp);
+
+ return 1;
+}
+
+static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute)
+{
+ Sequence *seq;
+ int seqmute;
+
+ /* for sound we go over full meta tree to update muted state,
+ * since sound is played outside of evaluating the imbufs, */
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ seqmute = (mute || (seq->flag & SEQ_MUTE));
+
+ if (seq->type == SEQ_TYPE_META) {
+ /* if this is the current meta sequence, unmute because
+ * all sequences above this were set to mute */
+ if (seq == metaseq) {
+ seqmute = 0;
+ }
+
+ seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ if (seq->scene_sound) {
+ BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
+ }
+ }
+ }
+}
+
+void BKE_sequencer_update_muting(Editing *ed)
+{
+ if (ed) {
+ /* mute all sounds up to current metastack list */
+ MetaStack *ms = ed->metastack.last;
+
+ if (ms) {
+ seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
+ }
+ else {
+ seq_update_muting_recursive(&ed->seqbase, NULL, 0);
+ }
+ }
+}
+
+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. */
+ if (user_seq->type == SEQ_TYPE_META) {
+ sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq);
+ }
+
+ /* Clear seq from modifiers. */
+ SequenceModifierData *smd;
+ for (smd = user_seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence == seq) {
+ smd->mask_sequence = NULL;
+ }
+ }
+
+ /* Remove effects, that use seq. */
+ if ((user_seq->seq1 && user_seq->seq1 == seq) || (user_seq->seq2 && user_seq->seq2 == seq) ||
+ (user_seq->seq3 && user_seq->seq3 == seq)) {
+ user_seq->flag |= SEQ_FLAG_DELETE;
+ /* Strips can be used as mask even if not in same seqbase. */
+ sequencer_flag_users_for_removal(scene, &scene->ed->seqbase, user_seq);
+ }
+ }
+}
+
+/* Flag seq and its users (effects) for removal. */
+void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
+{
+ if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
+ return;
+ }
+
+ /* Flag and remove meta children. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ BKE_sequencer_flag_for_removal(scene, &seq->seqbase, meta_child);
+ }
+ }
+
+ seq->flag |= SEQ_FLAG_DELETE;
+ sequencer_flag_users_for_removal(scene, seqbase, seq);
+}
+
+/* Remove all flagged sequences, return true if sequence is removed. */
+void BKE_sequencer_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
+{
+ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
+ if (seq->flag & SEQ_FLAG_DELETE) {
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequencer_remove_flagged_sequences(scene, &seq->seqbase);
+ }
+ BLI_remlink(seqbase, seq);
+ BKE_sequence_free(scene, seq, true);
+ }
+ }
+}
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
new file mode 100644
index 00000000000..d802ce22f21
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -0,0 +1,468 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_session_uuid.h"
+
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_imbuf.h"
+
+#include "SEQ_sequencer.h"
+
+#include "effects.h"
+#include "image_cache.h"
+#include "utils.h"
+
+/* check whether sequence cur depends on seq */
+static bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
+{
+ if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq) {
+ return true;
+ }
+
+ /* sequences are not intersecting in time, assume no dependency exists between them */
+ if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp) {
+ return false;
+ }
+
+ /* checking sequence is below reference one, not dependent on it */
+ if (cur->machine < seq->machine) {
+ return false;
+ }
+
+ /* sequence is not blending with lower machines, no dependency here occurs
+ * check for non-effects only since effect could use lower machines as input
+ */
+ if ((cur->type & SEQ_TYPE_EFFECT) == 0 &&
+ ((cur->blend_mode == SEQ_BLEND_REPLACE) ||
+ (cur->blend_mode == SEQ_TYPE_CROSS && cur->blend_opacity == 100.0f))) {
+ return false;
+ }
+
+ return true;
+}
+
+static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBase *seqbase)
+{
+ Sequence *cur;
+
+ for (cur = seqbase->first; cur; cur = cur->next) {
+ if (cur == seq) {
+ continue;
+ }
+
+ if (BKE_sequence_check_depend(seq, cur)) {
+ /* Effect must be invalidated completely if they depend on invalidated seq. */
+ if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
+ BKE_sequencer_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
+ }
+ else {
+ /* In case of alpha over for example only invalidate composite image */
+ BKE_sequencer_cache_cleanup_sequence(
+ scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT, false);
+ }
+ }
+
+ if (cur->seqbase.first) {
+ sequence_do_invalidate_dependent(scene, seq, &cur->seqbase);
+ }
+ }
+}
+
+static void sequence_invalidate_cache(Scene *scene,
+ Sequence *seq,
+ bool invalidate_self,
+ int invalidate_types)
+{
+ Editing *ed = scene->ed;
+
+ if (invalidate_self) {
+ BKE_sequence_free_anim(seq);
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false);
+ }
+
+ if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) {
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ }
+
+ sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ BKE_sequencer_prefetch_stop(scene);
+}
+
+void BKE_sequence_invalidate_cache_in_range(Scene *scene,
+ Sequence *seq,
+ Sequence *range_mask,
+ int invalidate_types)
+{
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
+}
+
+void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
+{
+ sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
+}
+
+void BKE_sequence_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
+{
+ sequence_invalidate_cache(scene,
+ seq,
+ true,
+ SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE |
+ SEQ_CACHE_STORE_FINAL_OUT);
+}
+
+void BKE_sequence_invalidate_cache_composite(Scene *scene, Sequence *seq)
+{
+ if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ return;
+ }
+
+ sequence_invalidate_cache(
+ scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
+}
+
+void BKE_sequence_invalidate_dependent(Scene *scene, Sequence *seq)
+{
+ if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ return;
+ }
+
+ sequence_invalidate_cache(
+ scene, seq, false, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
+}
+
+static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase)
+{
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->scene == scene_target) {
+ BKE_sequence_invalidate_cache_raw(scene, seq);
+ }
+
+ if (seq->seqbase.first != NULL) {
+ invalidate_scene_strips(scene, scene_target, &seq->seqbase);
+ }
+ }
+}
+
+void BKE_sequence_invalidate_scene_strips(Main *bmain, Scene *scene_target)
+{
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ if (scene->ed != NULL) {
+ invalidate_scene_strips(scene, scene_target, &scene->ed->seqbase);
+ }
+ }
+}
+
+static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
+{
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->clip == clip_target) {
+ BKE_sequence_invalidate_cache_raw(scene, seq);
+ }
+
+ if (seq->seqbase.first != NULL) {
+ invalidate_movieclip_strips(scene, clip_target, &seq->seqbase);
+ }
+ }
+}
+
+void BKE_sequence_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target)
+{
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ if (scene->ed != NULL) {
+ invalidate_movieclip_strips(scene, clip_target, &scene->ed->seqbase);
+ }
+ }
+}
+
+void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
+{
+ if (scene->ed == NULL) {
+ return;
+ }
+
+ Sequence *seq;
+
+ BKE_sequencer_cache_cleanup(scene);
+ BKE_sequencer_prefetch_stop(scene);
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
+ continue;
+ }
+
+ if (seq->strip) {
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_SPEED) {
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ }
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequencer_free_imbuf(scene, &seq->seqbase, for_render);
+ }
+ if (seq->type == SEQ_TYPE_SCENE) {
+ /* FIXME: recurse downwards,
+ * but do recurse protection somehow! */
+ }
+ }
+}
+
+static bool update_changed_seq_recurs(
+ Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
+{
+ Sequence *subseq;
+ bool free_imbuf = false;
+
+ /* recurse downwards to see if this seq depends on the changed seq */
+
+ if (seq == NULL) {
+ return false;
+ }
+
+ if (seq == changed_seq) {
+ free_imbuf = true;
+ }
+
+ for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) {
+ if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) {
+ free_imbuf = true;
+ }
+ }
+
+ if (seq->seq1) {
+ if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) {
+ free_imbuf = true;
+ }
+ }
+ if (seq->seq2 && (seq->seq2 != seq->seq1)) {
+ if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) {
+ free_imbuf = true;
+ }
+ }
+ if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) {
+ if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) {
+ free_imbuf = true;
+ }
+ }
+
+ if (free_imbuf) {
+ if (ibuf_change) {
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ BKE_sequence_free_anim(seq);
+ }
+ else if (seq->type == SEQ_TYPE_SPEED) {
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ }
+ }
+
+ if (len_change) {
+ BKE_sequence_calc(scene, seq);
+ }
+ }
+
+ return free_imbuf;
+}
+
+void BKE_sequencer_update_changed_seq_and_deps(Scene *scene,
+ Sequence *changed_seq,
+ int len_change,
+ int ibuf_change)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+
+ if (ed == NULL) {
+ return;
+ }
+
+ for (seq = ed->seqbase.first; seq; seq = seq->next) {
+ update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
+ }
+}
+
+/* Unused */
+static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame)
+{
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->enddisp < timeline_frame || seq->startdisp > timeline_frame) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame);
+ }
+ }
+}
+
+/* Unused */
+void BKE_sequencer_all_free_anim_ibufs(Scene *scene, int timeline_frame)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ return;
+ }
+ sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame);
+ BKE_sequencer_cache_cleanup(scene);
+}
+
+static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type == SEQ_TYPE_SCENE && seq->scene == scene) {
+ return seq;
+ }
+
+ if (seq->type == SEQ_TYPE_SCENE && (seq->flag & SEQ_SCENE_STRIPS)) {
+ if (sequencer_check_scene_recursion(scene, &seq->scene->ed->seqbase)) {
+ return seq;
+ }
+ }
+
+ if (seq->type == SEQ_TYPE_META && sequencer_check_scene_recursion(scene, &seq->seqbase)) {
+ return seq;
+ }
+ }
+
+ return NULL;
+}
+
+bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ return false;
+ }
+
+ Sequence *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
+
+ if (recursive_seq != NULL) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
+ recursive_seq->name + 2,
+ recursive_seq->startdisp);
+
+ LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
+ if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
+ /* There are other strips to render, so render them. */
+ return false;
+ }
+ }
+ /* No other strips to render - cancel operator. */
+ return true;
+ }
+
+ return false;
+}
+
+/* Check if "seq_main" (indirectly) uses strip "seq". */
+bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq)
+{
+ if (seq_main == NULL || seq == NULL) {
+ return false;
+ }
+
+ if (seq_main == seq) {
+ return true;
+ }
+
+ if ((seq_main->seq1 && BKE_sequencer_render_loop_check(seq_main->seq1, seq)) ||
+ (seq_main->seq2 && BKE_sequencer_render_loop_check(seq_main->seq2, seq)) ||
+ (seq_main->seq3 && BKE_sequencer_render_loop_check(seq_main->seq3, seq))) {
+ return true;
+ }
+
+ SequenceModifierData *smd;
+ for (smd = seq_main->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence && BKE_sequencer_render_loop_check(smd->mask_sequence, seq)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Function to free imbuf and anim data on changes */
+void BKE_sequence_free_anim(Sequence *seq)
+{
+ while (seq->anims.last) {
+ StripAnim *sanim = seq->anims.last;
+
+ if (sanim->anim) {
+ IMB_free_anim(sanim->anim);
+ sanim->anim = NULL;
+ }
+
+ BLI_freelinkN(&seq->anims, sanim);
+ }
+ BLI_listbase_clear(&seq->anims);
+}
+
+void BKE_sequence_session_uuid_generate(struct Sequence *sequence)
+{
+ sequence->runtime.session_uuid = BLI_session_uuid_generate();
+}
+
+void BKE_sequencer_check_uuids_unique_and_report(const Scene *scene)
+{
+ if (scene->ed == NULL) {
+ return;
+ }
+
+ struct GSet *used_uuids = BLI_gset_new(
+ BLI_session_uuid_ghash_hash, BLI_session_uuid_ghash_compare, "sequencer used uuids");
+
+ const Sequence *sequence;
+ SEQ_ALL_BEGIN (scene->ed, sequence) {
+ const SessionUUID *session_uuid = &sequence->runtime.session_uuid;
+ if (!BLI_session_uuid_is_generated(session_uuid)) {
+ printf("Sequence %s does not have UUID generated.\n", sequence->name);
+ continue;
+ }
+
+ if (BLI_gset_lookup(used_uuids, session_uuid) != NULL) {
+ printf("Sequence %s has duplicate UUID generated.\n", sequence->name);
+ continue;
+ }
+
+ BLI_gset_insert(used_uuids, (void *)session_uuid);
+ }
+ SEQ_ALL_END;
+
+ BLI_gset_free(used_uuids, NULL);
+}
diff --git a/source/blender/sequencer/intern/strip_select.c b/source/blender/sequencer/intern/strip_select.c
new file mode 100644
index 00000000000..478ae9be337
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_select.c
@@ -0,0 +1,81 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_scene.h"
+
+#include "SEQ_sequencer.h"
+
+Sequence *BKE_sequencer_active_get(Scene *scene)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ return ed->act_seq;
+}
+
+void BKE_sequencer_active_set(Scene *scene, Sequence *seq)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (ed == NULL) {
+ return;
+ }
+
+ ed->act_seq = seq;
+}
+
+int BKE_sequencer_active_get_pair(Scene *scene, Sequence **seq_act, Sequence **seq_other)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ *seq_act = BKE_sequencer_active_get(scene);
+
+ if (*seq_act == NULL) {
+ return 0;
+ }
+
+ Sequence *seq;
+
+ *seq_other = NULL;
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT && (seq != (*seq_act))) {
+ if (*seq_other) {
+ return 0;
+ }
+
+ *seq_other = seq;
+ }
+ }
+
+ return (*seq_other != NULL);
+}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
new file mode 100644
index 00000000000..a0ae6d6f16d
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -0,0 +1,353 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_movieclip.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "IMB_imbuf.h"
+
+#include "SEQ_sequencer.h"
+
+#include "strip_time.h"
+#include "utils.h"
+
+float seq_give_frame_index(Sequence *seq, float timeline_frame)
+{
+ float frame_index;
+ int sta = seq->start;
+ int end = seq->start + seq->len - 1;
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ end = seq->enddisp;
+ }
+
+ if (end < sta) {
+ return -1;
+ }
+
+ if (seq->flag & SEQ_REVERSE_FRAMES) {
+ /*reverse frame in this sequence */
+ if (timeline_frame <= sta) {
+ frame_index = end - sta;
+ }
+ else if (timeline_frame >= end) {
+ frame_index = 0;
+ }
+ else {
+ frame_index = end - timeline_frame;
+ }
+ }
+ else {
+ if (timeline_frame <= sta) {
+ frame_index = 0;
+ }
+ else if (timeline_frame >= end) {
+ frame_index = end - sta;
+ }
+ else {
+ frame_index = timeline_frame - sta;
+ }
+ }
+
+ if (seq->strobe < 1.0f) {
+ seq->strobe = 1.0f;
+ }
+
+ if (seq->strobe > 1.0f) {
+ frame_index -= fmodf((double)frame_index, (double)seq->strobe);
+ }
+
+ return frame_index;
+}
+
+static int metaseq_start(Sequence *metaseq)
+{
+ return metaseq->start + metaseq->startofs;
+}
+
+static int metaseq_end(Sequence *metaseq)
+{
+ return metaseq->start + metaseq->len - metaseq->endofs;
+}
+
+static void seq_update_sound_bounds_recursive_impl(Scene *scene,
+ Sequence *metaseq,
+ int start,
+ int end)
+{
+ Sequence *seq;
+
+ /* for sound we go over full meta tree to update bounds of the sound strips,
+ * since sound is played outside of evaluating the imbufs, */
+ for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive_impl(
+ scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ if (seq->scene_sound) {
+ int startofs = seq->startofs;
+ int endofs = seq->endofs;
+ if (seq->startofs + seq->start < start) {
+ startofs = start - seq->start;
+ }
+
+ if (seq->start + seq->len - seq->endofs > end) {
+ endofs = seq->start + seq->len - end;
+ }
+
+ BKE_sound_move_scene_sound(scene,
+ seq->scene_sound,
+ seq->start + startofs,
+ seq->start + seq->len - endofs,
+ startofs + seq->anim_startofs);
+ }
+ }
+ }
+}
+
+void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
+{
+ seq_update_sound_bounds_recursive_impl(
+ scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
+}
+
+void BKE_sequence_calc_disp(Scene *scene, Sequence *seq)
+{
+ if (seq->startofs && seq->startstill) {
+ seq->startstill = 0;
+ }
+ if (seq->endofs && seq->endstill) {
+ seq->endstill = 0;
+ }
+
+ seq->startdisp = seq->start + seq->startofs - seq->startstill;
+ seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
+
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
+}
+
+void BKE_sequence_calc(Scene *scene, Sequence *seq)
+{
+ Sequence *seqm;
+ int min, max;
+
+ /* check all metas recursively */
+ seqm = seq->seqbase.first;
+ while (seqm) {
+ if (seqm->seqbase.first) {
+ BKE_sequence_calc(scene, seqm);
+ }
+ seqm = seqm->next;
+ }
+
+ /* effects and meta: automatic start and end */
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ if (seq->seq1) {
+ seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
+ if (seq->seq3) {
+ seq->start = seq->startdisp = max_iii(
+ seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
+ seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+ }
+ else if (seq->seq2) {
+ seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
+ seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
+ }
+ else {
+ seq->start = seq->startdisp = seq->seq1->startdisp;
+ seq->enddisp = seq->seq1->enddisp;
+ }
+ /* we cant help if strips don't overlap, it wont give useful results.
+ * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
+ if (seq->enddisp < seq->startdisp) {
+ /* simple start/end swap */
+ seq->start = seq->enddisp;
+ seq->enddisp = seq->startdisp;
+ seq->startdisp = seq->start;
+ seq->flag |= SEQ_INVALID_EFFECT;
+ }
+ else {
+ seq->flag &= ~SEQ_INVALID_EFFECT;
+ }
+
+ seq->len = seq->enddisp - seq->startdisp;
+ }
+ else {
+ BKE_sequence_calc_disp(scene, seq);
+ }
+ }
+ else {
+ if (seq->type == SEQ_TYPE_META) {
+ seqm = seq->seqbase.first;
+ if (seqm) {
+ min = MAXFRAME * 2;
+ max = -MAXFRAME * 2;
+ while (seqm) {
+ if (seqm->startdisp < min) {
+ min = seqm->startdisp;
+ }
+ if (seqm->enddisp > max) {
+ max = seqm->enddisp;
+ }
+ seqm = seqm->next;
+ }
+ seq->start = min + seq->anim_startofs;
+ seq->len = max - min;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ }
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
+ BKE_sequence_calc_disp(scene, seq);
+ }
+}
+
+/** Comparison function suitable to be used with BLI_listbase_sort()... */
+int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
+{
+ const Sequence *seq_a = a;
+ const Sequence *seq_b = b;
+
+ return (seq_a->startdisp > seq_b->startdisp);
+}
+
+int BKE_sequencer_find_next_prev_edit(Scene *scene,
+ int timeline_frame,
+ const short side,
+ const bool do_skip_mute,
+ const bool do_center,
+ const bool do_unselected)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+
+ int dist, best_dist, best_frame = timeline_frame;
+ int seq_frames[2], seq_frames_tot;
+
+ /* In case where both is passed,
+ * frame just finds the nearest end while frame_left the nearest start. */
+
+ best_dist = MAXFRAME * 2;
+
+ if (ed == NULL) {
+ return timeline_frame;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ int i;
+
+ if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
+ continue;
+ }
+
+ if (do_unselected && (seq->flag & SELECT)) {
+ continue;
+ }
+
+ if (do_center) {
+ seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames_tot = 1;
+ }
+ else {
+ seq_frames[0] = seq->startdisp;
+ seq_frames[1] = seq->enddisp;
+
+ seq_frames_tot = 2;
+ }
+
+ for (i = 0; i < seq_frames_tot; i++) {
+ const int seq_frame = seq_frames[i];
+
+ dist = MAXFRAME * 2;
+
+ switch (side) {
+ case SEQ_SIDE_LEFT:
+ if (seq_frame < timeline_frame) {
+ dist = timeline_frame - seq_frame;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (seq_frame > timeline_frame) {
+ dist = seq_frame - timeline_frame;
+ }
+ break;
+ case SEQ_SIDE_BOTH:
+ dist = abs(seq_frame - timeline_frame);
+ break;
+ }
+
+ if (dist < best_dist) {
+ best_frame = seq_frame;
+ best_dist = dist;
+ }
+ }
+ }
+
+ return best_frame;
+}
+
+float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE: {
+ seq_open_anim_file(scene, seq, true);
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ return 0.0f;
+ }
+ StripAnim *strip_anim = seq->anims.first;
+ if (strip_anim->anim == NULL) {
+ return 0.0f;
+ }
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
+ return (float)frs_sec / frs_sec_base;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIECLIP:
+ if (seq->clip != NULL) {
+ return BKE_movieclip_get_fps(seq->clip);
+ }
+ break;
+ case SEQ_TYPE_SCENE:
+ if (seq->scene != NULL) {
+ return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
+ }
+ break;
+ }
+ return 0.0f;
+}
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
new file mode 100644
index 00000000000..e4fb7f1d2ec
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Scene;
+struct Sequence;
+
+float seq_give_frame_index(struct Sequence *seq, float timeline_frame);
+void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
new file mode 100644
index 00000000000..dd6b7e6dba5
--- /dev/null
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -0,0 +1,397 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "SEQ_sequencer.h"
+
+static int seq_tx_get_start(Sequence *seq)
+{
+ return seq->start;
+}
+static int seq_tx_get_end(Sequence *seq)
+{
+ return seq->start + seq->len;
+}
+
+int BKE_sequence_tx_get_final_left(Sequence *seq, bool metaclip)
+{
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return max_ii(BKE_sequence_tx_get_final_left(seq, false),
+ BKE_sequence_tx_get_final_left((Sequence *)seq->tmp, true));
+ }
+
+ return (seq->start - seq->startstill) + seq->startofs;
+}
+int BKE_sequence_tx_get_final_right(Sequence *seq, bool metaclip)
+{
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return min_ii(BKE_sequence_tx_get_final_right(seq, false),
+ BKE_sequence_tx_get_final_right((Sequence *)seq->tmp, true));
+ }
+
+ return ((seq->start + seq->len) + seq->endstill) - seq->endofs;
+}
+
+void BKE_sequence_tx_set_final_left(Sequence *seq, int val)
+{
+ if (val < (seq)->start) {
+ seq->startstill = abs(val - (seq)->start);
+ seq->startofs = 0;
+ }
+ else {
+ seq->startofs = abs(val - (seq)->start);
+ seq->startstill = 0;
+ }
+}
+
+void BKE_sequence_tx_set_final_right(Sequence *seq, int val)
+{
+ if (val > (seq)->start + (seq)->len) {
+ seq->endstill = abs(val - (seq->start + (seq)->len));
+ seq->endofs = 0;
+ }
+ else {
+ seq->endofs = abs(val - ((seq)->start + (seq)->len));
+ seq->endstill = 0;
+ }
+}
+
+/* used so we can do a quick check for single image seq
+ * since they work a bit differently to normal image seq's (during transform) */
+bool BKE_sequence_single_check(Sequence *seq)
+{
+ return ((seq->len == 1) &&
+ (seq->type == SEQ_TYPE_IMAGE ||
+ ((seq->type & SEQ_TYPE_EFFECT) && BKE_sequence_effect_get_num_inputs(seq->type) == 0)));
+}
+
+/* check if the selected seq's reference unselected seq's */
+bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase)
+{
+ Sequence *seq;
+ /* is there more than 1 select */
+ bool ok = false;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT) {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false) {
+ return false;
+ }
+
+ /* test relationships */
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
+ continue;
+ }
+
+ if (seq->flag & SELECT) {
+ if ((seq->seq1 && (seq->seq1->flag & SELECT) == 0) ||
+ (seq->seq2 && (seq->seq2->flag & SELECT) == 0) ||
+ (seq->seq3 && (seq->seq3->flag & SELECT) == 0)) {
+ return false;
+ }
+ }
+ else {
+ if ((seq->seq1 && (seq->seq1->flag & SELECT)) || (seq->seq2 && (seq->seq2->flag & SELECT)) ||
+ (seq->seq3 && (seq->seq3->flag & SELECT))) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* use to impose limits when dragging/extending - so impossible situations don't happen
+ * Cant use the SEQ_LEFTSEL and SEQ_LEFTSEL directly because the strip may be in a metastrip */
+void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
+{
+ if (leftflag) {
+ if (BKE_sequence_tx_get_final_left(seq, false) >=
+ BKE_sequence_tx_get_final_right(seq, false)) {
+ BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_right(seq, false) - 1);
+ }
+
+ if (BKE_sequence_single_check(seq) == 0) {
+ if (BKE_sequence_tx_get_final_left(seq, false) >= seq_tx_get_end(seq)) {
+ BKE_sequence_tx_set_final_left(seq, seq_tx_get_end(seq) - 1);
+ }
+
+ /* doesn't work now - TODO */
+#if 0
+ if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
+ int ofs;
+ ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
+ seq->start -= ofs;
+ seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs);
+ }
+#endif
+ }
+ }
+
+ if (rightflag) {
+ if (BKE_sequence_tx_get_final_right(seq, false) <=
+ BKE_sequence_tx_get_final_left(seq, false)) {
+ BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + 1);
+ }
+
+ if (BKE_sequence_single_check(seq) == 0) {
+ if (BKE_sequence_tx_get_final_right(seq, false) <= seq_tx_get_start(seq)) {
+ BKE_sequence_tx_set_final_right(seq, seq_tx_get_start(seq) + 1);
+ }
+ }
+ }
+
+ /* sounds cannot be extended past their endpoints */
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ seq->startstill = 0;
+ seq->endstill = 0;
+ }
+}
+
+void BKE_sequence_single_fix(Sequence *seq)
+{
+ int left, start, offset;
+ if (!BKE_sequence_single_check(seq)) {
+ return;
+ }
+
+ /* make sure the image is always at the start since there is only one,
+ * adjusting its start should be ok */
+ left = BKE_sequence_tx_get_final_left(seq, false);
+ start = seq->start;
+ if (start != left) {
+ offset = left - start;
+ BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_left(seq, false) - offset);
+ BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_right(seq, false) - offset);
+ seq->start += offset;
+ }
+}
+
+bool BKE_sequence_tx_test(Sequence *seq)
+{
+ return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0);
+}
+
+/**
+ * Return \a true if given \a seq needs a complete cleanup of its cache when it is transformed.
+ *
+ * Some (effect) strip types need a complete recache of themselves when they are transformed,
+ * because they do not 'contain' anything and do not have any explicit relations to other strips.
+ */
+bool BKE_sequence_tx_fullupdate_test(Sequence *seq)
+{
+ return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM);
+}
+
+static bool seq_overlap(Sequence *seq1, Sequence *seq2)
+{
+ return (seq1 != seq2 && seq1->machine == seq2->machine &&
+ ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
+}
+
+bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test)
+{
+ Sequence *seq;
+
+ seq = seqbasep->first;
+ while (seq) {
+ if (seq_overlap(test, seq)) {
+ return true;
+ }
+
+ seq = seq->next;
+ }
+ return false;
+}
+
+void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta)
+{
+ if (delta == 0) {
+ return;
+ }
+
+ BKE_sequencer_offset_animdata(evil_scene, seq, delta);
+ seq->start += delta;
+
+ if (seq->type == SEQ_TYPE_META) {
+ Sequence *seq_child;
+ for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
+ BKE_sequence_translate(evil_scene, seq_child, delta);
+ }
+ }
+
+ BKE_sequence_calc_disp(evil_scene, seq);
+}
+
+/* return 0 if there weren't enough space */
+bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep,
+ Sequence *test,
+ Scene *evil_scene,
+ int channel_delta)
+{
+ const int orig_machine = test->machine;
+ BLI_assert(ELEM(channel_delta, -1, 1));
+
+ test->machine += channel_delta;
+ BKE_sequence_calc(evil_scene, test);
+ while (BKE_sequence_test_overlap(seqbasep, test)) {
+ if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
+ break;
+ }
+
+ test->machine += channel_delta;
+ BKE_sequence_calc(
+ evil_scene,
+ test); // XXX - I don't think this is needed since were only moving vertically, Campbell.
+ }
+
+ if ((test->machine < 1) || (test->machine > MAXSEQ)) {
+ /* Blender 2.4x would remove the strip.
+ * nicer to move it to the end */
+
+ Sequence *seq;
+ int new_frame = test->enddisp;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->machine == orig_machine) {
+ new_frame = max_ii(new_frame, seq->enddisp);
+ }
+ }
+
+ test->machine = orig_machine;
+ new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
+ BKE_sequence_translate(evil_scene, test, new_frame - test->start);
+
+ BKE_sequence_calc(evil_scene, test);
+ return false;
+ }
+
+ return true;
+}
+
+bool BKE_sequence_base_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
+{
+ return BKE_sequence_base_shuffle_ex(seqbasep, test, evil_scene, 1);
+}
+
+static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir)
+{
+ int offset = 0;
+ Sequence *seq, *seq_other;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
+ if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
+ if (dir == 'L') {
+ offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
+ }
+ else {
+ offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
+ }
+ }
+ }
+ }
+ }
+ return offset;
+}
+
+static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
+{
+ int ofs = 0;
+ int tot_ofs = 0;
+ Sequence *seq;
+ while ((ofs = shuffle_seq_time_offset_test(seqbasep, dir))) {
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ /* seq_test_overlap only tests display values */
+ seq->startdisp += ofs;
+ seq->enddisp += ofs;
+ }
+ }
+
+ tot_ofs += ofs;
+ }
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ BKE_sequence_calc_disp(scene, seq); /* corrects dummy startdisp/enddisp values */
+ }
+ }
+
+ return tot_ofs;
+}
+
+bool BKE_sequence_base_shuffle_time(ListBase *seqbasep,
+ Scene *evil_scene,
+ ListBase *markers,
+ const bool use_sync_markers)
+{
+ /* note: seq->tmp is used to tag strips to move */
+
+ Sequence *seq;
+
+ int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
+ int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
+ int offset = (-offset_l < offset_r) ? offset_l : offset_r;
+
+ if (offset) {
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ BKE_sequence_translate(evil_scene, seq, offset);
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+ }
+
+ if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
+ TimeMarker *marker;
+ /* affect selected markers - it's unlikely that we will want to affect all in this way? */
+ for (marker = markers->first; marker; marker = marker->next) {
+ if (marker->flag & SELECT) {
+ marker->frame += offset;
+ }
+ }
+ }
+ }
+
+ return offset ? false : true;
+}
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
new file mode 100644
index 00000000000..2b1d36a7709
--- /dev/null
+++ b/source/blender/sequencer/intern/utils.c
@@ -0,0 +1,549 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * - Blender Foundation, 2003-2009
+ * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mask_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "SEQ_sequencer.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "multiview.h"
+#include "proxy.h"
+#include "utils.h"
+
+void BKE_sequencer_sort(Scene *scene)
+{
+ /* all strips together per kind, and in order of y location ("machine") */
+ ListBase seqbase, effbase;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq, *seqt;
+
+ if (ed == NULL) {
+ return;
+ }
+
+ BLI_listbase_clear(&seqbase);
+ BLI_listbase_clear(&effbase);
+
+ while ((seq = BLI_pophead(ed->seqbasep))) {
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ seqt = effbase.first;
+ while (seqt) {
+ if (seqt->machine >= seq->machine) {
+ BLI_insertlinkbefore(&effbase, seqt, seq);
+ break;
+ }
+ seqt = seqt->next;
+ }
+ if (seqt == NULL) {
+ BLI_addtail(&effbase, seq);
+ }
+ }
+ else {
+ seqt = seqbase.first;
+ while (seqt) {
+ if (seqt->machine >= seq->machine) {
+ BLI_insertlinkbefore(&seqbase, seqt, seq);
+ break;
+ }
+ seqt = seqt->next;
+ }
+ if (seqt == NULL) {
+ BLI_addtail(&seqbase, seq);
+ }
+ }
+ }
+
+ BLI_movelisttolist(&seqbase, &effbase);
+ *(ed->seqbasep) = seqbase;
+}
+
+typedef struct SeqUniqueInfo {
+ Sequence *seq;
+ char name_src[SEQ_NAME_MAXSTR];
+ char name_dest[SEQ_NAME_MAXSTR];
+ int count;
+ int match;
+} SeqUniqueInfo;
+
+static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
+{
+ Sequence *seq;
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
+ /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */
+ BLI_snprintf(sui->name_dest,
+ sizeof(sui->name_dest),
+ "%.*s.%03d",
+ SEQ_NAME_MAXSTR - 4 - 1 - 2,
+ sui->name_src,
+ sui->count++);
+ sui->match = 1; /* be sure to re-scan */
+ }
+ }
+}
+
+static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
+{
+ if (seq->seqbase.first) {
+ seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
+ }
+ return 1;
+}
+
+void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
+{
+ SeqUniqueInfo sui;
+ char *dot;
+ sui.seq = seq;
+ BLI_strncpy(sui.name_src, seq->name + 2, sizeof(sui.name_src));
+ BLI_strncpy(sui.name_dest, seq->name + 2, sizeof(sui.name_dest));
+
+ sui.count = 1;
+ sui.match = 1; /* assume the worst to start the loop */
+
+ /* Strip off the suffix */
+ if ((dot = strrchr(sui.name_src, '.'))) {
+ *dot = '\0';
+ dot++;
+
+ if (*dot) {
+ sui.count = atoi(dot) + 1;
+ }
+ }
+
+ while (sui.match) {
+ sui.match = 0;
+ seqbase_unique_name(seqbasep, &sui);
+ BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
+ }
+
+ BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
+}
+
+static const char *give_seqname_by_type(int type)
+{
+ switch (type) {
+ case SEQ_TYPE_META:
+ return "Meta";
+ case SEQ_TYPE_IMAGE:
+ return "Image";
+ case SEQ_TYPE_SCENE:
+ return "Scene";
+ case SEQ_TYPE_MOVIE:
+ return "Movie";
+ case SEQ_TYPE_MOVIECLIP:
+ return "Clip";
+ case SEQ_TYPE_MASK:
+ return "Mask";
+ case SEQ_TYPE_SOUND_RAM:
+ return "Audio";
+ case SEQ_TYPE_CROSS:
+ return "Cross";
+ case SEQ_TYPE_GAMCROSS:
+ return "Gamma Cross";
+ case SEQ_TYPE_ADD:
+ return "Add";
+ case SEQ_TYPE_SUB:
+ return "Sub";
+ case SEQ_TYPE_MUL:
+ return "Mul";
+ case SEQ_TYPE_ALPHAOVER:
+ return "Alpha Over";
+ case SEQ_TYPE_ALPHAUNDER:
+ return "Alpha Under";
+ case SEQ_TYPE_OVERDROP:
+ return "Over Drop";
+ case SEQ_TYPE_COLORMIX:
+ return "Color Mix";
+ case SEQ_TYPE_WIPE:
+ return "Wipe";
+ case SEQ_TYPE_GLOW:
+ return "Glow";
+ case SEQ_TYPE_TRANSFORM:
+ return "Transform";
+ case SEQ_TYPE_COLOR:
+ return "Color";
+ case SEQ_TYPE_MULTICAM:
+ return "Multicam";
+ case SEQ_TYPE_ADJUSTMENT:
+ return "Adjustment";
+ case SEQ_TYPE_SPEED:
+ return "Speed";
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ return "Gaussian Blur";
+ case SEQ_TYPE_TEXT:
+ return "Text";
+ default:
+ return NULL;
+ }
+}
+
+const char *BKE_sequence_give_name(Sequence *seq)
+{
+ const char *name = give_seqname_by_type(seq->type);
+
+ if (!name) {
+ if (!(seq->type & SEQ_TYPE_EFFECT)) {
+ return seq->strip->dir;
+ }
+
+ return "Effect";
+ }
+ return name;
+}
+
+ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
+{
+ ListBase *seqbase = NULL;
+
+ switch (seq->type) {
+ case SEQ_TYPE_META: {
+ seqbase = &seq->seqbase;
+ *r_offset = seq->start;
+ break;
+ }
+ case SEQ_TYPE_SCENE: {
+ if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
+ Editing *ed = BKE_sequencer_editing_get(seq->scene, false);
+ if (ed) {
+ seqbase = &ed->seqbase;
+ *r_offset = seq->scene->r.sfra;
+ }
+ }
+ break;
+ }
+ }
+
+ return seqbase;
+}
+
+void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
+{
+ char dir[FILE_MAX];
+ char name[FILE_MAX];
+ StripProxy *proxy;
+ bool use_proxy;
+ bool is_multiview_loaded = false;
+ Editing *ed = scene->ed;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
+ return;
+ }
+
+ /* reset all the previously created anims */
+ BKE_sequence_free_anim(seq);
+
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+
+ proxy = seq->strip->proxy;
+
+ use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
+ (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
+
+ if (use_proxy) {
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (ed->proxy_dir[0] == 0) {
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ }
+ else {
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+ }
+ }
+ else {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
+ }
+
+ if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ int totfiles = seq_num_files(scene, seq->views_format, true);
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ int i;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+ char str[FILE_MAX];
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+
+ BLI_addtail(&seq->anims, sanim);
+
+ BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
+
+ if (openfile) {
+ sanim->anim = openanim(str,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(str,
+ IB_rect |
+ ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim) {
+ /* we already have the suffix */
+ IMB_suffix_anim(sanim->anim, suffix);
+ }
+ else {
+ if (openfile) {
+ sanim->anim = openanim(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(name,
+ IB_rect |
+ ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ /* No individual view files - monoscopic, stereo 3d or EXR multi-view. */
+ totfiles = 1;
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ StripAnim *sanim;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+
+ if (openfile) {
+ sanim->anim = openanim(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+}
+
+const Sequence *BKE_sequencer_foreground_frame_get(const Scene *scene, int frame)
+{
+ const Editing *ed = scene->ed;
+ const Sequence *seq, *best_seq = NULL;
+ int best_machine = -1;
+
+ if (!ed) {
+ return NULL;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) {
+ continue;
+ }
+ /* Only use strips that generate an image, not ones that combine
+ * other strips or apply some effect. */
+ if (ELEM(seq->type,
+ SEQ_TYPE_IMAGE,
+ SEQ_TYPE_META,
+ SEQ_TYPE_SCENE,
+ SEQ_TYPE_MOVIE,
+ SEQ_TYPE_COLOR,
+ SEQ_TYPE_TEXT)) {
+ if (seq->machine > best_machine) {
+ best_seq = seq;
+ best_machine = seq->machine;
+ }
+ }
+ }
+ return best_seq;
+}
+
+/* in cases where we done know the sequence's listbase */
+ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq)
+{
+ Sequence *iseq;
+ ListBase *lb = NULL;
+
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (seq == iseq) {
+ return seqbase;
+ }
+ if (iseq->seqbase.first && (lb = BKE_sequence_seqbase(&iseq->seqbase, seq))) {
+ return lb;
+ }
+ }
+
+ return NULL;
+}
+
+Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *seq)
+{
+ Sequence *iseq;
+
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ Sequence *rval;
+
+ if (seq == iseq) {
+ return meta;
+ }
+ if (iseq->seqbase.first && (rval = BKE_sequence_metastrip(&iseq->seqbase, iseq, seq))) {
+ return rval;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Only use as last resort when the StripElem is available but no the Sequence.
+ * (needed for RNA)
+ */
+Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se)
+{
+ Sequence *iseq;
+
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ Sequence *seq_found;
+ if ((iseq->strip && iseq->strip->stripdata) &&
+ (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))) {
+ break;
+ }
+ if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) {
+ iseq = seq_found;
+ break;
+ }
+ }
+
+ return iseq;
+}
+
+Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool recursive)
+{
+ Sequence *iseq = NULL;
+ Sequence *rseq = NULL;
+
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (STREQ(name, iseq->name + 2)) {
+ return iseq;
+ }
+ if (recursive && (iseq->seqbase.first) &&
+ (rseq = BKE_sequence_get_by_name(&iseq->seqbase, name, 1))) {
+ return rseq;
+ }
+ }
+
+ return NULL;
+}
+
+Mask *BKE_sequencer_mask_get(Scene *scene)
+{
+ Sequence *seq_act = BKE_sequencer_active_get(scene);
+
+ if (seq_act && seq_act->type == SEQ_TYPE_MASK) {
+ return seq_act->mask;
+ }
+
+ return NULL;
+}
+
+void BKE_sequence_alpha_mode_from_extension(Sequence *seq)
+{
+ if (seq->strip && seq->strip->stripdata) {
+ const char *filename = seq->strip->stripdata->name;
+ seq->alpha_mode = BKE_image_alpha_mode_from_extension_ex(filename);
+ }
+}
+
+/* called on draw, needs to be fast,
+ * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
+bool BKE_sequence_is_valid_check(Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_MASK:
+ return (seq->mask != NULL);
+ case SEQ_TYPE_MOVIECLIP:
+ return (seq->clip != NULL);
+ case SEQ_TYPE_SCENE:
+ return (seq->scene != NULL);
+ case SEQ_TYPE_SOUND_RAM:
+ return (seq->sound != NULL);
+ }
+
+ return true;
+}
+
+bool sequencer_seq_generates_image(Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE:
+ case SEQ_TYPE_SCENE:
+ case SEQ_TYPE_MOVIE:
+ case SEQ_TYPE_MOVIECLIP:
+ case SEQ_TYPE_MASK:
+ case SEQ_TYPE_COLOR:
+ case SEQ_TYPE_TEXT:
+ return true;
+ }
+ return false;
+}
diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h
new file mode 100644
index 00000000000..fe6041ec5e8
--- /dev/null
+++ b/source/blender/sequencer/intern/utils.h
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Scene;
+struct anim;
+
+bool sequencer_seq_generates_image(struct Sequence *seq);
+void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
+struct Sequence *BKE_sequence_metastrip(ListBase *seqbase /* = ed->seqbase */,
+ struct Sequence *meta /* = NULL */,
+ struct Sequence *seq);
+
+#ifdef __cplusplus
+}
+#endif