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-05 15:33:27 +0300
committerRichard Antalik <richardantalik@gmail.com>2020-11-05 15:33:27 +0300
commit0f43fe7fa66b94cf3cb5033223c1d96b89372ecc (patch)
treeebe008c860f1b0988f48da46d220d28b6860f9cb
parent7bc7b7da2d2fdd48a7c8c28f7c23419ca9178b4d (diff)
Cleanup: split sequencer.c file
Move functions closely related to rendering images and proxies into render.c and proxy.c files. render.h and proxy.h are created for functions used internally. There should be no functional changes.
-rw-r--r--source/blender/sequencer/CMakeLists.txt4
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h28
-rw-r--r--source/blender/sequencer/intern/effects.c17
-rw-r--r--source/blender/sequencer/intern/modifier.c373
-rw-r--r--source/blender/sequencer/intern/prefetch.c3
-rw-r--r--source/blender/sequencer/intern/proxy.c570
-rw-r--r--source/blender/sequencer/intern/proxy.h40
-rw-r--r--source/blender/sequencer/intern/render.c2106
-rw-r--r--source/blender/sequencer/intern/render.h75
-rw-r--r--source/blender/sequencer/intern/sequencer.c2935
-rw-r--r--source/blender/sequencer/intern/sequencer.h61
11 files changed, 3208 insertions, 3004 deletions
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index 7aac6eebc66..1b14207b840 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -48,6 +48,10 @@ set(SRC
intern/effects.c
intern/modifier.c
intern/prefetch.c
+ intern/proxy.c
+ intern/proxy.h
+ intern/render.c
+ intern/render.h
)
set(LIB
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index a154b5d908b..b38f92e7b01 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -108,7 +108,7 @@ void BKE_sequence_iterator_next(SeqIterator *iter);
void BKE_sequence_iterator_end(SeqIterator *iter);
/* **********************************************************************
- * sequencer.c
+ * render.c
*
* Sequencer render functions
* **********************************************************************
@@ -146,7 +146,6 @@ struct ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra,
struct ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context,
float cfra,
struct Sequence *seq);
-void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq);
void BKE_sequence_init_colorspace(struct Sequence *seq);
void BKE_sequencer_new_render_data(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -156,11 +155,11 @@ void BKE_sequencer_new_render_data(struct Main *bmain,
int preview_render_size,
int for_render,
SeqRenderData *r_context);
-bool SEQ_can_use_proxy(struct Sequence *seq, int psize);
-int SEQ_rendersize_to_proxysize(int render_size);
+int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
+struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
/* **********************************************************************
- * sequencer.c
+ * render.c
*
* Sequencer color space functions
* ********************************************************************** */
@@ -173,6 +172,7 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe
*
* Sequencer scene functions
* ********************************************************************** */
+
struct Editing *BKE_sequencer_editing_get(struct Scene *scene, bool alloc);
struct Editing *BKE_sequencer_editing_ensure(struct Scene *scene);
void BKE_sequencer_editing_free(struct Scene *scene, const bool do_id_user);
@@ -214,12 +214,21 @@ void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
struct Sequence *seq,
bool *r_was_reloaded,
bool *r_can_produce_frames);
-int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
-struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
+void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene,
struct Sequence *changed_seq,
int len_change,
int ibuf_change);
+bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
+bool BKE_sequencer_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
+int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b);
+
+/* **********************************************************************
+ * proxy.c
+ *
+ * Proxy functions
+ * ********************************************************************** */
+
bool BKE_sequencer_proxy_rebuild_context(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -232,9 +241,8 @@ void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context,
float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
void BKE_sequencer_proxy_set(struct Sequence *seq, bool value);
-bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
-bool BKE_sequencer_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
-int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b);
+bool SEQ_can_use_proxy(struct Sequence *seq, int psize);
+int SEQ_rendersize_to_proxysize(int render_size);
double BKE_sequencer_rendersize_to_scale_factor(int size);
/* **********************************************************************
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index ee94ecadb14..06bd6022607 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -62,6 +62,7 @@
#include "BLF_api.h"
+#include "render.h"
#include "sequencer.h"
static struct SeqEffectHandle get_sequence_effect_impl(int seq_type);
@@ -151,15 +152,15 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context,
if (out->rect_float) {
if (ibuf1 && !ibuf1->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
+ seq_imbuf_to_sequencer_space(scene, ibuf1, true);
}
if (ibuf2 && !ibuf2->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
+ seq_imbuf_to_sequencer_space(scene, ibuf2, true);
}
if (ibuf3 && !ibuf3->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
+ seq_imbuf_to_sequencer_space(scene, ibuf3, true);
}
IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
@@ -2989,7 +2990,7 @@ static ImBuf *do_multicam(const SeqRenderData *context,
return NULL;
}
- out = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->multicam_source, seqbasep);
+ out = seq_render_give_ibuf_seqbase(context, cfra, seq->multicam_source, seqbasep);
return out;
}
@@ -3018,7 +3019,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq);
if (seq->machine > 1) {
- i = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->machine - 1, seqbasep);
+ i = seq_render_give_ibuf_seqbase(context, cfra, seq->machine - 1, seqbasep);
}
/* found nothing? so let's work the way up the metastrip stack, so
@@ -3253,7 +3254,7 @@ float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
float cfra,
int input)
{
- int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ int nr = seq_give_stripelem_index(seq, cfra);
SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
@@ -3272,7 +3273,7 @@ float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, Sequence *seq, float cfra)
{
- int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ int nr = seq_give_stripelem_index(seq, cfra);
return s->frameMap[nr] - floor(s->frameMap[nr]);
}
@@ -3293,7 +3294,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, cfra);
/* Current frame is ibuf1, next frame is ibuf2. */
- out = BKE_sequencer_effect_execute_threaded(
+ out = seq_render_effect_execute_threaded(
&cross_effect, context, NULL, cfra, facf0, facf1, ibuf1, ibuf2, ibuf3);
return out;
}
diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c
index 6ddbbc6a8e9..4a922e9ce9f 100644
--- a/source/blender/sequencer/intern/modifier.c
+++ b/source/blender/sequencer/intern/modifier.c
@@ -46,6 +46,7 @@
#include "SEQ_sequencer.h"
+#include "render.h"
#include "sequencer.h"
static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
@@ -82,19 +83,58 @@ typedef struct ModifierThread {
modifier_apply_threaded_cb apply_callback;
} ModifierThread;
+/**
+ * \a cfra is offset by \a fra_offset only in case we are using a real mask.
+ */
+static ImBuf *modifier_render_mask_input(const SeqRenderData *context,
+ int mask_input_type,
+ Sequence *mask_sequence,
+ Mask *mask_id,
+ int cfra,
+ int fra_offset,
+ bool make_float)
+{
+ ImBuf *mask_input = NULL;
+
+ if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
+ if (mask_sequence) {
+ SeqRenderState state;
+ seq_render_state_init(&state);
+
+ mask_input = seq_render_strip(context, &state, mask_sequence, cfra);
+
+ if (make_float) {
+ if (!mask_input->rect_float) {
+ IMB_float_from_rect(mask_input);
+ }
+ }
+ else {
+ if (!mask_input->rect) {
+ IMB_rect_from_float(mask_input);
+ }
+ }
+ }
+ }
+ else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
+ mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
+ }
+
+ return mask_input;
+}
+
static ImBuf *modifier_mask_get(SequenceModifierData *smd,
const SeqRenderData *context,
int cfra,
int fra_offset,
bool make_float)
{
- return BKE_sequencer_render_mask_input(context,
- smd->mask_input_type,
- smd->mask_sequence,
- smd->mask_id,
- cfra,
- fra_offset,
- make_float);
+ return modifier_render_mask_input(context,
+ smd->mask_input_type,
+ smd->mask_sequence,
+ smd->mask_id,
+ cfra,
+ fra_offset,
+ make_float);
}
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -174,6 +214,291 @@ static void modifier_apply_threaded(ImBuf *ibuf,
/** \name Color Balance Modifier
* \{ */
+static StripColorBalance calc_cb(StripColorBalance *cb_)
+{
+ StripColorBalance cb = *cb_;
+ int c;
+
+ for (c = 0; c < 3; c++) {
+ cb.lift[c] = 2.0f - cb.lift[c];
+ }
+
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
+ for (c = 0; c < 3; c++) {
+ /* tweak to give more subtle results
+ * values above 1.0 are scaled */
+ if (cb.lift[c] > 1.0f) {
+ cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
+ }
+
+ cb.lift[c] = 2.0f - cb.lift[c];
+ }
+ }
+
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
+ for (c = 0; c < 3; c++) {
+ if (cb.gain[c] != 0.0f) {
+ cb.gain[c] = 1.0f / cb.gain[c];
+ }
+ else {
+ cb.gain[c] = 1000000; /* should be enough :) */
+ }
+ }
+ }
+
+ if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
+ for (c = 0; c < 3; c++) {
+ if (cb.gamma[c] != 0.0f) {
+ cb.gamma[c] = 1.0f / cb.gamma[c];
+ }
+ else {
+ cb.gamma[c] = 1000000; /* should be enough :) */
+ }
+ }
+ }
+
+ return cb;
+}
+
+/* note: lift is actually 2-lift */
+MINLINE float color_balance_fl(
+ float in, const float lift, const float gain, const float gamma, const float mul)
+{
+ float x = (((in - 1.0f) * lift) + 1.0f) * gain;
+
+ /* prevent NaN */
+ if (x < 0.f) {
+ x = 0.f;
+ }
+
+ x = powf(x, gamma) * mul;
+ CLAMP(x, FLT_MIN, FLT_MAX);
+ return x;
+}
+
+static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul)
+{
+ int y;
+
+ for (y = 0; y < 256; y++) {
+ float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
+
+ table[y] = v;
+ }
+}
+
+static void color_balance_byte_byte(StripColorBalance *cb_,
+ unsigned char *rect,
+ unsigned char *mask_rect,
+ int width,
+ int height,
+ float mul)
+{
+ // unsigned char cb_tab[3][256];
+ unsigned char *cp = rect;
+ unsigned char *e = cp + width * 4 * height;
+ unsigned char *m = mask_rect;
+
+ StripColorBalance cb = calc_cb(cb_);
+
+ while (cp < e) {
+ float p[4];
+ int c;
+
+ straight_uchar_to_premul_float(p, cp);
+
+ for (c = 0; c < 3; c++) {
+ float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+
+ if (m) {
+ float m_normal = (float)m[c] / 255.0f;
+
+ p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
+ }
+ else {
+ p[c] = t;
+ }
+ }
+
+ premul_float_to_straight_uchar(cp, p);
+
+ cp += 4;
+ if (m) {
+ m += 4;
+ }
+ }
+}
+
+static void color_balance_byte_float(StripColorBalance *cb_,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ int width,
+ int height,
+ float mul)
+{
+ float cb_tab[4][256];
+ int c, i;
+ unsigned char *p = rect;
+ unsigned char *e = p + width * 4 * height;
+ unsigned char *m = mask_rect;
+ float *o;
+ StripColorBalance cb;
+
+ o = rect_float;
+
+ cb = calc_cb(cb_);
+
+ for (c = 0; c < 3; c++) {
+ make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
+ }
+
+ for (i = 0; i < 256; i++) {
+ cb_tab[3][i] = ((float)i) * (1.0f / 255.0f);
+ }
+
+ while (p < e) {
+ if (m) {
+ const float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f};
+
+ p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]];
+ p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]];
+ p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]];
+
+ m += 4;
+ }
+ else {
+ o[0] = cb_tab[0][p[0]];
+ o[1] = cb_tab[1][p[1]];
+ o[2] = cb_tab[2][p[2]];
+ }
+
+ o[3] = cb_tab[3][p[3]];
+
+ p += 4;
+ o += 4;
+ }
+}
+
+static void color_balance_float_float(StripColorBalance *cb_,
+ float *rect_float,
+ const float *mask_rect_float,
+ int width,
+ int height,
+ float mul)
+{
+ float *p = rect_float;
+ const float *e = rect_float + width * 4 * height;
+ const float *m = mask_rect_float;
+ StripColorBalance cb = calc_cb(cb_);
+
+ while (p < e) {
+ int c;
+ for (c = 0; c < 3; c++) {
+ float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+
+ if (m) {
+ p[c] = p[c] * (1.0f - m[c]) + t * m[c];
+ }
+ else {
+ p[c] = t;
+ }
+ }
+
+ p += 4;
+ if (m) {
+ m += 4;
+ }
+ }
+}
+
+typedef struct ColorBalanceInitData {
+ StripColorBalance *cb;
+ ImBuf *ibuf;
+ float mul;
+ ImBuf *mask;
+ bool make_float;
+} ColorBalanceInitData;
+
+typedef struct ColorBalanceThread {
+ StripColorBalance *cb;
+ float mul;
+
+ int width, height;
+
+ unsigned char *rect, *mask_rect;
+ float *rect_float, *mask_rect_float;
+
+ bool make_float;
+} ColorBalanceThread;
+
+static void color_balance_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
+{
+ ColorBalanceThread *handle = (ColorBalanceThread *)handle_v;
+ ColorBalanceInitData *init_data = (ColorBalanceInitData *)init_data_v;
+ ImBuf *ibuf = init_data->ibuf;
+ ImBuf *mask = init_data->mask;
+
+ int offset = 4 * start_line * ibuf->x;
+
+ memset(handle, 0, sizeof(ColorBalanceThread));
+
+ handle->cb = init_data->cb;
+ handle->mul = init_data->mul;
+ handle->width = ibuf->x;
+ handle->height = tot_line;
+ handle->make_float = init_data->make_float;
+
+ if (ibuf->rect) {
+ handle->rect = (unsigned char *)ibuf->rect + offset;
+ }
+
+ if (ibuf->rect_float) {
+ handle->rect_float = ibuf->rect_float + offset;
+ }
+
+ if (mask) {
+ if (mask->rect) {
+ handle->mask_rect = (unsigned char *)mask->rect + offset;
+ }
+
+ if (mask->rect_float) {
+ handle->mask_rect_float = mask->rect_float + offset;
+ }
+ }
+ else {
+ handle->mask_rect = NULL;
+ handle->mask_rect_float = NULL;
+ }
+}
+
+static void *color_balance_do_thread(void *thread_data_v)
+{
+ ColorBalanceThread *thread_data = (ColorBalanceThread *)thread_data_v;
+ StripColorBalance *cb = thread_data->cb;
+ int width = thread_data->width, height = thread_data->height;
+ unsigned char *rect = thread_data->rect;
+ unsigned char *mask_rect = thread_data->mask_rect;
+ float *rect_float = thread_data->rect_float;
+ float *mask_rect_float = thread_data->mask_rect_float;
+ float mul = thread_data->mul;
+
+ if (rect_float) {
+ color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
+ }
+ else if (thread_data->make_float) {
+ color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
+ }
+ else {
+ color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
+ }
+
+ return NULL;
+}
+
static void colorBalance_init_data(SequenceModifierData *smd)
{
ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
@@ -188,11 +513,41 @@ static void colorBalance_init_data(SequenceModifierData *smd)
}
}
+static void modifier_color_balance_apply(
+ StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
+{
+ ColorBalanceInitData init_data;
+
+ if (!ibuf->rect_float && make_float) {
+ imb_addrectfloatImBuf(ibuf);
+ }
+
+ init_data.cb = cb;
+ init_data.ibuf = ibuf;
+ init_data.mul = mul;
+ init_data.make_float = make_float;
+ init_data.mask = mask_input;
+
+ IMB_processor_apply_threaded(ibuf->y,
+ sizeof(ColorBalanceThread),
+ &init_data,
+ color_balance_init_handle,
+ color_balance_do_thread);
+
+ /* color balance either happens on float buffer or byte buffer, but never on both,
+ * free byte buffer if there's float buffer since float buffer would be used for
+ * color balance in favor of byte buffer
+ */
+ if (ibuf->rect_float && ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+}
+
static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
- BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
+ modifier_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
}
static SequenceModifierTypeInfo seqModifier_ColorBalance = {
@@ -1100,7 +1455,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context,
}
if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
+ seq_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
}
return processed_ibuf;
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 3ea3b6f1ac7..cc4c335f9af 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -55,6 +55,7 @@
#include "SEQ_sequencer.h"
+#include "render.h"
#include "sequencer.h"
typedef struct PrefetchJob {
@@ -361,7 +362,7 @@ static bool seq_prefetch_do_skip_frame(Scene *scene)
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
float cfra = seq_prefetch_cfra(pfjob);
Sequence *seq_arr[MAXSEQ + 1];
- int count = BKE_sequencer_get_shown_sequences(ed->seqbasep, cfra, 0, seq_arr);
+ int count = seq_get_shown_sequences(ed->seqbasep, cfra, 0, seq_arr);
SeqRenderData *ctx = &pfjob->context_cpy;
ImBuf *ibuf = NULL;
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
new file mode 100644
index 00000000000..caa0ecb4ad7
--- /dev/null
+++ b/source/blender/sequencer/intern/proxy.c
@@ -0,0 +1,570 @@
+/*
+ * 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_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#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 "proxy.h"
+#include "render.h"
+#include "sequencer.h"
+
+typedef struct SeqIndexBuildContext {
+ struct IndexBuildContext *index_context;
+
+ int tc_flags;
+ int size_flags;
+ int quality;
+ bool overwrite;
+ int view_id;
+
+ Main *bmain;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Sequence *seq, *orig_seq;
+} SeqIndexBuildContext;
+
+int SEQ_rendersize_to_proxysize(int render_size)
+{
+ switch (render_size) {
+ case SEQ_RENDER_SIZE_PROXY_25:
+ return IMB_PROXY_25;
+ case SEQ_RENDER_SIZE_PROXY_50:
+ return IMB_PROXY_50;
+ case SEQ_RENDER_SIZE_PROXY_75:
+ return IMB_PROXY_75;
+ case SEQ_RENDER_SIZE_PROXY_100:
+ return IMB_PROXY_100;
+ }
+ return IMB_PROXY_NONE;
+}
+
+double BKE_sequencer_rendersize_to_scale_factor(int render_size)
+{
+ switch (render_size) {
+ case SEQ_RENDER_SIZE_PROXY_25:
+ return 0.25;
+ case SEQ_RENDER_SIZE_PROXY_50:
+ return 0.50;
+ case SEQ_RENDER_SIZE_PROXY_75:
+ return 0.75;
+ }
+ return 1.0;
+}
+
+bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_id)
+{
+ char fname[FILE_MAXFILE];
+ char suffix[24];
+ StripProxy *proxy = seq->strip->proxy;
+
+ if (proxy == NULL) {
+ return false;
+ }
+
+ BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file);
+ BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
+
+ if (view_id > 0) {
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
+ /* TODO(sergey): This will actually append suffix after extension
+ * which is weird but how was originally coded in multi-view branch.
+ */
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
+ }
+ else {
+ BLI_strncpy(name, fname, PROXY_MAXFILE);
+ }
+
+ return true;
+}
+
+static bool seq_proxy_get_fname(Editing *ed,
+ Sequence *seq,
+ int cfra,
+ eSpaceSeq_Proxy_RenderSize render_size,
+ char *name,
+ const int view_id)
+{
+ char dir[PROXY_MAXFILE];
+ char suffix[24] = {'\0'};
+ StripProxy *proxy = seq->strip->proxy;
+
+ if (proxy == NULL) {
+ return false;
+ }
+
+ /* Multi-view suffix. */
+ if (view_id > 0) {
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
+ }
+
+ /* Per strip with Custom file situation is handled separately. */
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
+ ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (seq_proxy_get_custom_file_fname(seq, name, view_id)) {
+ return true;
+ }
+ }
+
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ /* Per project default. */
+ if (ed->proxy_dir[0] == 0) {
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ }
+ else { /* Per project with custom dir. */
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+ }
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ }
+ else {
+ /* Pre strip with custom dir. */
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ else { /* Per strip default. */
+ BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
+ }
+ }
+
+ /* Proxy size number to be used in path. */
+ int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100;
+
+ BLI_snprintf(name,
+ PROXY_MAXFILE,
+ "%s/images/%d/%s_proxy%s",
+ dir,
+ proxy_size_number,
+ BKE_sequencer_give_stripelem(seq, cfra)->name,
+ suffix);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ strcat(name, ".jpg");
+
+ return true;
+}
+
+bool SEQ_can_use_proxy(Sequence *seq, int psize)
+{
+ if (seq->strip->proxy == NULL) {
+ return false;
+ }
+ short size_flags = seq->strip->proxy->build_size_flags;
+ return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0;
+}
+
+ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
+{
+ char name[PROXY_MAXFILE];
+ StripProxy *proxy = seq->strip->proxy;
+ const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
+ Editing *ed = context->scene->ed;
+ StripAnim *sanim;
+
+ /* only use proxies, if they are enabled (even if present!) */
+ if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(psize))) {
+ return NULL;
+ }
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ int frameno = (int)seq_give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ if (proxy->anim == NULL) {
+ if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
+ return NULL;
+ }
+
+ proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
+ }
+ if (proxy->anim == NULL) {
+ return NULL;
+ }
+
+ seq_open_anim_file(context->scene, seq, true);
+ sanim = seq->anims.first;
+
+ frameno = IMB_anim_index_get_frame_index(
+ sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
+
+ return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
+ }
+
+ if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
+ return NULL;
+ }
+
+ if (BLI_exists(name)) {
+ ImBuf *ibuf = IMB_loadiffname(name, IB_rect, NULL);
+
+ if (ibuf) {
+ seq_imbuf_assign_spaces(context->scene, ibuf);
+ }
+
+ return ibuf;
+ }
+
+ return NULL;
+}
+
+static void seq_proxy_build_frame(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ int cfra,
+ int proxy_render_size,
+ const bool overwrite)
+{
+ char name[PROXY_MAXFILE];
+ int quality;
+ int rectx, recty;
+ int ok;
+ ImBuf *ibuf_tmp, *ibuf;
+ Editing *ed = context->scene->ed;
+
+ if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
+ return;
+ }
+
+ if (!overwrite && BLI_exists(name)) {
+ return;
+ }
+
+ ibuf_tmp = seq_render_strip(context, state, seq, cfra);
+
+ rectx = (proxy_render_size * ibuf_tmp->x) / 100;
+ recty = (proxy_render_size * ibuf_tmp->y) / 100;
+
+ if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
+ ibuf = IMB_dupImBuf(ibuf_tmp);
+ IMB_metadata_copy(ibuf, ibuf_tmp);
+ IMB_freeImBuf(ibuf_tmp);
+ IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
+ }
+ else {
+ ibuf = ibuf_tmp;
+ }
+
+ /* depth = 32 is intentionally left in, otherwise ALPHA channels
+ * won't work... */
+ quality = seq->strip->proxy->quality;
+ ibuf->ftype = IMB_FTYPE_JPG;
+ ibuf->foptions.quality = quality;
+
+ /* unsupported feature only confuses other s/w */
+ if (ibuf->planes == 32) {
+ ibuf->planes = 24;
+ }
+
+ BLI_make_existing_file(name);
+
+ ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
+ if (ok == 0) {
+ perror(name);
+ }
+
+ IMB_freeImBuf(ibuf);
+}
+
+/**
+ * Returns whether the file this context would read from even exist,
+ * if not, don't create the context
+ */
+static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
+{
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ return false;
+ }
+
+ if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ static char prefix[FILE_MAX];
+ static const char *ext = NULL;
+ char str[FILE_MAX];
+
+ if (view_id == 0) {
+ char path[FILE_MAX];
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ if (prefix[0] == '\0') {
+ return view_id != 0;
+ }
+
+ seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
+
+ if (BLI_access(str, R_OK) == 0) {
+ return false;
+ }
+
+ return view_id != 0;
+ }
+ return false;
+}
+
+/**
+ * This returns the maximum possible number of required contexts
+ */
+static int seq_proxy_context_count(Sequence *seq, Scene *scene)
+{
+ int num_views = 1;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ return 1;
+ }
+
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE: {
+ num_views = BLI_listbase_count(&seq->anims);
+ break;
+ }
+ case SEQ_TYPE_IMAGE: {
+ switch (seq->views_format) {
+ case R_IMF_VIEWS_INDIVIDUAL:
+ num_views = BKE_scene_multiview_num_views_get(&scene->r);
+ break;
+ case R_IMF_VIEWS_STEREO_3D:
+ num_views = 2;
+ break;
+ case R_IMF_VIEWS_MULTIVIEW:
+ /* not supported at the moment */
+ /* pass through */
+ default:
+ num_views = 1;
+ }
+ break;
+ }
+ }
+
+ return num_views;
+}
+
+bool BKE_sequencer_proxy_rebuild_context(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Sequence *seq,
+ struct GSet *file_list,
+ ListBase *queue)
+{
+ SeqIndexBuildContext *context;
+ Sequence *nseq;
+ LinkData *link;
+ int num_files;
+ int i;
+
+ if (!seq->strip || !seq->strip->proxy) {
+ return true;
+ }
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return true;
+ }
+
+ num_files = seq_proxy_context_count(seq, scene);
+
+ for (i = 0; i < num_files; i++) {
+ if (seq_proxy_multiview_context_invalid(seq, scene, i)) {
+ continue;
+ }
+
+ context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+
+ nseq = BKE_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
+
+ context->tc_flags = nseq->strip->proxy->build_tc_flags;
+ context->size_flags = nseq->strip->proxy->build_size_flags;
+ context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
+
+ context->bmain = bmain;
+ context->depsgraph = depsgraph;
+ context->scene = scene;
+ context->orig_seq = seq;
+ context->seq = nseq;
+
+ context->view_id = i; /* only for images */
+
+ if (nseq->type == SEQ_TYPE_MOVIE) {
+ StripAnim *sanim;
+
+ seq_open_anim_file(scene, nseq, true);
+ sanim = BLI_findlink(&nseq->anims, i);
+
+ if (sanim->anim) {
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags,
+ context->size_flags,
+ context->quality,
+ context->overwrite,
+ file_list);
+ }
+ if (!context->index_context) {
+ MEM_freeN(context);
+ return false;
+ }
+ }
+
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
+ }
+ return true;
+}
+
+void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ const bool overwrite = context->overwrite;
+ SeqRenderData render_context;
+ Sequence *seq = context->seq;
+ Scene *scene = context->scene;
+ Main *bmain = context->bmain;
+ int cfra;
+
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ if (context->index_context) {
+ IMB_anim_index_rebuild(context->index_context, stop, do_update, progress);
+ }
+
+ return;
+ }
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return;
+ }
+
+ /* that's why it is called custom... */
+ if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ return;
+ }
+
+ /* fail safe code */
+
+ BKE_sequencer_new_render_data(bmain,
+ context->depsgraph,
+ context->scene,
+ roundf((scene->r.size * (float)scene->r.xsch) / 100.0f),
+ roundf((scene->r.size * (float)scene->r.ysch) / 100.0f),
+ 100,
+ false,
+ &render_context);
+
+ render_context.skip_cache = true;
+ render_context.is_proxy_render = true;
+ render_context.view_id = context->view_id;
+
+ SeqRenderState state;
+ seq_render_state_init(&state);
+
+ for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
+ if (context->size_flags & IMB_PROXY_25) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 25, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_50) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 50, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_75) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 75, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_100) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 100, overwrite);
+ }
+
+ *progress = (float)(cfra - seq->startdisp - seq->startstill) /
+ (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
+ *do_update = true;
+
+ if (*stop || G.is_break) {
+ break;
+ }
+ }
+}
+
+void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
+{
+ if (context->index_context) {
+ StripAnim *sanim;
+
+ for (sanim = context->seq->anims.first; sanim; sanim = sanim->next) {
+ IMB_close_anim_proxies(sanim->anim);
+ }
+
+ for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) {
+ IMB_close_anim_proxies(sanim->anim);
+ }
+
+ IMB_anim_index_rebuild_finish(context->index_context, stop);
+ }
+
+ seq_free_sequence_recurse(NULL, context->seq, true);
+
+ MEM_freeN(context);
+}
+
+void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
+{
+ if (value) {
+ seq->flag |= SEQ_USE_PROXY;
+ if (seq->strip->proxy == NULL) {
+ seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
+ seq->strip->proxy->quality = 90;
+ seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
+ seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
+ }
+ }
+ else {
+ seq->flag &= ~SEQ_USE_PROXY;
+ }
+}
diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h
new file mode 100644
index 00000000000..ed23db1a826
--- /dev/null
+++ b/source/blender/sequencer/intern/proxy.h
@@ -0,0 +1,40 @@
+/*
+ * 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 SeqRenderData;
+struct ImBuf;
+struct Sequence;
+
+#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
+struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context, struct Sequence *seq, int cfra);
+bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, const int view_id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
new file mode 100644
index 00000000000..d59fdabe504
--- /dev/null
+++ b/source/blender/sequencer/intern/render.c
@@ -0,0 +1,2106 @@
+/*
+ * 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 <time.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.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_scene.h"
+#include "BKE_sequencer_offscreen.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
+
+#include "RNA_access.h"
+
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+#include "SEQ_sequencer.h"
+
+#include "proxy.h"
+#include "render.h"
+#include "sequencer.h"
+
+static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
+ SeqRenderState *state,
+ ListBase *seqbasep,
+ float cfra,
+ int chanshown);
+
+static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
+SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
+
+/* -------------------------------------------------------------------- */
+/** \name Colorspace utility functions
+ * \{ */
+void seq_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
+{
+#if 0
+ /* Bute buffer is supposed to be in sequencer working space already. */
+ if (ibuf->rect != NULL) {
+ IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
+#endif
+ if (ibuf->rect_float != NULL) {
+ IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
+}
+
+void seq_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
+{
+ /* Early output check: if both buffers are NULL we have nothing to convert. */
+ if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
+ return;
+ }
+ /* Get common conversion settings. */
+ const char *to_colorspace = scene->sequencer_colorspace_settings.name;
+ /* Perform actual conversion logic. */
+ if (ibuf->rect_float == NULL) {
+ /* We are not requested to give float buffer and byte buffer is already
+ * in thee required colorspace. Can skip doing anything here.
+ */
+ const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
+ if (!make_float && STREQ(from_colorspace, to_colorspace)) {
+ return;
+ }
+ if (false) {
+ /* The idea here is to provide as fast playback as possible and
+ * enforcing float buffer here (a) uses more cache memory (b) might
+ * make some other effects slower to apply.
+ *
+ * However, this might also have negative effect by adding weird
+ * artifacts which will then not happen in final render.
+ */
+ IMB_colormanagement_transform_byte_threaded((unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ }
+ else {
+ /* We perform conversion to a float buffer so we don't worry about
+ * precision loss.
+ */
+ imb_addrectfloatImBuf(ibuf);
+ IMB_colormanagement_transform_from_byte_threaded(ibuf->rect_float,
+ (unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ /* We don't need byte buffer anymore. */
+ imb_freerectImBuf(ibuf);
+ }
+ }
+ else {
+ const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
+ /* Unknown input color space, can't perform conversion. */
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ /* We don't want both byte and float buffers around: they'll either run
+ * out of sync or conversion of byte buffer will lose precision in there.
+ */
+ if (ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+ IMB_colormanagement_transform_threaded(
+ ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
+ }
+ seq_imbuf_assign_spaces(scene, ibuf);
+}
+
+void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
+{
+ const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+
+ if (!ibuf->rect_float) {
+ return;
+ }
+
+ if (to_colorspace && to_colorspace[0] != '\0') {
+ IMB_colormanagement_transform_threaded(
+ ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
+ IMB_colormanagement_assign_float_colorspace(ibuf, to_colorspace);
+ }
+}
+
+void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4])
+{
+ const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+
+ if (to_colorspace && to_colorspace[0] != '\0') {
+ IMB_colormanagement_transform_v4(pixel, from_colorspace, to_colorspace);
+ }
+ else {
+ /* if no color management enables fallback to legacy conversion */
+ srgb_to_linearrgb_v4(pixel, pixel);
+ }
+}
+
+void BKE_sequence_init_colorspace(Sequence *seq)
+{
+ if (seq->strip && seq->strip->stripdata) {
+ char name[FILE_MAX];
+ ImBuf *ibuf;
+
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+
+ /* initialize input color space */
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ ibuf = IMB_loadiffname(
+ name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name);
+
+ /* byte images are default to straight alpha, however sequencer
+ * works in premul space, so mark strip to be premultiplied first
+ */
+ seq->alpha_mode = SEQ_ALPHA_STRAIGHT;
+ if (ibuf) {
+ if (ibuf->flags & IB_alphamode_premul) {
+ seq->alpha_mode = IMA_ALPHA_PREMUL;
+ }
+
+ IMB_freeImBuf(ibuf);
+ }
+ }
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rendering utility functions
+ * \{ */
+void BKE_sequencer_new_render_data(Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ int rectx,
+ int recty,
+ int preview_render_size,
+ int for_render,
+ SeqRenderData *r_context)
+{
+ r_context->bmain = bmain;
+ r_context->depsgraph = depsgraph;
+ r_context->scene = scene;
+ r_context->rectx = rectx;
+ r_context->recty = recty;
+ r_context->preview_render_size = preview_render_size;
+ r_context->for_render = for_render;
+ r_context->motion_blur_samples = 0;
+ r_context->motion_blur_shutter = 0;
+ r_context->skip_cache = false;
+ r_context->is_proxy_render = false;
+ r_context->view_id = 0;
+ r_context->gpu_offscreen = NULL;
+ r_context->task_id = SEQ_TASK_MAIN_RENDER;
+ r_context->is_prefetch_render = false;
+}
+
+void seq_render_state_init(SeqRenderState *state)
+{
+ state->scene_parents = NULL;
+}
+
+float seq_give_stripelem_index(Sequence *seq, float cfra)
+{
+ float nr;
+ 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 (cfra <= sta) {
+ nr = end - sta;
+ }
+ else if (cfra >= end) {
+ nr = 0;
+ }
+ else {
+ nr = end - cfra;
+ }
+ }
+ else {
+ if (cfra <= sta) {
+ nr = 0;
+ }
+ else if (cfra >= end) {
+ nr = end - sta;
+ }
+ else {
+ nr = cfra - sta;
+ }
+ }
+
+ if (seq->strobe < 1.0f) {
+ seq->strobe = 1.0f;
+ }
+
+ if (seq->strobe > 1.0f) {
+ nr -= fmodf((double)nr, (double)seq->strobe);
+ }
+
+ return nr;
+}
+
+StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
+{
+ StripElem *se = seq->strip->stripdata;
+
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ /* only IMAGE strips use the whole array, MOVIE strips use only the first element,
+ * all other strips don't use this...
+ */
+
+ int nr = (int)seq_give_stripelem_index(seq, cfra);
+
+ if (nr == -1 || se == NULL) {
+ return NULL;
+ }
+
+ se += nr + seq->anim_startofs;
+ }
+ return se;
+}
+
+static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown)
+{
+ /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
+ LinkNodePair effect_inputs = {NULL, NULL};
+ int totseq = 0;
+
+ memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
+
+ if (seq->seq1) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
+ }
+
+ if (seq->seq2) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
+ }
+
+ if (seq->seq3) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
+ }
+ }
+
+ seq_arr[seq->machine] = seq;
+ totseq++;
+ }
+ }
+
+ /* Drop strips which are used for effect inputs, we don't want
+ * them to blend into render stack in any other way than effect
+ * string rendering. */
+ for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
+ Sequence *seq = seq_item->link;
+ /* It's possible that effect strip would be placed to the same
+ * 'machine' as its inputs. We don't want to clear such strips
+ * from the stack. */
+ if (seq_arr[seq->machine] && seq_arr[seq->machine]->type & SEQ_TYPE_EFFECT) {
+ continue;
+ }
+ /* If we're shown a specified channel, then we want to see the strips
+ * which belongs to this machine. */
+ if (chanshown != 0 && chanshown <= seq->machine) {
+ continue;
+ }
+ seq_arr[seq->machine] = NULL;
+ }
+
+ return totseq;
+}
+
+int BKE_sequencer_evaluate_frame(Scene *scene, int cfra)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq_arr[MAXSEQ + 1];
+
+ if (ed == NULL) {
+ return 0;
+ }
+
+ return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra, 0);
+}
+
+static bool video_seq_is_rendered(Sequence *seq)
+{
+ return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
+}
+
+int seq_get_shown_sequences(ListBase *seqbasep, int cfra, int chanshown, Sequence **seq_arr_out)
+{
+ Sequence *seq_arr[MAXSEQ + 1];
+ int b = chanshown;
+ int cnt = 0;
+
+ if (b > MAXSEQ) {
+ return 0;
+ }
+
+ if (evaluate_seq_frame_gen(seq_arr, seqbasep, cfra, chanshown)) {
+ if (b == 0) {
+ b = MAXSEQ;
+ }
+ for (; b > 0; b--) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ break;
+ }
+ }
+ }
+
+ chanshown = b;
+
+ for (; b > 0; b--) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) {
+ break;
+ }
+ }
+ }
+
+ for (; b <= chanshown && b >= 0; b++) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ seq_arr_out[cnt++] = seq_arr[b];
+ }
+ }
+
+ return cnt;
+}
+
+/* Estimate time spent by the program rendering the strip */
+static clock_t seq_estimate_render_cost_begin(void)
+{
+ return clock();
+}
+
+static float seq_estimate_render_cost_end(Scene *scene, clock_t begin)
+{
+ clock_t end = clock();
+ float time_spent = (float)(end - begin);
+ float time_max = (1.0f / scene->r.frs_sec) * CLOCKS_PER_SEC;
+
+ if (time_max != 0) {
+ return time_spent / time_max;
+ }
+
+ return 1;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preprocessing and effects
+ * \{ */
+/*
+ * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE
+ *
+ * Do all the things you can't really do afterwards using sequence effects
+ * (read: before rescaling to render resolution has been done)
+ *
+ * Order is important!
+ *
+ * - Deinterlace
+ * - Crop and transform in image source coordinate space
+ * - Flip X + Flip Y (could be done afterwards, backward compatibility)
+ * - Promote image to float data (affects pipeline operations afterwards)
+ * - Color balance (is most efficient in the byte -> float
+ * (future: half -> float should also work fine!)
+ * case, if done on load, since we can use lookup tables)
+ * - Premultiply
+ */
+
+static bool sequencer_use_transform(const Sequence *seq)
+{
+ const StripTransform *transform = seq->strip->transform;
+
+ if (transform->xofs != 0 || transform->yofs != 0 || transform->scale_x != 1 ||
+ transform->scale_y != 1 || transform->rotation != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool sequencer_use_crop(const Sequence *seq)
+{
+ const StripCrop *crop = seq->strip->crop;
+ if (crop->left > 0 || crop->right > 0 || crop->top > 0 || crop->bottom > 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra))
+{
+ float mul;
+
+ if (context && context->is_proxy_render) {
+ return false;
+ }
+
+ if ((seq->flag & (SEQ_FILTERY | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) ||
+ sequencer_use_crop(seq) || sequencer_use_transform(seq)) {
+ return true;
+ }
+
+ mul = seq->mul;
+
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ mul *= seq->blend_opacity / 100.0f;
+ }
+
+ if (mul != 1.0f) {
+ return true;
+ }
+
+ if (seq->sat != 1.0f) {
+ return true;
+ }
+
+ if (seq->modifiers.first) {
+ return true;
+ }
+
+ return false;
+}
+
+typedef struct ImageTransformThreadInitData {
+ ImBuf *ibuf_source;
+ ImBuf *ibuf_out;
+ StripTransform *transform;
+ float scale_to_fit;
+ float image_scale_factor;
+ bool for_render;
+} ImageTransformThreadInitData;
+
+typedef struct ImageTransformThreadData {
+ ImBuf *ibuf_source;
+ ImBuf *ibuf_out;
+ StripTransform *transform;
+ float scale_to_fit;
+ float image_scale_factor;
+ bool for_render;
+ int start_line;
+ int tot_line;
+} ImageTransformThreadData;
+
+static void sequencer_image_transform_init(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
+{
+ ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v;
+ const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v;
+
+ handle->ibuf_source = init_data->ibuf_source;
+ handle->ibuf_out = init_data->ibuf_out;
+ handle->transform = init_data->transform;
+ handle->scale_to_fit = init_data->scale_to_fit;
+ handle->image_scale_factor = init_data->image_scale_factor;
+ handle->for_render = init_data->for_render;
+
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
+}
+
+static void *sequencer_image_transform_do_thread(void *data_v)
+{
+ const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v;
+ const StripTransform *transform = data->transform;
+ const float scale_x = transform->scale_x * data->scale_to_fit;
+ const float scale_y = transform->scale_y * data->scale_to_fit;
+ const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
+ const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2;
+ const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x;
+ const float translate_y = transform->yofs * data->image_scale_factor + scale_to_fit_offs_y;
+ const int width = data->ibuf_out->x;
+ const int height = data->ibuf_out->y;
+ const float pivot[2] = {width / 2 - scale_to_fit_offs_x, height / 2 - scale_to_fit_offs_y};
+ float transform_matrix[3][3];
+ loc_rot_size_to_mat3(transform_matrix,
+ (const float[]){translate_x, translate_y},
+ transform->rotation,
+ (const float[]){scale_x, scale_y});
+ invert_m3(transform_matrix);
+ transform_pivot_set_m3(transform_matrix, pivot);
+
+ for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) {
+ for (int xi = 0; xi < width; xi++) {
+ float uv[2] = {xi, yi};
+ mul_v2_m3v2(uv, transform_matrix, uv);
+
+ if (data->for_render) {
+ bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
+ }
+ else {
+ nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void multibuf(ImBuf *ibuf, const float fmul)
+{
+ char *rt;
+ float *rt_float;
+
+ int a;
+
+ rt = (char *)ibuf->rect;
+ rt_float = ibuf->rect_float;
+
+ if (rt) {
+ const int imul = (int)(256.0f * fmul);
+ a = ibuf->x * ibuf->y;
+ while (a--) {
+ rt[0] = min_ii((imul * rt[0]) >> 8, 255);
+ rt[1] = min_ii((imul * rt[1]) >> 8, 255);
+ rt[2] = min_ii((imul * rt[2]) >> 8, 255);
+ rt[3] = min_ii((imul * rt[3]) >> 8, 255);
+
+ rt += 4;
+ }
+ }
+ if (rt_float) {
+ a = ibuf->x * ibuf->y;
+ while (a--) {
+ rt_float[0] *= fmul;
+ rt_float[1] *= fmul;
+ rt_float[2] *= fmul;
+ rt_float[3] *= fmul;
+
+ rt_float += 4;
+ }
+ }
+}
+
+static ImBuf *input_preprocess(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ ImBuf *ibuf,
+ const bool UNUSED(is_proxy_image))
+{
+ Scene *scene = context->scene;
+ ImBuf *preprocessed_ibuf = NULL;
+
+ /* Deinterlace. */
+ if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
+ /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
+ ibuf = preprocessed_ibuf;
+
+ IMB_filtery(preprocessed_ibuf);
+ }
+
+ /* Calculate scale factor, so image fits in preview area with original aspect ratio. */
+ const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x,
+ (float)context->recty / (float)ibuf->y);
+
+ /* Get scale factor if preview resolution doesn't match project resolution. */
+ float preview_scale_factor;
+ if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
+ preview_scale_factor = (float)scene->r.size / 100;
+ }
+ else {
+ preview_scale_factor = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
+ }
+
+ if (sequencer_use_crop(seq)) {
+ /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
+ ibuf = preprocessed_ibuf;
+
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ const StripCrop *c = seq->strip->crop;
+
+ const int left = c->left / scale_to_fit_factor * preview_scale_factor;
+ const int right = c->right / scale_to_fit_factor * preview_scale_factor;
+ const int top = c->top / scale_to_fit_factor * preview_scale_factor;
+ const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor;
+ const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* Left. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, 0, 0, left, height);
+ /* Bottom. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, left, 0, width, bottom);
+ /* Right. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, width - right, bottom, width, height);
+ /* Top. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, left, height - top, width - right, height);
+ }
+
+ if (sequencer_use_transform(seq) || context->rectx != ibuf->x || context->recty != ibuf->y) {
+ const int x = context->rectx;
+ const int y = context->recty;
+ preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ ImageTransformThreadInitData init_data = {NULL};
+ init_data.ibuf_source = ibuf;
+ init_data.ibuf_out = preprocessed_ibuf;
+ init_data.transform = seq->strip->transform;
+ init_data.scale_to_fit = scale_to_fit_factor;
+ init_data.image_scale_factor = preview_scale_factor;
+ init_data.for_render = context->for_render;
+ IMB_processor_apply_threaded(context->recty,
+ sizeof(ImageTransformThreadData),
+ &init_data,
+ sequencer_image_transform_init,
+ sequencer_image_transform_do_thread);
+ seq_imbuf_assign_spaces(scene, preprocessed_ibuf);
+ IMB_metadata_copy(preprocessed_ibuf, ibuf);
+ IMB_freeImBuf(ibuf);
+ }
+
+ /* Duplicate ibuf if we still have original. */
+ if (preprocessed_ibuf == NULL) {
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
+ }
+
+ if (seq->flag & SEQ_FLIPX) {
+ IMB_flipx(preprocessed_ibuf);
+ }
+
+ if (seq->flag & SEQ_FLIPY) {
+ IMB_flipy(preprocessed_ibuf);
+ }
+
+ if (seq->sat != 1.0f) {
+ IMB_saturation(preprocessed_ibuf, seq->sat);
+ }
+
+ if (seq->flag & SEQ_MAKE_FLOAT) {
+ if (!preprocessed_ibuf->rect_float) {
+ seq_imbuf_to_sequencer_space(scene, preprocessed_ibuf, true);
+ }
+
+ if (preprocessed_ibuf->rect) {
+ imb_freerectImBuf(preprocessed_ibuf);
+ }
+ }
+
+ float mul = seq->mul;
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ mul *= seq->blend_opacity / 100.0f;
+ }
+
+ if (mul != 1.0f) {
+ multibuf(preprocessed_ibuf, mul);
+ }
+
+ if (seq->modifiers.first) {
+ ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, preprocessed_ibuf, cfra);
+
+ if (ibuf_new != preprocessed_ibuf) {
+ IMB_metadata_copy(ibuf_new, preprocessed_ibuf);
+ IMB_freeImBuf(preprocessed_ibuf);
+ preprocessed_ibuf = ibuf_new;
+ }
+ }
+
+ return preprocessed_ibuf;
+}
+
+static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ float cfra,
+ clock_t begin,
+ bool use_preprocess,
+ const bool is_proxy_image)
+{
+ if (context->is_proxy_render == false &&
+ (ibuf->x != context->rectx || ibuf->y != context->recty)) {
+ use_preprocess = true;
+ }
+
+ if (use_preprocess) {
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+
+ /* TODO(Richard): It should be possible to store in cache if image is proxy,
+ * but it adds quite a bit of complexity. Since proxies are fast to read, I would
+ * rather simplify existing code a bit. */
+ if (!is_proxy_image) {
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
+ }
+
+ /* Reset timer so we can get partial render time. */
+ begin = seq_estimate_render_cost_begin();
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image);
+ }
+
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
+ return ibuf;
+}
+
+typedef struct RenderEffectInitData {
+ struct SeqEffectHandle *sh;
+ const SeqRenderData *context;
+ Sequence *seq;
+ float cfra, facf0, facf1;
+ ImBuf *ibuf1, *ibuf2, *ibuf3;
+
+ ImBuf *out;
+} RenderEffectInitData;
+
+typedef struct RenderEffectThread {
+ struct SeqEffectHandle *sh;
+ const SeqRenderData *context;
+ Sequence *seq;
+ float cfra, facf0, facf1;
+ ImBuf *ibuf1, *ibuf2, *ibuf3;
+
+ ImBuf *out;
+ int start_line, tot_line;
+} RenderEffectThread;
+
+static void render_effect_execute_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
+{
+ RenderEffectThread *handle = (RenderEffectThread *)handle_v;
+ RenderEffectInitData *init_data = (RenderEffectInitData *)init_data_v;
+
+ handle->sh = init_data->sh;
+ handle->context = init_data->context;
+ handle->seq = init_data->seq;
+ handle->cfra = init_data->cfra;
+ handle->facf0 = init_data->facf0;
+ handle->facf1 = init_data->facf1;
+ handle->ibuf1 = init_data->ibuf1;
+ handle->ibuf2 = init_data->ibuf2;
+ handle->ibuf3 = init_data->ibuf3;
+ handle->out = init_data->out;
+
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
+}
+
+static void *render_effect_execute_do_thread(void *thread_data_v)
+{
+ RenderEffectThread *thread_data = (RenderEffectThread *)thread_data_v;
+
+ thread_data->sh->execute_slice(thread_data->context,
+ thread_data->seq,
+ thread_data->cfra,
+ thread_data->facf0,
+ thread_data->facf1,
+ thread_data->ibuf1,
+ thread_data->ibuf2,
+ thread_data->ibuf3,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
+
+ return NULL;
+}
+
+ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ RenderEffectInitData init_data;
+ ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
+
+ init_data.sh = sh;
+ init_data.context = context;
+ init_data.seq = seq;
+ init_data.cfra = cfra;
+ init_data.facf0 = facf0;
+ init_data.facf1 = facf1;
+ init_data.ibuf1 = ibuf1;
+ init_data.ibuf2 = ibuf2;
+ init_data.ibuf3 = ibuf3;
+ init_data.out = out;
+
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_thread);
+
+ return out;
+}
+
+static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra)
+{
+ Scene *scene = context->scene;
+ float fac, facf;
+ int early_out;
+ int i;
+ struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
+ FCurve *fcu = NULL;
+ ImBuf *ibuf[3];
+ Sequence *input[3];
+ ImBuf *out = NULL;
+
+ ibuf[0] = ibuf[1] = ibuf[2] = NULL;
+
+ input[0] = seq->seq1;
+ input[1] = seq->seq2;
+ input[2] = seq->seq3;
+
+ if (!sh.execute && !(sh.execute_slice && sh.init_execution)) {
+ /* effect not supported in this version... */
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ return out;
+ }
+
+ if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ facf = fac;
+ }
+ else {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
+ if (fcu) {
+ fac = facf = evaluate_fcurve(fcu, cfra);
+ }
+ else {
+ fac = facf = seq->effect_fader;
+ }
+ }
+
+ early_out = sh.early_out(seq, fac, facf);
+
+ switch (early_out) {
+ case EARLY_NO_INPUT:
+ out = sh.execute(context, seq, cfra, fac, facf, NULL, NULL, NULL);
+ break;
+ case EARLY_DO_EFFECT:
+ for (i = 0; i < 3; i++) {
+ /* Speed effect requires time remapping of `cfra` for input(s). */
+ if (input[0] && seq->type == SEQ_TYPE_SPEED) {
+ float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i);
+ ibuf[i] = seq_render_strip(context, state, input[0], target_frame);
+ }
+ else { /* Other effects. */
+ if (input[i]) {
+ ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ }
+ }
+ }
+
+ if (ibuf[0] && (ibuf[1] || BKE_sequence_effect_get_num_inputs(seq->type) == 1)) {
+ if (sh.multithreaded) {
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ }
+ else {
+ out = sh.execute(context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ }
+ }
+ break;
+ case EARLY_USE_INPUT_1:
+ if (input[0]) {
+ out = seq_render_strip(context, state, input[0], cfra);
+ }
+ break;
+ case EARLY_USE_INPUT_2:
+ if (input[1]) {
+ out = seq_render_strip(context, state, input[1], cfra);
+ }
+ break;
+ }
+
+ for (i = 0; i < 3; i++) {
+ IMB_freeImBuf(ibuf[i]);
+ }
+
+ if (out == NULL) {
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ }
+
+ return out;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Individual strip rendering functions
+ * \{ */
+/**
+ * Render individual view for multi-view or single (default view) for mono-view.
+ */
+static ImBuf *seq_render_image_strip_view(const SeqRenderData *context,
+ Sequence *seq,
+ char *name,
+ char *prefix,
+ const char *ext,
+ int view_id)
+{
+
+ ImBuf *ibuf = NULL;
+
+ int flag = IB_rect | IB_metadata;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL) {
+ flag |= IB_alphamode_premul;
+ }
+
+ if (prefix[0] == '\0') {
+ ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
+ ibuf = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ /* We don't need both (speed reasons)! */
+ if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ /* All sequencer color is done in SRGB space, linear gives odd cross-fades. */
+ seq_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ return ibuf;
+}
+
+static bool seq_image_strip_is_multiview_render(
+ Scene *scene, Sequence *seq, int totfiles, char *name, char *r_prefix, const char *r_ext)
+{
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(scene, name, r_prefix, &r_ext);
+ if (r_prefix[0] == '\0') {
+ return false;
+ }
+ }
+ else {
+ r_prefix[0] = '\0';
+ }
+
+ return (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
+}
+
+static ImBuf *seq_render_image_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(nr),
+ float cfra,
+ bool *r_is_proxy_image)
+{
+ char name[FILE_MAX];
+ const char *ext = NULL;
+ char prefix[FILE_MAX];
+ ImBuf *ibuf = NULL;
+
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ if (s_elem == NULL) {
+ return NULL;
+ }
+
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+
+ /* Try to get a proxy image. */
+ ibuf = seq_proxy_fetch(context, seq, cfra);
+ if (ibuf != NULL) {
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ *r_is_proxy_image = true;
+ return ibuf;
+ }
+
+ /* Proxy not found, render original. */
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ bool is_multiview_render = seq_image_strip_is_multiview_render(
+ context->scene, seq, totfiles, name, prefix, ext);
+
+ if (is_multiview_render) {
+ int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ImBuf **ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (int view_id = 0; view_id < totfiles; view_id++) {
+ ibufs_arr[view_id] = seq_render_image_strip_view(context, seq, name, prefix, ext, view_id);
+ }
+
+ if (ibufs_arr[0] == NULL) {
+ return NULL;
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
+ }
+
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = view_id;
+
+ if (view_id != context->view_id) {
+ ibufs_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false);
+ }
+ }
+
+ /* Return the original requested ImBuf. */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* Remove the others (decrease their refcount). */
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
+ }
+ }
+
+ MEM_freeN(ibufs_arr);
+ }
+ else {
+ ibuf = seq_render_image_strip_view(context, seq, name, prefix, ext, context->view_id);
+ }
+
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *context,
+ Sequence *seq,
+ int cfra)
+{
+ char name[PROXY_MAXFILE];
+ StripProxy *proxy = seq->strip->proxy;
+
+ if (proxy->anim == NULL) {
+ if (seq_proxy_get_custom_file_fname(seq, name, context->view_id)) {
+ proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
+ }
+ if (proxy->anim == NULL) {
+ return NULL;
+ }
+ }
+
+ int frameno = (int)seq_give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
+}
+
+/**
+ * Render individual view for multi-view or single (default view) for mono-view.
+ */
+static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ float cfra,
+ StripAnim *sanim,
+ bool *r_is_proxy_image)
+{
+ ImBuf *ibuf = NULL;
+ IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
+
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ if (SEQ_can_use_proxy(seq, psize)) {
+ /* Try to get a proxy image.
+ * Movie proxies are handled by ImBuf module with exception of `custom file` setting. */
+ if (context->scene->ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE &&
+ seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ ibuf = seq_render_movie_strip_custom_file_proxy(context, seq, cfra);
+ }
+ else {
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ psize);
+ }
+
+ if (ibuf != NULL) {
+ *r_is_proxy_image = true;
+ }
+ }
+
+ /* Fetching for requested proxy size failed, try fetching the original instead. */
+ if (ibuf == NULL) {
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ seq_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ /* We don't need both (speed reasons)! */
+ if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(
+ const SeqRenderData *context, Sequence *seq, float nr, float cfra, bool *r_is_proxy_image)
+{
+ /* Load all the videos. */
+ seq_open_anim_file(context->scene, seq, false);
+
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim = seq->anims.first;
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ bool is_multiview_render = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0 &&
+ BLI_listbase_count_at_most(&seq->anims, totfiles + 1) == totfiles;
+
+ if (is_multiview_render) {
+ ImBuf **ibuf_arr;
+ int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+ int ibuf_view_id;
+
+ for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) {
+ if (sanim->anim) {
+ ibuf_arr[ibuf_view_id] = seq_render_movie_strip_view(
+ context, seq, nr, cfra, sanim, r_is_proxy_image);
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (ibuf_arr[0] == NULL) {
+ /* Probably proxy hasn't been created yet. */
+ MEM_freeN(ibuf_arr);
+ return NULL;
+ }
+
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = view_id;
+
+ if (view_id != context->view_id) {
+ ibuf_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false);
+ }
+ }
+
+ /* Return the original requested ImBuf. */
+ ibuf = ibuf_arr[context->view_id];
+
+ /* Remove the others (decrease their refcount). */
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibuf_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[view_id]);
+ }
+ }
+
+ MEM_freeN(ibuf_arr);
+ }
+ else {
+ ibuf = seq_render_movie_strip_view(context, seq, nr, cfra, sanim, r_is_proxy_image);
+ }
+
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+
+ return ibuf;
+}
+
+static ImBuf *seq_get_movieclip_ibuf(Sequence *seq, MovieClipUser user)
+{
+ ImBuf *ibuf = NULL;
+ float tloc[2], tscale, tangle;
+ if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
+ ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
+ }
+ else {
+ ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
+ }
+ return ibuf;
+}
+
+static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ bool *r_is_proxy_image)
+{
+ ImBuf *ibuf = NULL;
+ MovieClipUser user;
+ IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
+
+ if (!seq->clip) {
+ return NULL;
+ }
+
+ memset(&user, 0, sizeof(MovieClipUser));
+
+ BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame);
+
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ switch (psize) {
+ case IMB_PROXY_NONE:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ break;
+ case IMB_PROXY_100:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_100;
+ break;
+ case IMB_PROXY_75:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_75;
+ break;
+ case IMB_PROXY_50:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_50;
+ break;
+ case IMB_PROXY_25:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_25;
+ break;
+ }
+
+ if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_UNDISTORTED) {
+ user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT;
+ }
+
+ /* Try to get a proxy image. */
+ ibuf = seq_get_movieclip_ibuf(seq, user);
+
+ if (ibuf != NULL && psize != IMB_PROXY_NONE) {
+ *r_is_proxy_image = true;
+ }
+
+ /* If proxy is not found, grab full-size frame. */
+ if (ibuf == NULL) {
+ user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
+ ibuf = seq_get_movieclip_ibuf(seq, user);
+ }
+
+ return ibuf;
+}
+
+ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float)
+{
+ /* TODO - add option to rasterize to alpha imbuf? */
+ ImBuf *ibuf = NULL;
+ float *maskbuf;
+ int i;
+
+ if (!mask) {
+ return NULL;
+ }
+
+ AnimData *adt;
+ Mask *mask_temp;
+ MaskRasterHandle *mr_handle;
+
+ mask_temp = (Mask *)BKE_id_copy_ex(
+ NULL, &mask->id, NULL, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+
+ BKE_mask_evaluate(mask_temp, mask->sfra + nr, true);
+
+ /* anim-data */
+ adt = BKE_animdata_from_id(&mask->id);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ context->depsgraph, mask->sfra + nr);
+ BKE_animsys_evaluate_animdata(&mask_temp->id, adt, &anim_eval_context, ADT_RECALC_ANIM, false);
+
+ maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
+
+ mr_handle = BKE_maskrasterize_handle_new();
+
+ BKE_maskrasterize_handle_init(
+ mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
+
+ BKE_id_free(NULL, &mask_temp->id);
+
+ BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
+
+ BKE_maskrasterize_handle_free(mr_handle);
+
+ if (make_float) {
+ /* pixels */
+ const float *fp_src;
+ float *fp_dst;
+
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rectfloat);
+
+ fp_src = maskbuf;
+ fp_dst = ibuf->rect_float;
+ i = context->rectx * context->recty;
+ while (--i) {
+ fp_dst[0] = fp_dst[1] = fp_dst[2] = *fp_src;
+ fp_dst[3] = 1.0f;
+
+ fp_src += 1;
+ fp_dst += 4;
+ }
+ }
+ else {
+ /* pixels */
+ const float *fp_src;
+ unsigned char *ub_dst;
+
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+
+ fp_src = maskbuf;
+ ub_dst = (unsigned char *)ibuf->rect;
+ i = context->rectx * context->recty;
+ while (--i) {
+ ub_dst[0] = ub_dst[1] = ub_dst[2] = (unsigned char)(*fp_src * 255.0f); /* already clamped */
+ ub_dst[3] = 255;
+
+ fp_src += 1;
+ ub_dst += 4;
+ }
+ }
+
+ MEM_freeN(maskbuf);
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq, float nr)
+{
+ bool make_float = (seq->flag & SEQ_MAKE_FLOAT) != 0;
+
+ return seq_render_mask(context, seq->mask, nr, make_float);
+}
+
+static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ double frame;
+ Object *camera;
+
+ struct {
+ int scemode;
+ int cfra;
+ float subframe;
+
+#ifdef DURIAN_CAMERA_SWITCH
+ int mode;
+#endif
+ } orig_data;
+
+ /* Old info:
+ * Hack! This function can be called from do_render_seq(), in that case
+ * the seq->scene can already have a Render initialized with same name,
+ * so we have to use a default name. (compositor uses scene name to
+ * find render).
+ * However, when called from within the UI (image preview in sequencer)
+ * we do want to use scene Render, that way the render result is defined
+ * for display in render/imagewindow
+ *
+ * Hmm, don't see, why we can't do that all the time,
+ * and since G.is_rendering is uhm, gone... (Peter)
+ */
+
+ /* New info:
+ * Using the same name for the renders works just fine as the do_render_seq()
+ * render is not used while the scene strips are rendered.
+ *
+ * However rendering from UI (through sequencer_preview_area_draw) can crash in
+ * very many cases since other renders (material preview, an actual render etc.)
+ * can be started while this sequence preview render is running. The only proper
+ * solution is to make the sequencer preview render a proper job, which can be
+ * stopped when needed. This would also give a nice progress bar for the preview
+ * space so that users know there's something happening.
+ *
+ * As a result the active scene now only uses OpenGL rendering for the sequencer
+ * preview. This is far from nice, but is the only way to prevent crashes at this
+ * time.
+ *
+ * -jahka
+ */
+
+ const bool is_rendering = G.is_rendering;
+ const bool is_background = G.background;
+ const bool do_seq_gl = is_rendering ? 0 : (context->scene->r.seq_prev_type) != OB_RENDER;
+ bool have_comp = false;
+ bool use_gpencil = true;
+ /* do we need to re-evaluate the frame after rendering? */
+ bool is_frame_update = false;
+ Scene *scene;
+ int is_thread_main = BLI_thread_is_main();
+
+ /* don't refer to seq->scene above this point!, it can be NULL */
+ if (seq->scene == NULL) {
+ return NULL;
+ }
+
+ /* Prevent rendering scene recursively. */
+ if (seq->scene == context->scene) {
+ return NULL;
+ }
+
+ scene = seq->scene;
+ frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
+
+#if 0 /* UNUSED */
+ have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first);
+#endif
+ have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
+
+ /* Get view layer for the strip. */
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
+
+ orig_data.scemode = scene->r.scemode;
+ orig_data.cfra = scene->r.cfra;
+ orig_data.subframe = scene->r.subframe;
+#ifdef DURIAN_CAMERA_SWITCH
+ orig_data.mode = scene->r.mode;
+#endif
+
+ BKE_scene_frame_set(scene, frame);
+
+ if (seq->scene_camera) {
+ camera = seq->scene_camera;
+ }
+ else {
+ BKE_scene_camera_switch_update(scene);
+ camera = scene->camera;
+ }
+
+ if (have_comp == false && camera == NULL) {
+ goto finally;
+ }
+
+ if (seq->flag & SEQ_SCENE_NO_GPENCIL) {
+ use_gpencil = false;
+ }
+
+ /* prevent eternal loop */
+ scene->r.scemode &= ~R_DOSEQ;
+
+#ifdef DURIAN_CAMERA_SWITCH
+ /* stooping to new low's in hackyness :( */
+ scene->r.mode |= R_NO_CAMERA_SWITCH;
+#endif
+
+ is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
+
+ if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
+ char err_out[256] = "unknown";
+ const int width = (scene->r.xsch * scene->r.size) / 100;
+ const int height = (scene->r.ysch * scene->r.size) / 100;
+ const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
+
+ unsigned int draw_flags = V3D_OFSDRAW_NONE;
+ draw_flags |= (use_gpencil) ? V3D_OFSDRAW_SHOW_ANNOTATION : 0;
+ draw_flags |= (context->scene->r.seq_flag & R_SEQ_OVERRIDE_SCENE_SETTINGS) ?
+ V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS :
+ 0;
+
+ /* for old scene this can be uninitialized,
+ * should probably be added to do_versions at some point if the functionality stays */
+ if (context->scene->r.seq_prev_type == 0) {
+ context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
+ }
+
+ /* opengl offscreen render */
+ depsgraph = BKE_scene_ensure_depsgraph(context->bmain, scene, view_layer);
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ ibuf = sequencer_view3d_fn(
+ /* set for OpenGL render (NULL when scrubbing) */
+ depsgraph,
+ scene,
+ &context->scene->display.shading,
+ context->scene->r.seq_prev_type,
+ camera,
+ width,
+ height,
+ IB_rect,
+ draw_flags,
+ scene->r.alphamode,
+ viewname,
+ context->gpu_offscreen,
+ err_out);
+ if (ibuf == NULL) {
+ fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
+ }
+ }
+ else {
+ Render *re = RE_GetSceneRender(scene);
+ const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ ImBuf **ibufs_arr;
+
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ /* XXX: this if can be removed when sequence preview rendering uses the job system
+ *
+ * disable rendered preview for sequencer while rendering -- it's very much possible
+ * that preview render will went into conflict with final render
+ *
+ * When rendering from command line renderer is called from main thread, in this
+ * case it's always safe to render scene here
+ */
+ if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
+ if (re == NULL) {
+ re = RE_NewSceneRender(scene);
+ }
+
+ RE_RenderFrame(
+ re, context->bmain, scene, have_comp ? NULL : view_layer, camera, frame, false);
+
+ /* restore previous state after it was toggled on & off by RE_RenderFrame */
+ G.is_rendering = is_rendering;
+ }
+
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ SeqRenderData localcontext = *context;
+ RenderResult rres;
+
+ localcontext.view_id = view_id;
+
+ RE_AcquireResultImage(re, &rres, view_id);
+
+ if (rres.rectf) {
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[view_id]->rect_float,
+ rres.rectf,
+ sizeof(float[4]) * rres.rectx * rres.recty);
+
+ if (rres.rectz) {
+ addzbuffloatImBuf(ibufs_arr[view_id]);
+ memcpy(
+ ibufs_arr[view_id]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ }
+
+ /* float buffers in the sequencer are not linear */
+ seq_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
+ }
+ else if (rres.rect32) {
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[view_id]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+ }
+
+ if (view_id != context->view_id) {
+ BKE_sequencer_cache_put(
+ &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], 0, false);
+ }
+
+ RE_ReleaseResultImage(re);
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* "remove" the others (decrease their refcount) */
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
+ }
+ }
+ MEM_freeN(ibufs_arr);
+ }
+
+finally:
+ /* restore */
+ scene->r.scemode = orig_data.scemode;
+ scene->r.cfra = orig_data.cfra;
+ scene->r.subframe = orig_data.subframe;
+
+ if (is_frame_update && (depsgraph != NULL)) {
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ }
+
+#ifdef DURIAN_CAMERA_SWITCH
+ /* stooping to new low's in hackyness :( */
+ scene->r.mode &= orig_data.mode | ~R_NO_CAMERA_SWITCH;
+#endif
+
+ return ibuf;
+}
+
+/**
+ * Used for meta-strips & scenes with #SEQ_SCENE_STRIPS flag set.
+ */
+static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float nr)
+{
+ ImBuf *ibuf = NULL;
+ ListBase *seqbase = NULL;
+ int offset;
+
+ seqbase = BKE_sequence_seqbase_get(seq, &offset);
+
+ if (seqbase && !BLI_listbase_is_empty(seqbase)) {
+
+ if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset);
+ }
+
+ ibuf = seq_render_strip_stack(context,
+ state,
+ seqbase,
+ /* scene strips don't have their start taken into account */
+ nr + offset,
+ 0);
+ }
+
+ return ibuf;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Strip stack rendering functions
+ * \{ */
+static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra,
+ bool *r_is_proxy_image)
+{
+ ImBuf *ibuf = NULL;
+ float nr = seq_give_stripelem_index(seq, cfra);
+ int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
+ switch (type) {
+ case SEQ_TYPE_META: {
+ ibuf = do_render_strip_seqbase(context, state, seq, nr);
+ break;
+ }
+
+ case SEQ_TYPE_SCENE: {
+ if (seq->flag & SEQ_SCENE_STRIPS) {
+ if (seq->scene && (context->scene != seq->scene)) {
+ /* recursive check */
+ if (BLI_linklist_index(state->scene_parents, seq->scene) != -1) {
+ break;
+ }
+ LinkNode scene_parent = {
+ .next = state->scene_parents,
+ .link = seq->scene,
+ };
+ state->scene_parents = &scene_parent;
+ /* end check */
+
+ /* Use the Scene Seq's scene for the context when rendering the scene's sequences
+ * (necessary for Multicam Selector among others).
+ */
+ SeqRenderData local_context = *context;
+ local_context.scene = seq->scene;
+ local_context.skip_cache = true;
+
+ ibuf = do_render_strip_seqbase(&local_context, state, seq, nr);
+
+ /* step back in the list */
+ state->scene_parents = state->scene_parents->next;
+ }
+ }
+ else {
+ /* scene can be NULL after deletions */
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
+ }
+
+ break;
+ }
+
+ case SEQ_TYPE_EFFECT: {
+ ibuf = seq_render_effect_strip_impl(context, state, seq, cfra);
+ break;
+ }
+
+ case SEQ_TYPE_IMAGE: {
+ ibuf = seq_render_image_strip(context, seq, nr, cfra, r_is_proxy_image);
+ break;
+ }
+
+ case SEQ_TYPE_MOVIE: {
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra, r_is_proxy_image);
+ break;
+ }
+
+ case SEQ_TYPE_MOVIECLIP: {
+ ibuf = seq_render_movieclip_strip(context, seq, nr, r_is_proxy_image);
+
+ if (ibuf) {
+ /* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */
+ ImBuf *i = IMB_dupImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
+ ibuf = i;
+
+ if (ibuf->rect_float) {
+ seq_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ }
+ }
+
+ break;
+ }
+
+ case SEQ_TYPE_MASK: {
+ /* ibuf is always new */
+ ibuf = seq_render_mask_strip(context, seq, nr);
+ break;
+ }
+ }
+
+ if (ibuf) {
+ seq_imbuf_assign_spaces(context->scene, ibuf);
+ }
+
+ return ibuf;
+}
+
+ImBuf *seq_render_strip(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ bool use_preprocess = false;
+ bool is_proxy_image = false;
+
+ clock_t begin = seq_estimate_render_cost_begin();
+
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
+ if (ibuf != NULL) {
+ return ibuf;
+ }
+
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false);
+ if (ibuf == NULL) {
+ ibuf = do_render_strip_uncached(context, state, seq, cfra, &is_proxy_image);
+ }
+
+ if (ibuf) {
+ use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
+ ibuf = seq_render_preprocess_ibuf(
+ context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image);
+ }
+
+ if (ibuf == NULL) {
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ seq_imbuf_assign_spaces(context->scene, ibuf);
+ }
+
+ return ibuf;
+}
+
+static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
+{
+ bool swap_input = false;
+
+ /* bad hack, to fix crazy input ordering of
+ * those two effects */
+
+ if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
+ swap_input = true;
+ }
+
+ return swap_input;
+}
+
+static int seq_get_early_out_for_blend_mode(Sequence *seq)
+{
+ struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
+ float facf = seq->blend_opacity / 100.0f;
+ int early_out = sh.early_out(seq, facf, facf);
+
+ if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
+ return early_out;
+ }
+
+ if (seq_must_swap_input_in_blend_mode(seq)) {
+ if (early_out == EARLY_USE_INPUT_2) {
+ return EARLY_USE_INPUT_1;
+ }
+ if (early_out == EARLY_USE_INPUT_1) {
+ return EARLY_USE_INPUT_2;
+ }
+ }
+ return early_out;
+}
+
+static ImBuf *seq_render_strip_stack_apply_effect(
+ const SeqRenderData *context, Sequence *seq, float cfra, ImBuf *ibuf1, ImBuf *ibuf2)
+{
+ ImBuf *out;
+ struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
+ float facf = seq->blend_opacity / 100.0f;
+ int swap_input = seq_must_swap_input_in_blend_mode(seq);
+
+ if (swap_input) {
+ if (sh.multithreaded) {
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
+ }
+ else {
+ out = sh.execute(context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
+ }
+ }
+ else {
+ if (sh.multithreaded) {
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
+ }
+ else {
+ out = sh.execute(context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
+ }
+ }
+
+ return out;
+}
+
+static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
+ SeqRenderState *state,
+ ListBase *seqbasep,
+ float cfra,
+ int chanshown)
+{
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count;
+ int i;
+ ImBuf *out = NULL;
+ clock_t begin;
+
+ count = seq_get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
+
+ if (count == 0) {
+ return NULL;
+ }
+
+ for (i = count - 1; i >= 0; i--) {
+ int early_out;
+ Sequence *seq = seq_arr[i];
+
+ out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_COMPOSITE, false);
+
+ if (out) {
+ break;
+ }
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ out = seq_render_strip(context, state, seq, cfra);
+ break;
+ }
+
+ early_out = seq_get_early_out_for_blend_mode(seq);
+
+ switch (early_out) {
+ case EARLY_NO_INPUT:
+ case EARLY_USE_INPUT_2:
+ out = seq_render_strip(context, state, seq, cfra);
+ break;
+ case EARLY_USE_INPUT_1:
+ if (i == 0) {
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ }
+ break;
+ case EARLY_DO_EFFECT:
+ if (i == 0) {
+ begin = seq_estimate_render_cost_begin();
+
+ ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(
+ context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost, false);
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
+ }
+ break;
+ }
+ if (out) {
+ break;
+ }
+ }
+
+ i++;
+ for (; i < count; i++) {
+ begin = seq_estimate_render_cost_begin();
+ Sequence *seq = seq_arr[i];
+
+ if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
+ ImBuf *ibuf1 = out;
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
+ }
+
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(
+ context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost, false);
+ }
+
+ return out;
+}
+
+/*
+ * returned ImBuf is refed!
+ * you have to free after usage!
+ */
+
+ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown)
+{
+ Scene *scene = context->scene;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ ListBase *seqbasep;
+
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ if ((chanshown < 0) && !BLI_listbase_is_empty(&ed->metastack)) {
+ int count = BLI_listbase_count(&ed->metastack);
+ count = max_ii(count + chanshown, 0);
+ seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep;
+ }
+ else {
+ seqbasep = ed->seqbasep;
+ }
+
+ SeqRenderState state;
+ seq_render_state_init(&state);
+ ImBuf *out = NULL;
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count;
+
+ count = seq_get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
+
+ if (count) {
+ out = BKE_sequencer_cache_get(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ }
+
+ BKE_sequencer_cache_free_temp_cache(context->scene, context->task_id, cfra);
+
+ clock_t begin = seq_estimate_render_cost_begin();
+ float cost = 0;
+
+ if (count && !out) {
+ BLI_mutex_lock(&seq_render_mutex);
+ out = seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
+ cost = seq_estimate_render_cost_end(context->scene, begin);
+
+ if (context->is_prefetch_render) {
+ BKE_sequencer_cache_put(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost, false);
+ }
+ else {
+ BKE_sequencer_cache_put_if_possible(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost, false);
+ }
+ BLI_mutex_unlock(&seq_render_mutex);
+ }
+
+ BKE_sequencer_prefetch_start(context, cfra, cost);
+
+ return out;
+}
+
+ImBuf *seq_render_give_ibuf_seqbase(const SeqRenderData *context,
+ float cfra,
+ int chan_shown,
+ ListBase *seqbasep)
+{
+ SeqRenderState state;
+ seq_render_state_init(&state);
+
+ return seq_render_strip_stack(context, &state, seqbasep, cfra, chan_shown);
+}
+
+ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context, float cfra, Sequence *seq)
+{
+ SeqRenderState state;
+ seq_render_state_init(&state);
+
+ ImBuf *ibuf = seq_render_strip(context, &state, seq, cfra);
+
+ return ibuf;
+}
+/** \} */
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
new file mode 100644
index 00000000000..8be4ed7c2ab
--- /dev/null
+++ b/source/blender/sequencer/intern/render.h
@@ -0,0 +1,75 @@
+/*
+ * 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 SeqRenderData;
+struct ListBase;
+struct ImBuf;
+struct Scene;
+struct Sequence;
+
+/* mutable state for sequencer */
+typedef struct SeqRenderState {
+ struct LinkNode *scene_parents;
+} SeqRenderState;
+
+void seq_render_state_init(SeqRenderState *state);
+
+struct ImBuf *seq_render_give_ibuf_seqbase(const struct SeqRenderData *context,
+ float cfra,
+ int chan_shown,
+ struct ListBase *seqbasep);
+struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ struct ImBuf *ibuf1,
+ struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3);
+void seq_imbuf_to_sequencer_space(struct Scene *scene, struct ImBuf *ibuf, bool make_float);
+float seq_give_stripelem_index(struct Sequence *seq, float cfra);
+int seq_get_shown_sequences(struct ListBase *seqbasep,
+ int cfra,
+ int chanshown,
+ struct Sequence **seq_arr_out);
+struct ImBuf *seq_render_strip(const struct SeqRenderData *context,
+ struct SeqRenderState *state,
+ struct Sequence *seq,
+ float cfra);
+struct ImBuf *seq_render_mask(const struct SeqRenderData *context,
+ struct Mask *mask,
+ float nr,
+ bool make_float);
+void seq_imbuf_assign_spaces(struct Scene *scene, struct ImBuf *ibuf);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 8082356b8f4..89709c54942 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -103,41 +103,14 @@
# include <AUD_Special.h>
#endif
-/* mutable state for sequencer */
-typedef struct SeqRenderState {
- LinkNode *scene_parents;
-} SeqRenderState;
-
-static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
- SeqRenderState *state,
- ListBase *seqbasep,
- float cfra,
- int chanshown);
-static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- float cfra,
- clock_t begin,
- bool use_preprocess,
- const bool is_proxy_image);
-static ImBuf *seq_render_strip(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
-static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
-static int seq_num_files(Scene *scene, char views_format, const bool is_multiview);
static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id);
-static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
-
/* **** XXX ******** */
#define SELECT 1
ListBase seqbase_clipboard;
int seqbase_clipboard_frame;
-SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
-
#if 0 /* unused function */
static void printf_strip(Sequence *seq)
{
@@ -162,11 +135,6 @@ static void printf_strip(Sequence *seq)
}
#endif
-static void sequencer_state_init(SeqRenderState *state)
-{
- state->scene_parents = NULL;
-}
-
int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
int (*apply_fn)(Sequence *seq, void *),
void *arg)
@@ -333,7 +301,7 @@ void BKE_sequence_free_anim(Sequence *seq)
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
-static void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
+void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
{
Sequence *iseq, *iseq_next;
@@ -523,147 +491,6 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
scene->ed = NULL;
}
-/*********************** Sequencer color space functions *************************/
-
-static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
-{
-#if 0
- /* Bute buffer is supposed to be in sequencer working space already. */
- if (ibuf->rect != NULL) {
- IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
- }
-#endif
- if (ibuf->rect_float != NULL) {
- IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
- }
-}
-
-void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
-{
- /* Early output check: if both buffers are NULL we have nothing to convert. */
- if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
- return;
- }
- /* Get common conversion settings. */
- const char *to_colorspace = scene->sequencer_colorspace_settings.name;
- /* Perform actual conversion logic. */
- if (ibuf->rect_float == NULL) {
- /* We are not requested to give float buffer and byte buffer is already
- * in thee required colorspace. Can skip doing anything here.
- */
- const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
- if (!make_float && STREQ(from_colorspace, to_colorspace)) {
- return;
- }
- if (false) {
- /* The idea here is to provide as fast playback as possible and
- * enforcing float buffer here (a) uses more cache memory (b) might
- * make some other effects slower to apply.
- *
- * However, this might also have negative effect by adding weird
- * artifacts which will then not happen in final render.
- */
- IMB_colormanagement_transform_byte_threaded((unsigned char *)ibuf->rect,
- ibuf->x,
- ibuf->y,
- ibuf->channels,
- from_colorspace,
- to_colorspace);
- }
- else {
- /* We perform conversion to a float buffer so we don't worry about
- * precision loss.
- */
- imb_addrectfloatImBuf(ibuf);
- IMB_colormanagement_transform_from_byte_threaded(ibuf->rect_float,
- (unsigned char *)ibuf->rect,
- ibuf->x,
- ibuf->y,
- ibuf->channels,
- from_colorspace,
- to_colorspace);
- /* We don't need byte buffer anymore. */
- imb_freerectImBuf(ibuf);
- }
- }
- else {
- const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
- /* Unknown input color space, can't perform conversion. */
- if (from_colorspace == NULL || from_colorspace[0] == '\0') {
- return;
- }
- /* We don't want both byte and float buffers around: they'll either run
- * out of sync or conversion of byte buffer will lose precision in there.
- */
- if (ibuf->rect != NULL) {
- imb_freerectImBuf(ibuf);
- }
- IMB_colormanagement_transform_threaded(
- ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
- }
- sequencer_imbuf_assign_spaces(scene, ibuf);
-}
-
-void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
-{
- const char *from_colorspace = scene->sequencer_colorspace_settings.name;
- const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
- COLOR_ROLE_SCENE_LINEAR);
-
- if (!ibuf->rect_float) {
- return;
- }
-
- if (to_colorspace && to_colorspace[0] != '\0') {
- IMB_colormanagement_transform_threaded(
- ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
- IMB_colormanagement_assign_float_colorspace(ibuf, to_colorspace);
- }
-}
-
-void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4])
-{
- const char *from_colorspace = scene->sequencer_colorspace_settings.name;
- const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
- COLOR_ROLE_SCENE_LINEAR);
-
- if (to_colorspace && to_colorspace[0] != '\0') {
- IMB_colormanagement_transform_v4(pixel, from_colorspace, to_colorspace);
- }
- else {
- /* if no color management enables fallback to legacy conversion */
- srgb_to_linearrgb_v4(pixel, pixel);
- }
-}
-
-/*********************** sequencer pipeline functions *************************/
-
-void BKE_sequencer_new_render_data(Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- int rectx,
- int recty,
- int preview_render_size,
- int for_render,
- SeqRenderData *r_context)
-{
- r_context->bmain = bmain;
- r_context->depsgraph = depsgraph;
- r_context->scene = scene;
- r_context->rectx = rectx;
- r_context->recty = recty;
- r_context->preview_render_size = preview_render_size;
- r_context->for_render = for_render;
- r_context->motion_blur_samples = 0;
- r_context->motion_blur_shutter = 0;
- r_context->skip_cache = false;
- r_context->is_proxy_render = false;
- r_context->view_id = 0;
- r_context->gpu_offscreen = NULL;
- r_context->task_id = SEQ_TASK_MAIN_RENDER;
- r_context->is_prefetch_render = false;
-}
-
/* ************************* iterator ************************** */
/* *************** (replaces old WHILE_SEQ) ********************* */
/* **************** use now SEQ_ALL_BEGIN () SEQ_ALL_END ***************** */
@@ -911,12 +738,12 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
}
-static void seq_multiview_name(Scene *scene,
- const int view_id,
- const char *prefix,
- const char *ext,
- char *r_path,
- size_t r_size)
+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);
@@ -1394,273 +1221,8 @@ ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
return seqbase;
}
-/*********************** DO THE SEQUENCE *************************/
-
-static void multibuf(ImBuf *ibuf, const float fmul)
-{
- char *rt;
- float *rt_float;
-
- int a;
-
- rt = (char *)ibuf->rect;
- rt_float = ibuf->rect_float;
-
- if (rt) {
- const int imul = (int)(256.0f * fmul);
- a = ibuf->x * ibuf->y;
- while (a--) {
- rt[0] = min_ii((imul * rt[0]) >> 8, 255);
- rt[1] = min_ii((imul * rt[1]) >> 8, 255);
- rt[2] = min_ii((imul * rt[2]) >> 8, 255);
- rt[3] = min_ii((imul * rt[3]) >> 8, 255);
-
- rt += 4;
- }
- }
- if (rt_float) {
- a = ibuf->x * ibuf->y;
- while (a--) {
- rt_float[0] *= fmul;
- rt_float[1] *= fmul;
- rt_float[2] *= fmul;
- rt_float[3] *= fmul;
-
- rt_float += 4;
- }
- }
-}
-
-float BKE_sequencer_give_stripelem_index(Sequence *seq, float cfra)
-{
- float nr;
- 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 (cfra <= sta) {
- nr = end - sta;
- }
- else if (cfra >= end) {
- nr = 0;
- }
- else {
- nr = end - cfra;
- }
- }
- else {
- if (cfra <= sta) {
- nr = 0;
- }
- else if (cfra >= end) {
- nr = end - sta;
- }
- else {
- nr = cfra - sta;
- }
- }
-
- if (seq->strobe < 1.0f) {
- seq->strobe = 1.0f;
- }
-
- if (seq->strobe > 1.0f) {
- nr -= fmodf((double)nr, (double)seq->strobe);
- }
-
- return nr;
-}
-
-StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
-{
- StripElem *se = seq->strip->stripdata;
-
- if (seq->type == SEQ_TYPE_IMAGE) {
- /* only IMAGE strips use the whole array, MOVIE strips use only the first element,
- * all other strips don't use this...
- */
-
- int nr = (int)BKE_sequencer_give_stripelem_index(seq, cfra);
-
- if (nr == -1 || se == NULL) {
- return NULL;
- }
-
- se += nr + seq->anim_startofs;
- }
- return se;
-}
-
-static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown)
-{
- /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
- LinkNodePair effect_inputs = {NULL, NULL};
- int totseq = 0;
-
- memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
-
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
-
- if (seq->seq1) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
- }
-
- if (seq->seq2) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
- }
-
- if (seq->seq3) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
- }
- }
-
- seq_arr[seq->machine] = seq;
- totseq++;
- }
- }
-
- /* Drop strips which are used for effect inputs, we don't want
- * them to blend into render stack in any other way than effect
- * string rendering. */
- for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
- Sequence *seq = seq_item->link;
- /* It's possible that effect strip would be placed to the same
- * 'machine' as its inputs. We don't want to clear such strips
- * from the stack. */
- if (seq_arr[seq->machine] && seq_arr[seq->machine]->type & SEQ_TYPE_EFFECT) {
- continue;
- }
- /* If we're shown a specified channel, then we want to see the strips
- * which belongs to this machine. */
- if (chanshown != 0 && chanshown <= seq->machine) {
- continue;
- }
- seq_arr[seq->machine] = NULL;
- }
-
- return totseq;
-}
-
-int BKE_sequencer_evaluate_frame(Scene *scene, int cfra)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq_arr[MAXSEQ + 1];
-
- if (ed == NULL) {
- return 0;
- }
-
- return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra, 0);
-}
-
-static bool video_seq_is_rendered(Sequence *seq)
-{
- return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
-}
-
-int BKE_sequencer_get_shown_sequences(ListBase *seqbasep,
- int cfra,
- int chanshown,
- Sequence **seq_arr_out)
-{
- Sequence *seq_arr[MAXSEQ + 1];
- int b = chanshown;
- int cnt = 0;
-
- if (b > MAXSEQ) {
- return 0;
- }
-
- if (evaluate_seq_frame_gen(seq_arr, seqbasep, cfra, chanshown)) {
- if (b == 0) {
- b = MAXSEQ;
- }
- for (; b > 0; b--) {
- if (video_seq_is_rendered(seq_arr[b])) {
- break;
- }
- }
- }
-
- chanshown = b;
-
- for (; b > 0; b--) {
- if (video_seq_is_rendered(seq_arr[b])) {
- if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) {
- break;
- }
- }
- }
-
- for (; b <= chanshown && b >= 0; b++) {
- if (video_seq_is_rendered(seq_arr[b])) {
- seq_arr_out[cnt++] = seq_arr[b];
- }
- }
-
- return cnt;
-}
-
-/*********************** proxy management *************************/
-
-typedef struct SeqIndexBuildContext {
- struct IndexBuildContext *index_context;
-
- int tc_flags;
- int size_flags;
- int quality;
- bool overwrite;
- int view_id;
-
- Main *bmain;
- Depsgraph *depsgraph;
- Scene *scene;
- Sequence *seq, *orig_seq;
-} SeqIndexBuildContext;
-
-#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
-
-int SEQ_rendersize_to_proxysize(int render_size)
-{
- switch (render_size) {
- case SEQ_RENDER_SIZE_PROXY_25:
- return IMB_PROXY_25;
- case SEQ_RENDER_SIZE_PROXY_50:
- return IMB_PROXY_50;
- case SEQ_RENDER_SIZE_PROXY_75:
- return IMB_PROXY_75;
- case SEQ_RENDER_SIZE_PROXY_100:
- return IMB_PROXY_100;
- }
- return IMB_PROXY_NONE;
-}
-
-double BKE_sequencer_rendersize_to_scale_factor(int render_size)
-{
- switch (render_size) {
- case SEQ_RENDER_SIZE_PROXY_25:
- return 0.25;
- case SEQ_RENDER_SIZE_PROXY_50:
- return 0.50;
- case SEQ_RENDER_SIZE_PROXY_75:
- return 0.75;
- }
- return 1.0;
-}
-
/* the number of files will vary according to the stereo format */
-static int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
if (!is_multiview) {
return 1;
@@ -1673,7 +1235,7 @@ static int seq_num_files(Scene *scene, char views_format, const bool is_multivie
return BKE_scene_multiview_num_views_get(&scene->r);
}
-static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
+void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
{
char dir[FILE_MAX];
char fname[FILE_MAXFILE];
@@ -1684,7 +1246,7 @@ static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
IMB_anim_set_index_dir(anim, dir);
}
-static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
+void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
{
char dir[FILE_MAX];
char name[FILE_MAX];
@@ -1813,2454 +1375,6 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
}
-static bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_id)
-{
- char fname[FILE_MAXFILE];
- char suffix[24];
- StripProxy *proxy = seq->strip->proxy;
-
- if (proxy == NULL) {
- return false;
- }
-
- BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file);
- BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
-
- if (view_id > 0) {
- BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
- /* TODO(sergey): This will actually append suffix after extension
- * which is weird but how was originally coded in multi-view branch.
- */
- BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
- }
- else {
- BLI_strncpy(name, fname, PROXY_MAXFILE);
- }
-
- return true;
-}
-
-static bool seq_proxy_get_fname(Editing *ed,
- Sequence *seq,
- int cfra,
- eSpaceSeq_Proxy_RenderSize render_size,
- char *name,
- const int view_id)
-{
- char dir[PROXY_MAXFILE];
- char suffix[24] = {'\0'};
- StripProxy *proxy = seq->strip->proxy;
-
- if (proxy == NULL) {
- return false;
- }
-
- /* Multi-view suffix. */
- if (view_id > 0) {
- BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
- }
-
- /* Per strip with Custom file situation is handled separately. */
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
- ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) {
- if (seq_proxy_get_custom_file_fname(seq, name, view_id)) {
- return true;
- }
- }
-
- if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
- /* Per project default. */
- if (ed->proxy_dir[0] == 0) {
- BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
- }
- else { /* Per project with custom dir. */
- BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
- }
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- }
- else {
- /* Pre strip with custom dir. */
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- else { /* Per strip default. */
- BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
- }
- }
-
- /* Proxy size number to be used in path. */
- int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100;
-
- BLI_snprintf(name,
- PROXY_MAXFILE,
- "%s/images/%d/%s_proxy%s",
- dir,
- proxy_size_number,
- BKE_sequencer_give_stripelem(seq, cfra)->name,
- suffix);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- strcat(name, ".jpg");
-
- return true;
-}
-
-bool SEQ_can_use_proxy(Sequence *seq, int psize)
-{
- if (seq->strip->proxy == NULL) {
- return false;
- }
- short size_flags = seq->strip->proxy->build_size_flags;
- return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0;
-}
-
-static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
-{
- char name[PROXY_MAXFILE];
- StripProxy *proxy = seq->strip->proxy;
- const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
- Editing *ed = context->scene->ed;
- StripAnim *sanim;
-
- /* only use proxies, if they are enabled (even if present!) */
- if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(psize))) {
- return NULL;
- }
-
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
- if (proxy->anim == NULL) {
- if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
- return NULL;
- }
-
- proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
- }
- if (proxy->anim == NULL) {
- return NULL;
- }
-
- seq_open_anim_file(context->scene, seq, true);
- sanim = seq->anims.first;
-
- frameno = IMB_anim_index_get_frame_index(
- sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
-
- return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
- }
-
- if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
- return NULL;
- }
-
- if (BLI_exists(name)) {
- ImBuf *ibuf = IMB_loadiffname(name, IB_rect, NULL);
-
- if (ibuf) {
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
-
- return ibuf;
- }
-
- return NULL;
-}
-
-static void seq_proxy_build_frame(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- int cfra,
- int proxy_render_size,
- const bool overwrite)
-{
- char name[PROXY_MAXFILE];
- int quality;
- int rectx, recty;
- int ok;
- ImBuf *ibuf_tmp, *ibuf;
- Editing *ed = context->scene->ed;
-
- if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
- return;
- }
-
- if (!overwrite && BLI_exists(name)) {
- return;
- }
-
- ibuf_tmp = seq_render_strip(context, state, seq, cfra);
-
- rectx = (proxy_render_size * ibuf_tmp->x) / 100;
- recty = (proxy_render_size * ibuf_tmp->y) / 100;
-
- if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
- ibuf = IMB_dupImBuf(ibuf_tmp);
- IMB_metadata_copy(ibuf, ibuf_tmp);
- IMB_freeImBuf(ibuf_tmp);
- IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
- }
- else {
- ibuf = ibuf_tmp;
- }
-
- /* depth = 32 is intentionally left in, otherwise ALPHA channels
- * won't work... */
- quality = seq->strip->proxy->quality;
- ibuf->ftype = IMB_FTYPE_JPG;
- ibuf->foptions.quality = quality;
-
- /* unsupported feature only confuses other s/w */
- if (ibuf->planes == 32) {
- ibuf->planes = 24;
- }
-
- BLI_make_existing_file(name);
-
- ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
- if (ok == 0) {
- perror(name);
- }
-
- IMB_freeImBuf(ibuf);
-}
-
-/**
- * Returns whether the file this context would read from even exist,
- * if not, don't create the context
- */
-static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
-{
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- return false;
- }
-
- if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- static char prefix[FILE_MAX];
- static const char *ext = NULL;
- char str[FILE_MAX];
-
- if (view_id == 0) {
- char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
- }
- else {
- prefix[0] = '\0';
- }
-
- if (prefix[0] == '\0') {
- return view_id != 0;
- }
-
- seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
-
- if (BLI_access(str, R_OK) == 0) {
- return false;
- }
-
- return view_id != 0;
- }
- return false;
-}
-
-/**
- * This returns the maximum possible number of required contexts
- */
-static int seq_proxy_context_count(Sequence *seq, Scene *scene)
-{
- int num_views = 1;
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- return 1;
- }
-
- switch (seq->type) {
- case SEQ_TYPE_MOVIE: {
- num_views = BLI_listbase_count(&seq->anims);
- break;
- }
- case SEQ_TYPE_IMAGE: {
- switch (seq->views_format) {
- case R_IMF_VIEWS_INDIVIDUAL:
- num_views = BKE_scene_multiview_num_views_get(&scene->r);
- break;
- case R_IMF_VIEWS_STEREO_3D:
- num_views = 2;
- break;
- case R_IMF_VIEWS_MULTIVIEW:
- /* not supported at the moment */
- /* pass through */
- default:
- num_views = 1;
- }
- break;
- }
- }
-
- return num_views;
-}
-
-bool BKE_sequencer_proxy_rebuild_context(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Sequence *seq,
- struct GSet *file_list,
- ListBase *queue)
-{
- SeqIndexBuildContext *context;
- Sequence *nseq;
- LinkData *link;
- int num_files;
- int i;
-
- if (!seq->strip || !seq->strip->proxy) {
- return true;
- }
-
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return true;
- }
-
- num_files = seq_proxy_context_count(seq, scene);
-
- for (i = 0; i < num_files; i++) {
- if (seq_proxy_multiview_context_invalid(seq, scene, i)) {
- continue;
- }
-
- context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
-
- nseq = BKE_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
-
- context->tc_flags = nseq->strip->proxy->build_tc_flags;
- context->size_flags = nseq->strip->proxy->build_size_flags;
- context->quality = nseq->strip->proxy->quality;
- context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
-
- context->bmain = bmain;
- context->depsgraph = depsgraph;
- context->scene = scene;
- context->orig_seq = seq;
- context->seq = nseq;
-
- context->view_id = i; /* only for images */
-
- if (nseq->type == SEQ_TYPE_MOVIE) {
- StripAnim *sanim;
-
- seq_open_anim_file(scene, nseq, true);
- sanim = BLI_findlink(&nseq->anims, i);
-
- if (sanim->anim) {
- context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
- context->tc_flags,
- context->size_flags,
- context->quality,
- context->overwrite,
- file_list);
- }
- if (!context->index_context) {
- MEM_freeN(context);
- return false;
- }
- }
-
- link = BLI_genericNodeN(context);
- BLI_addtail(queue, link);
- }
- return true;
-}
-
-void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context,
- short *stop,
- short *do_update,
- float *progress)
-{
- const bool overwrite = context->overwrite;
- SeqRenderData render_context;
- Sequence *seq = context->seq;
- Scene *scene = context->scene;
- Main *bmain = context->bmain;
- int cfra;
-
- if (seq->type == SEQ_TYPE_MOVIE) {
- if (context->index_context) {
- IMB_anim_index_rebuild(context->index_context, stop, do_update, progress);
- }
-
- return;
- }
-
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return;
- }
-
- /* that's why it is called custom... */
- if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- return;
- }
-
- /* fail safe code */
-
- BKE_sequencer_new_render_data(bmain,
- context->depsgraph,
- context->scene,
- roundf((scene->r.size * (float)scene->r.xsch) / 100.0f),
- roundf((scene->r.size * (float)scene->r.ysch) / 100.0f),
- 100,
- false,
- &render_context);
-
- render_context.skip_cache = true;
- render_context.is_proxy_render = true;
- render_context.view_id = context->view_id;
-
- SeqRenderState state;
- sequencer_state_init(&state);
-
- for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
- if (context->size_flags & IMB_PROXY_25) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 25, overwrite);
- }
- if (context->size_flags & IMB_PROXY_50) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 50, overwrite);
- }
- if (context->size_flags & IMB_PROXY_75) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 75, overwrite);
- }
- if (context->size_flags & IMB_PROXY_100) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 100, overwrite);
- }
-
- *progress = (float)(cfra - seq->startdisp - seq->startstill) /
- (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
- *do_update = true;
-
- if (*stop || G.is_break) {
- break;
- }
- }
-}
-
-void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
-{
- if (context->index_context) {
- StripAnim *sanim;
-
- for (sanim = context->seq->anims.first; sanim; sanim = sanim->next) {
- IMB_close_anim_proxies(sanim->anim);
- }
-
- for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) {
- IMB_close_anim_proxies(sanim->anim);
- }
-
- IMB_anim_index_rebuild_finish(context->index_context, stop);
- }
-
- seq_free_sequence_recurse(NULL, context->seq, true);
-
- MEM_freeN(context);
-}
-
-void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
-{
- if (value) {
- seq->flag |= SEQ_USE_PROXY;
- if (seq->strip->proxy == NULL) {
- seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
- seq->strip->proxy->quality = 90;
- seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
- seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
- }
- }
- else {
- seq->flag &= ~SEQ_USE_PROXY;
- }
-}
-
-/*********************** color balance *************************/
-
-static StripColorBalance calc_cb(StripColorBalance *cb_)
-{
- StripColorBalance cb = *cb_;
- int c;
-
- for (c = 0; c < 3; c++) {
- cb.lift[c] = 2.0f - cb.lift[c];
- }
-
- if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
- for (c = 0; c < 3; c++) {
- /* tweak to give more subtle results
- * values above 1.0 are scaled */
- if (cb.lift[c] > 1.0f) {
- cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
- }
-
- cb.lift[c] = 2.0f - cb.lift[c];
- }
- }
-
- if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
- for (c = 0; c < 3; c++) {
- if (cb.gain[c] != 0.0f) {
- cb.gain[c] = 1.0f / cb.gain[c];
- }
- else {
- cb.gain[c] = 1000000; /* should be enough :) */
- }
- }
- }
-
- if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
- for (c = 0; c < 3; c++) {
- if (cb.gamma[c] != 0.0f) {
- cb.gamma[c] = 1.0f / cb.gamma[c];
- }
- else {
- cb.gamma[c] = 1000000; /* should be enough :) */
- }
- }
- }
-
- return cb;
-}
-
-/* note: lift is actually 2-lift */
-MINLINE float color_balance_fl(
- float in, const float lift, const float gain, const float gamma, const float mul)
-{
- float x = (((in - 1.0f) * lift) + 1.0f) * gain;
-
- /* prevent NaN */
- if (x < 0.f) {
- x = 0.f;
- }
-
- x = powf(x, gamma) * mul;
- CLAMP(x, FLT_MIN, FLT_MAX);
- return x;
-}
-
-static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul)
-{
- int y;
-
- for (y = 0; y < 256; y++) {
- float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
-
- table[y] = v;
- }
-}
-
-static void color_balance_byte_byte(StripColorBalance *cb_,
- unsigned char *rect,
- unsigned char *mask_rect,
- int width,
- int height,
- float mul)
-{
- // unsigned char cb_tab[3][256];
- unsigned char *cp = rect;
- unsigned char *e = cp + width * 4 * height;
- unsigned char *m = mask_rect;
-
- StripColorBalance cb = calc_cb(cb_);
-
- while (cp < e) {
- float p[4];
- int c;
-
- straight_uchar_to_premul_float(p, cp);
-
- for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
-
- if (m) {
- float m_normal = (float)m[c] / 255.0f;
-
- p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
- }
- else {
- p[c] = t;
- }
- }
-
- premul_float_to_straight_uchar(cp, p);
-
- cp += 4;
- if (m) {
- m += 4;
- }
- }
-}
-
-static void color_balance_byte_float(StripColorBalance *cb_,
- unsigned char *rect,
- float *rect_float,
- unsigned char *mask_rect,
- int width,
- int height,
- float mul)
-{
- float cb_tab[4][256];
- int c, i;
- unsigned char *p = rect;
- unsigned char *e = p + width * 4 * height;
- unsigned char *m = mask_rect;
- float *o;
- StripColorBalance cb;
-
- o = rect_float;
-
- cb = calc_cb(cb_);
-
- for (c = 0; c < 3; c++) {
- make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
- }
-
- for (i = 0; i < 256; i++) {
- cb_tab[3][i] = ((float)i) * (1.0f / 255.0f);
- }
-
- while (p < e) {
- if (m) {
- const float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f};
-
- p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]];
- p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]];
- p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]];
-
- m += 4;
- }
- else {
- o[0] = cb_tab[0][p[0]];
- o[1] = cb_tab[1][p[1]];
- o[2] = cb_tab[2][p[2]];
- }
-
- o[3] = cb_tab[3][p[3]];
-
- p += 4;
- o += 4;
- }
-}
-
-static void color_balance_float_float(StripColorBalance *cb_,
- float *rect_float,
- const float *mask_rect_float,
- int width,
- int height,
- float mul)
-{
- float *p = rect_float;
- const float *e = rect_float + width * 4 * height;
- const float *m = mask_rect_float;
- StripColorBalance cb = calc_cb(cb_);
-
- while (p < e) {
- int c;
- for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
-
- if (m) {
- p[c] = p[c] * (1.0f - m[c]) + t * m[c];
- }
- else {
- p[c] = t;
- }
- }
-
- p += 4;
- if (m) {
- m += 4;
- }
- }
-}
-
-typedef struct ColorBalanceInitData {
- StripColorBalance *cb;
- ImBuf *ibuf;
- float mul;
- ImBuf *mask;
- bool make_float;
-} ColorBalanceInitData;
-
-typedef struct ColorBalanceThread {
- StripColorBalance *cb;
- float mul;
-
- int width, height;
-
- unsigned char *rect, *mask_rect;
- float *rect_float, *mask_rect_float;
-
- bool make_float;
-} ColorBalanceThread;
-
-static void color_balance_init_handle(void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
-{
- ColorBalanceThread *handle = (ColorBalanceThread *)handle_v;
- ColorBalanceInitData *init_data = (ColorBalanceInitData *)init_data_v;
- ImBuf *ibuf = init_data->ibuf;
- ImBuf *mask = init_data->mask;
-
- int offset = 4 * start_line * ibuf->x;
-
- memset(handle, 0, sizeof(ColorBalanceThread));
-
- handle->cb = init_data->cb;
- handle->mul = init_data->mul;
- handle->width = ibuf->x;
- handle->height = tot_line;
- handle->make_float = init_data->make_float;
-
- if (ibuf->rect) {
- handle->rect = (unsigned char *)ibuf->rect + offset;
- }
-
- if (ibuf->rect_float) {
- handle->rect_float = ibuf->rect_float + offset;
- }
-
- if (mask) {
- if (mask->rect) {
- handle->mask_rect = (unsigned char *)mask->rect + offset;
- }
-
- if (mask->rect_float) {
- handle->mask_rect_float = mask->rect_float + offset;
- }
- }
- else {
- handle->mask_rect = NULL;
- handle->mask_rect_float = NULL;
- }
-}
-
-static void *color_balance_do_thread(void *thread_data_v)
-{
- ColorBalanceThread *thread_data = (ColorBalanceThread *)thread_data_v;
- StripColorBalance *cb = thread_data->cb;
- int width = thread_data->width, height = thread_data->height;
- unsigned char *rect = thread_data->rect;
- unsigned char *mask_rect = thread_data->mask_rect;
- float *rect_float = thread_data->rect_float;
- float *mask_rect_float = thread_data->mask_rect_float;
- float mul = thread_data->mul;
-
- if (rect_float) {
- color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
- }
- else if (thread_data->make_float) {
- color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
- }
- else {
- color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
- }
-
- return NULL;
-}
-
-/**
- * \a cfra is offset by \a fra_offset only in case we are using a real mask.
- */
-ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context,
- int mask_input_type,
- Sequence *mask_sequence,
- Mask *mask_id,
- int cfra,
- int fra_offset,
- bool make_float)
-{
- ImBuf *mask_input = NULL;
-
- if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
- if (mask_sequence) {
- SeqRenderState state;
- sequencer_state_init(&state);
-
- mask_input = seq_render_strip(context, &state, mask_sequence, cfra);
-
- if (make_float) {
- if (!mask_input->rect_float) {
- IMB_float_from_rect(mask_input);
- }
- }
- else {
- if (!mask_input->rect) {
- IMB_rect_from_float(mask_input);
- }
- }
- }
- }
- else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
- mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
- }
-
- return mask_input;
-}
-
-void BKE_sequencer_color_balance_apply(
- StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
-{
- ColorBalanceInitData init_data;
-
- if (!ibuf->rect_float && make_float) {
- imb_addrectfloatImBuf(ibuf);
- }
-
- init_data.cb = cb;
- init_data.ibuf = ibuf;
- init_data.mul = mul;
- init_data.make_float = make_float;
- init_data.mask = mask_input;
-
- IMB_processor_apply_threaded(ibuf->y,
- sizeof(ColorBalanceThread),
- &init_data,
- color_balance_init_handle,
- color_balance_do_thread);
-
- /* color balance either happens on float buffer or byte buffer, but never on both,
- * free byte buffer if there's float buffer since float buffer would be used for
- * color balance in favor of byte buffer
- */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-}
-
-/*
- * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE
- *
- * Do all the things you can't really do afterwards using sequence effects
- * (read: before rescaling to render resolution has been done)
- *
- * Order is important!
- *
- * - Deinterlace
- * - Crop and transform in image source coordinate space
- * - Flip X + Flip Y (could be done afterwards, backward compatibility)
- * - Promote image to float data (affects pipeline operations afterwards)
- * - Color balance (is most efficient in the byte -> float
- * (future: half -> float should also work fine!)
- * case, if done on load, since we can use lookup tables)
- * - Premultiply
- */
-
-static bool sequencer_use_transform(const Sequence *seq)
-{
- const StripTransform *transform = seq->strip->transform;
-
- if (transform->xofs != 0 || transform->yofs != 0 || transform->scale_x != 1 ||
- transform->scale_y != 1 || transform->rotation != 0) {
- return true;
- }
-
- return false;
-}
-
-static bool sequencer_use_crop(const Sequence *seq)
-{
- const StripCrop *crop = seq->strip->crop;
- if (crop->left > 0 || crop->right > 0 || crop->top > 0 || crop->bottom > 0) {
- return true;
- }
-
- return false;
-}
-
-bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
- Sequence *seq,
- float UNUSED(cfra))
-{
- float mul;
-
- if (context && context->is_proxy_render) {
- return false;
- }
-
- if ((seq->flag & (SEQ_FILTERY | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) ||
- sequencer_use_crop(seq) || sequencer_use_transform(seq)) {
- return true;
- }
-
- mul = seq->mul;
-
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- mul *= seq->blend_opacity / 100.0f;
- }
-
- if (mul != 1.0f) {
- return true;
- }
-
- if (seq->sat != 1.0f) {
- return true;
- }
-
- if (seq->modifiers.first) {
- return true;
- }
-
- return false;
-}
-
-typedef struct ImageTransformThreadInitData {
- ImBuf *ibuf_source;
- ImBuf *ibuf_out;
- StripTransform *transform;
- float scale_to_fit;
- float image_scale_factor;
- bool for_render;
-} ImageTransformThreadInitData;
-
-typedef struct ImageTransformThreadData {
- ImBuf *ibuf_source;
- ImBuf *ibuf_out;
- StripTransform *transform;
- float scale_to_fit;
- float image_scale_factor;
- bool for_render;
- int start_line;
- int tot_line;
-} ImageTransformThreadData;
-
-static void sequencer_image_transform_init(void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
-{
- ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v;
- const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v;
-
- handle->ibuf_source = init_data->ibuf_source;
- handle->ibuf_out = init_data->ibuf_out;
- handle->transform = init_data->transform;
- handle->scale_to_fit = init_data->scale_to_fit;
- handle->image_scale_factor = init_data->image_scale_factor;
- handle->for_render = init_data->for_render;
-
- handle->start_line = start_line;
- handle->tot_line = tot_line;
-}
-
-static void *sequencer_image_transform_do_thread(void *data_v)
-{
- const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v;
- const StripTransform *transform = data->transform;
- const float scale_x = transform->scale_x * data->scale_to_fit;
- const float scale_y = transform->scale_y * data->scale_to_fit;
- const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
- const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2;
- const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x;
- const float translate_y = transform->yofs * data->image_scale_factor + scale_to_fit_offs_y;
- const int width = data->ibuf_out->x;
- const int height = data->ibuf_out->y;
- const float pivot[2] = {width / 2 - scale_to_fit_offs_x, height / 2 - scale_to_fit_offs_y};
- float transform_matrix[3][3];
- loc_rot_size_to_mat3(transform_matrix,
- (const float[]){translate_x, translate_y},
- transform->rotation,
- (const float[]){scale_x, scale_y});
- invert_m3(transform_matrix);
- transform_pivot_set_m3(transform_matrix, pivot);
-
- for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) {
- for (int xi = 0; xi < width; xi++) {
- float uv[2] = {xi, yi};
- mul_v2_m3v2(uv, transform_matrix, uv);
-
- if (data->for_render) {
- bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
- }
- else {
- nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
- }
- }
- }
-
- return NULL;
-}
-
-static ImBuf *input_preprocess(const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- ImBuf *ibuf,
- const bool UNUSED(is_proxy_image))
-{
- Scene *scene = context->scene;
- ImBuf *preprocessed_ibuf = NULL;
-
- /* Deinterlace. */
- if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
- preprocessed_ibuf = IMB_makeSingleUser(ibuf);
- ibuf = preprocessed_ibuf;
-
- IMB_filtery(preprocessed_ibuf);
- }
-
- /* Calculate scale factor, so image fits in preview area with original aspect ratio. */
- const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x,
- (float)context->recty / (float)ibuf->y);
-
- /* Get scale factor if preview resolution doesn't match project resolution. */
- float preview_scale_factor;
- if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
- preview_scale_factor = (float)scene->r.size / 100;
- }
- else {
- preview_scale_factor = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
- }
-
- if (sequencer_use_crop(seq)) {
- /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
- preprocessed_ibuf = IMB_makeSingleUser(ibuf);
- ibuf = preprocessed_ibuf;
-
- const int width = ibuf->x;
- const int height = ibuf->y;
- const StripCrop *c = seq->strip->crop;
-
- const int left = c->left / scale_to_fit_factor * preview_scale_factor;
- const int right = c->right / scale_to_fit_factor * preview_scale_factor;
- const int top = c->top / scale_to_fit_factor * preview_scale_factor;
- const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor;
- const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- /* Left. */
- IMB_rectfill_area_replace(preprocessed_ibuf, col, 0, 0, left, height);
- /* Bottom. */
- IMB_rectfill_area_replace(preprocessed_ibuf, col, left, 0, width, bottom);
- /* Right. */
- IMB_rectfill_area_replace(preprocessed_ibuf, col, width - right, bottom, width, height);
- /* Top. */
- IMB_rectfill_area_replace(preprocessed_ibuf, col, left, height - top, width - right, height);
- }
-
- if (sequencer_use_transform(seq) || context->rectx != ibuf->x || context->recty != ibuf->y) {
- const int x = context->rectx;
- const int y = context->recty;
- preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
-
- ImageTransformThreadInitData init_data = {NULL};
- init_data.ibuf_source = ibuf;
- init_data.ibuf_out = preprocessed_ibuf;
- init_data.transform = seq->strip->transform;
- init_data.scale_to_fit = scale_to_fit_factor;
- init_data.image_scale_factor = preview_scale_factor;
- init_data.for_render = context->for_render;
- IMB_processor_apply_threaded(context->recty,
- sizeof(ImageTransformThreadData),
- &init_data,
- sequencer_image_transform_init,
- sequencer_image_transform_do_thread);
- sequencer_imbuf_assign_spaces(scene, preprocessed_ibuf);
- IMB_metadata_copy(preprocessed_ibuf, ibuf);
- IMB_freeImBuf(ibuf);
- }
-
- /* Duplicate ibuf if we still have original. */
- if (preprocessed_ibuf == NULL) {
- preprocessed_ibuf = IMB_makeSingleUser(ibuf);
- }
-
- if (seq->flag & SEQ_FLIPX) {
- IMB_flipx(preprocessed_ibuf);
- }
-
- if (seq->flag & SEQ_FLIPY) {
- IMB_flipy(preprocessed_ibuf);
- }
-
- if (seq->sat != 1.0f) {
- IMB_saturation(preprocessed_ibuf, seq->sat);
- }
-
- if (seq->flag & SEQ_MAKE_FLOAT) {
- if (!preprocessed_ibuf->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, preprocessed_ibuf, true);
- }
-
- if (preprocessed_ibuf->rect) {
- imb_freerectImBuf(preprocessed_ibuf);
- }
- }
-
- float mul = seq->mul;
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- mul *= seq->blend_opacity / 100.0f;
- }
-
- if (mul != 1.0f) {
- multibuf(preprocessed_ibuf, mul);
- }
-
- if (seq->modifiers.first) {
- ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, preprocessed_ibuf, cfra);
-
- if (ibuf_new != preprocessed_ibuf) {
- IMB_metadata_copy(ibuf_new, preprocessed_ibuf);
- IMB_freeImBuf(preprocessed_ibuf);
- preprocessed_ibuf = ibuf_new;
- }
- }
-
- return preprocessed_ibuf;
-}
-
-/*********************** strip rendering functions *************************/
-
-typedef struct RenderEffectInitData {
- struct SeqEffectHandle *sh;
- const SeqRenderData *context;
- Sequence *seq;
- float cfra, facf0, facf1;
- ImBuf *ibuf1, *ibuf2, *ibuf3;
-
- ImBuf *out;
-} RenderEffectInitData;
-
-typedef struct RenderEffectThread {
- struct SeqEffectHandle *sh;
- const SeqRenderData *context;
- Sequence *seq;
- float cfra, facf0, facf1;
- ImBuf *ibuf1, *ibuf2, *ibuf3;
-
- ImBuf *out;
- int start_line, tot_line;
-} RenderEffectThread;
-
-static void render_effect_execute_init_handle(void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
-{
- RenderEffectThread *handle = (RenderEffectThread *)handle_v;
- RenderEffectInitData *init_data = (RenderEffectInitData *)init_data_v;
-
- handle->sh = init_data->sh;
- handle->context = init_data->context;
- handle->seq = init_data->seq;
- handle->cfra = init_data->cfra;
- handle->facf0 = init_data->facf0;
- handle->facf1 = init_data->facf1;
- handle->ibuf1 = init_data->ibuf1;
- handle->ibuf2 = init_data->ibuf2;
- handle->ibuf3 = init_data->ibuf3;
- handle->out = init_data->out;
-
- handle->start_line = start_line;
- handle->tot_line = tot_line;
-}
-
-static void *render_effect_execute_do_thread(void *thread_data_v)
-{
- RenderEffectThread *thread_data = (RenderEffectThread *)thread_data_v;
-
- thread_data->sh->execute_slice(thread_data->context,
- thread_data->seq,
- thread_data->cfra,
- thread_data->facf0,
- thread_data->facf1,
- thread_data->ibuf1,
- thread_data->ibuf2,
- thread_data->ibuf3,
- thread_data->start_line,
- thread_data->tot_line,
- thread_data->out);
-
- return NULL;
-}
-
-ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
- const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- float facf0,
- float facf1,
- ImBuf *ibuf1,
- ImBuf *ibuf2,
- ImBuf *ibuf3)
-{
- RenderEffectInitData init_data;
- ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
-
- init_data.sh = sh;
- init_data.context = context;
- init_data.seq = seq;
- init_data.cfra = cfra;
- init_data.facf0 = facf0;
- init_data.facf1 = facf1;
- init_data.ibuf1 = ibuf1;
- init_data.ibuf2 = ibuf2;
- init_data.ibuf3 = ibuf3;
- init_data.out = out;
-
- IMB_processor_apply_threaded(out->y,
- sizeof(RenderEffectThread),
- &init_data,
- render_effect_execute_init_handle,
- render_effect_execute_do_thread);
-
- return out;
-}
-
-static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- float cfra)
-{
- Scene *scene = context->scene;
- float fac, facf;
- int early_out;
- int i;
- struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
- FCurve *fcu = NULL;
- ImBuf *ibuf[3];
- Sequence *input[3];
- ImBuf *out = NULL;
-
- ibuf[0] = ibuf[1] = ibuf[2] = NULL;
-
- input[0] = seq->seq1;
- input[1] = seq->seq2;
- input[2] = seq->seq3;
-
- if (!sh.execute && !(sh.execute_slice && sh.init_execution)) {
- /* effect not supported in this version... */
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- return out;
- }
-
- if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- sh.get_default_fac(seq, cfra, &fac, &facf);
- facf = fac;
- }
- else {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
- if (fcu) {
- fac = facf = evaluate_fcurve(fcu, cfra);
- }
- else {
- fac = facf = seq->effect_fader;
- }
- }
-
- early_out = sh.early_out(seq, fac, facf);
-
- switch (early_out) {
- case EARLY_NO_INPUT:
- out = sh.execute(context, seq, cfra, fac, facf, NULL, NULL, NULL);
- break;
- case EARLY_DO_EFFECT:
- for (i = 0; i < 3; i++) {
- /* Speed effect requires time remapping of `cfra` for input(s). */
- if (input[0] && seq->type == SEQ_TYPE_SPEED) {
- float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i);
- ibuf[i] = seq_render_strip(context, state, input[0], target_frame);
- }
- else { /* Other effects. */
- if (input[i]) {
- ibuf[i] = seq_render_strip(context, state, input[i], cfra);
- }
- }
- }
-
- if (ibuf[0] && (ibuf[1] || BKE_sequence_effect_get_num_inputs(seq->type) == 1)) {
- if (sh.multithreaded) {
- out = BKE_sequencer_effect_execute_threaded(
- &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
- }
- else {
- out = sh.execute(context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
- }
- }
- break;
- case EARLY_USE_INPUT_1:
- if (input[0]) {
- out = seq_render_strip(context, state, input[0], cfra);
- }
- break;
- case EARLY_USE_INPUT_2:
- if (input[1]) {
- out = seq_render_strip(context, state, input[1], cfra);
- }
- break;
- }
-
- for (i = 0; i < 3; i++) {
- IMB_freeImBuf(ibuf[i]);
- }
-
- if (out == NULL) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
-
- return out;
-}
-
-/**
- * Render individual view for multi-view or single (default view) for mono-view.
- */
-static ImBuf *seq_render_image_strip_view(const SeqRenderData *context,
- Sequence *seq,
- char *name,
- char *prefix,
- const char *ext,
- int view_id)
-{
-
- ImBuf *ibuf = NULL;
-
- int flag = IB_rect | IB_metadata;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL) {
- flag |= IB_alphamode_premul;
- }
-
- if (prefix[0] == '\0') {
- ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
- }
- else {
- char str[FILE_MAX];
- BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
- seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
- ibuf = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
- }
-
- if (ibuf == NULL) {
- return NULL;
- }
-
- /* We don't need both (speed reasons)! */
- if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
- imb_freerectImBuf(ibuf);
- }
-
- /* All sequencer color is done in SRGB space, linear gives odd cross-fades. */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- return ibuf;
-}
-
-static bool seq_image_strip_is_multiview_render(
- Scene *scene, Sequence *seq, int totfiles, char *name, char *r_prefix, const char *r_ext)
-{
- if (totfiles > 1) {
- BKE_scene_multiview_view_prefix_get(scene, name, r_prefix, &r_ext);
- if (r_prefix[0] == '\0') {
- return false;
- }
- }
- else {
- r_prefix[0] = '\0';
- }
-
- return (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
-}
-
-static ImBuf *seq_render_image_strip(const SeqRenderData *context,
- Sequence *seq,
- float UNUSED(nr),
- float cfra,
- bool *r_is_proxy_image)
-{
- char name[FILE_MAX];
- const char *ext = NULL;
- char prefix[FILE_MAX];
- ImBuf *ibuf = NULL;
-
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- if (s_elem == NULL) {
- return NULL;
- }
-
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
-
- /* Try to get a proxy image. */
- ibuf = seq_proxy_fetch(context, seq, cfra);
- if (ibuf != NULL) {
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- *r_is_proxy_image = true;
- return ibuf;
- }
-
- /* Proxy not found, render original. */
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- bool is_multiview_render = seq_image_strip_is_multiview_render(
- context->scene, seq, totfiles, name, prefix, ext);
-
- if (is_multiview_render) {
- int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
- ImBuf **ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
-
- for (int view_id = 0; view_id < totfiles; view_id++) {
- ibufs_arr[view_id] = seq_render_image_strip_view(context, seq, name, prefix, ext, view_id);
- }
-
- if (ibufs_arr[0] == NULL) {
- return NULL;
- }
-
- if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
- IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
- }
-
- for (int view_id = 0; view_id < totviews; view_id++) {
- SeqRenderData localcontext = *context;
- localcontext.view_id = view_id;
-
- if (view_id != context->view_id) {
- ibufs_arr[view_id] = seq_render_preprocess_ibuf(
- &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false);
- }
- }
-
- /* Return the original requested ImBuf. */
- ibuf = ibufs_arr[context->view_id];
-
- /* Remove the others (decrease their refcount). */
- for (int view_id = 0; view_id < totviews; view_id++) {
- if (ibufs_arr[view_id] != ibuf) {
- IMB_freeImBuf(ibufs_arr[view_id]);
- }
- }
-
- MEM_freeN(ibufs_arr);
- }
- else {
- ibuf = seq_render_image_strip_view(context, seq, name, prefix, ext, context->view_id);
- }
-
- if (ibuf == NULL) {
- return NULL;
- }
-
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
-
- return ibuf;
-}
-
-static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *context,
- Sequence *seq,
- int cfra)
-{
- char name[PROXY_MAXFILE];
- StripProxy *proxy = seq->strip->proxy;
-
- if (proxy->anim == NULL) {
- if (seq_proxy_get_custom_file_fname(seq, name, context->view_id)) {
- proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
- }
- if (proxy->anim == NULL) {
- return NULL;
- }
- }
-
- int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
- return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
-}
-
-/**
- * Render individual view for multi-view or single (default view) for mono-view.
- */
-static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context,
- Sequence *seq,
- float nr,
- float cfra,
- StripAnim *sanim,
- bool *r_is_proxy_image)
-{
- ImBuf *ibuf = NULL;
- IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
-
- IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
-
- if (SEQ_can_use_proxy(seq, psize)) {
- /* Try to get a proxy image.
- * Movie proxies are handled by ImBuf module with exception of `custom file` setting. */
- if (context->scene->ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE &&
- seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- ibuf = seq_render_movie_strip_custom_file_proxy(context, seq, cfra);
- }
- else {
- ibuf = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- psize);
- }
-
- if (ibuf != NULL) {
- *r_is_proxy_image = true;
- }
- }
-
- /* Fetching for requested proxy size failed, try fetching the original instead. */
- if (ibuf == NULL) {
- ibuf = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf == NULL) {
- return NULL;
- }
-
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- /* We don't need both (speed reasons)! */
- if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
- imb_freerectImBuf(ibuf);
- }
-
- return ibuf;
-}
-
-static ImBuf *seq_render_movie_strip(
- const SeqRenderData *context, Sequence *seq, float nr, float cfra, bool *r_is_proxy_image)
-{
- /* Load all the videos. */
- seq_open_anim_file(context->scene, seq, false);
-
- ImBuf *ibuf = NULL;
- StripAnim *sanim = seq->anims.first;
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- bool is_multiview_render = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (context->scene->r.scemode & R_MULTIVIEW) != 0 &&
- BLI_listbase_count_at_most(&seq->anims, totfiles + 1) == totfiles;
-
- if (is_multiview_render) {
- ImBuf **ibuf_arr;
- int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
- ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
- int ibuf_view_id;
-
- for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) {
- if (sanim->anim) {
- ibuf_arr[ibuf_view_id] = seq_render_movie_strip_view(
- context, seq, nr, cfra, sanim, r_is_proxy_image);
- }
- }
-
- if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
- if (ibuf_arr[0] == NULL) {
- /* Probably proxy hasn't been created yet. */
- MEM_freeN(ibuf_arr);
- return NULL;
- }
-
- IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
- }
-
- for (int view_id = 0; view_id < totviews; view_id++) {
- SeqRenderData localcontext = *context;
- localcontext.view_id = view_id;
-
- if (view_id != context->view_id) {
- ibuf_arr[view_id] = seq_render_preprocess_ibuf(
- &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false);
- }
- }
-
- /* Return the original requested ImBuf. */
- ibuf = ibuf_arr[context->view_id];
-
- /* Remove the others (decrease their refcount). */
- for (int view_id = 0; view_id < totviews; view_id++) {
- if (ibuf_arr[view_id] != ibuf) {
- IMB_freeImBuf(ibuf_arr[view_id]);
- }
- }
-
- MEM_freeN(ibuf_arr);
- }
- else {
- ibuf = seq_render_movie_strip_view(context, seq, nr, cfra, sanim, r_is_proxy_image);
- }
-
- if (ibuf == NULL) {
- return NULL;
- }
-
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
-
- return ibuf;
-}
-
-static ImBuf *seq_get_movieclip_ibuf(Sequence *seq, MovieClipUser user)
-{
- ImBuf *ibuf = NULL;
- float tloc[2], tscale, tangle;
- if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
- ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
- }
- else {
- ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
- }
- return ibuf;
-}
-
-static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
- Sequence *seq,
- float nr,
- bool *r_is_proxy_image)
-{
- ImBuf *ibuf = NULL;
- MovieClipUser user;
- IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
-
- if (!seq->clip) {
- return NULL;
- }
-
- memset(&user, 0, sizeof(MovieClipUser));
-
- BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame);
-
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- switch (psize) {
- case IMB_PROXY_NONE:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- break;
- case IMB_PROXY_100:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_100;
- break;
- case IMB_PROXY_75:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_75;
- break;
- case IMB_PROXY_50:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_50;
- break;
- case IMB_PROXY_25:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_25;
- break;
- }
-
- if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_UNDISTORTED) {
- user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT;
- }
-
- /* Try to get a proxy image. */
- ibuf = seq_get_movieclip_ibuf(seq, user);
-
- if (ibuf != NULL && psize != IMB_PROXY_NONE) {
- *r_is_proxy_image = true;
- }
-
- /* If proxy is not found, grab full-size frame. */
- if (ibuf == NULL) {
- user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
- ibuf = seq_get_movieclip_ibuf(seq, user);
- }
-
- return ibuf;
-}
-
-static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float)
-{
- /* TODO - add option to rasterize to alpha imbuf? */
- ImBuf *ibuf = NULL;
- float *maskbuf;
- int i;
-
- if (!mask) {
- return NULL;
- }
-
- AnimData *adt;
- Mask *mask_temp;
- MaskRasterHandle *mr_handle;
-
- mask_temp = (Mask *)BKE_id_copy_ex(
- NULL, &mask->id, NULL, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
-
- BKE_mask_evaluate(mask_temp, mask->sfra + nr, true);
-
- /* anim-data */
- adt = BKE_animdata_from_id(&mask->id);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
- context->depsgraph, mask->sfra + nr);
- BKE_animsys_evaluate_animdata(&mask_temp->id, adt, &anim_eval_context, ADT_RECALC_ANIM, false);
-
- maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
-
- mr_handle = BKE_maskrasterize_handle_new();
-
- BKE_maskrasterize_handle_init(
- mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
-
- BKE_id_free(NULL, &mask_temp->id);
-
- BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
-
- BKE_maskrasterize_handle_free(mr_handle);
-
- if (make_float) {
- /* pixels */
- const float *fp_src;
- float *fp_dst;
-
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rectfloat);
-
- fp_src = maskbuf;
- fp_dst = ibuf->rect_float;
- i = context->rectx * context->recty;
- while (--i) {
- fp_dst[0] = fp_dst[1] = fp_dst[2] = *fp_src;
- fp_dst[3] = 1.0f;
-
- fp_src += 1;
- fp_dst += 4;
- }
- }
- else {
- /* pixels */
- const float *fp_src;
- unsigned char *ub_dst;
-
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
-
- fp_src = maskbuf;
- ub_dst = (unsigned char *)ibuf->rect;
- i = context->rectx * context->recty;
- while (--i) {
- ub_dst[0] = ub_dst[1] = ub_dst[2] = (unsigned char)(*fp_src * 255.0f); /* already clamped */
- ub_dst[3] = 255;
-
- fp_src += 1;
- ub_dst += 4;
- }
- }
-
- MEM_freeN(maskbuf);
-
- return ibuf;
-}
-
-static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq, float nr)
-{
- bool make_float = (seq->flag & SEQ_MAKE_FLOAT) != 0;
-
- return seq_render_mask(context, seq->mask, nr, make_float);
-}
-
-static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
- Sequence *seq,
- float nr,
- float cfra)
-{
- ImBuf *ibuf = NULL;
- double frame;
- Object *camera;
-
- struct {
- int scemode;
- int cfra;
- float subframe;
-
-#ifdef DURIAN_CAMERA_SWITCH
- int mode;
-#endif
- } orig_data;
-
- /* Old info:
- * Hack! This function can be called from do_render_seq(), in that case
- * the seq->scene can already have a Render initialized with same name,
- * so we have to use a default name. (compositor uses scene name to
- * find render).
- * However, when called from within the UI (image preview in sequencer)
- * we do want to use scene Render, that way the render result is defined
- * for display in render/imagewindow
- *
- * Hmm, don't see, why we can't do that all the time,
- * and since G.is_rendering is uhm, gone... (Peter)
- */
-
- /* New info:
- * Using the same name for the renders works just fine as the do_render_seq()
- * render is not used while the scene strips are rendered.
- *
- * However rendering from UI (through sequencer_preview_area_draw) can crash in
- * very many cases since other renders (material preview, an actual render etc.)
- * can be started while this sequence preview render is running. The only proper
- * solution is to make the sequencer preview render a proper job, which can be
- * stopped when needed. This would also give a nice progress bar for the preview
- * space so that users know there's something happening.
- *
- * As a result the active scene now only uses OpenGL rendering for the sequencer
- * preview. This is far from nice, but is the only way to prevent crashes at this
- * time.
- *
- * -jahka
- */
-
- const bool is_rendering = G.is_rendering;
- const bool is_background = G.background;
- const bool do_seq_gl = is_rendering ? 0 : (context->scene->r.seq_prev_type) != OB_RENDER;
- bool have_comp = false;
- bool use_gpencil = true;
- /* do we need to re-evaluate the frame after rendering? */
- bool is_frame_update = false;
- Scene *scene;
- int is_thread_main = BLI_thread_is_main();
-
- /* don't refer to seq->scene above this point!, it can be NULL */
- if (seq->scene == NULL) {
- return NULL;
- }
-
- /* Prevent rendering scene recursively. */
- if (seq->scene == context->scene) {
- return NULL;
- }
-
- scene = seq->scene;
- frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
-
-#if 0 /* UNUSED */
- have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first);
-#endif
- have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
-
- /* Get view layer for the strip. */
- ViewLayer *view_layer = BKE_view_layer_default_render(scene);
- /* Depsgraph will be NULL when doing rendering. */
- Depsgraph *depsgraph = NULL;
-
- orig_data.scemode = scene->r.scemode;
- orig_data.cfra = scene->r.cfra;
- orig_data.subframe = scene->r.subframe;
-#ifdef DURIAN_CAMERA_SWITCH
- orig_data.mode = scene->r.mode;
-#endif
-
- BKE_scene_frame_set(scene, frame);
-
- if (seq->scene_camera) {
- camera = seq->scene_camera;
- }
- else {
- BKE_scene_camera_switch_update(scene);
- camera = scene->camera;
- }
-
- if (have_comp == false && camera == NULL) {
- goto finally;
- }
-
- if (seq->flag & SEQ_SCENE_NO_GPENCIL) {
- use_gpencil = false;
- }
-
- /* prevent eternal loop */
- scene->r.scemode &= ~R_DOSEQ;
-
-#ifdef DURIAN_CAMERA_SWITCH
- /* stooping to new low's in hackyness :( */
- scene->r.mode |= R_NO_CAMERA_SWITCH;
-#endif
-
- is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
-
- if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
- char err_out[256] = "unknown";
- const int width = (scene->r.xsch * scene->r.size) / 100;
- const int height = (scene->r.ysch * scene->r.size) / 100;
- const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
-
- unsigned int draw_flags = V3D_OFSDRAW_NONE;
- draw_flags |= (use_gpencil) ? V3D_OFSDRAW_SHOW_ANNOTATION : 0;
- draw_flags |= (context->scene->r.seq_flag & R_SEQ_OVERRIDE_SCENE_SETTINGS) ?
- V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS :
- 0;
-
- /* for old scene this can be uninitialized,
- * should probably be added to do_versions at some point if the functionality stays */
- if (context->scene->r.seq_prev_type == 0) {
- context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
- }
-
- /* opengl offscreen render */
- depsgraph = BKE_scene_ensure_depsgraph(context->bmain, scene, view_layer);
- BKE_scene_graph_update_for_newframe(depsgraph);
- ibuf = sequencer_view3d_fn(
- /* set for OpenGL render (NULL when scrubbing) */
- depsgraph,
- scene,
- &context->scene->display.shading,
- context->scene->r.seq_prev_type,
- camera,
- width,
- height,
- IB_rect,
- draw_flags,
- scene->r.alphamode,
- viewname,
- context->gpu_offscreen,
- err_out);
- if (ibuf == NULL) {
- fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
- }
- }
- else {
- Render *re = RE_GetSceneRender(scene);
- const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
- ImBuf **ibufs_arr;
-
- ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
-
- /* XXX: this if can be removed when sequence preview rendering uses the job system
- *
- * disable rendered preview for sequencer while rendering -- it's very much possible
- * that preview render will went into conflict with final render
- *
- * When rendering from command line renderer is called from main thread, in this
- * case it's always safe to render scene here
- */
- if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
- if (re == NULL) {
- re = RE_NewSceneRender(scene);
- }
-
- RE_RenderFrame(
- re, context->bmain, scene, have_comp ? NULL : view_layer, camera, frame, false);
-
- /* restore previous state after it was toggled on & off by RE_RenderFrame */
- G.is_rendering = is_rendering;
- }
-
- for (int view_id = 0; view_id < totviews; view_id++) {
- SeqRenderData localcontext = *context;
- RenderResult rres;
-
- localcontext.view_id = view_id;
-
- RE_AcquireResultImage(re, &rres, view_id);
-
- if (rres.rectf) {
- ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibufs_arr[view_id]->rect_float,
- rres.rectf,
- sizeof(float[4]) * rres.rectx * rres.recty);
-
- if (rres.rectz) {
- addzbuffloatImBuf(ibufs_arr[view_id]);
- memcpy(
- ibufs_arr[view_id]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
- }
-
- /* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
- }
- else if (rres.rect32) {
- ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibufs_arr[view_id]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
- }
-
- if (view_id != context->view_id) {
- BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], 0, false);
- }
-
- RE_ReleaseResultImage(re);
- }
-
- /* return the original requested ImBuf */
- ibuf = ibufs_arr[context->view_id];
-
- /* "remove" the others (decrease their refcount) */
- for (int view_id = 0; view_id < totviews; view_id++) {
- if (ibufs_arr[view_id] != ibuf) {
- IMB_freeImBuf(ibufs_arr[view_id]);
- }
- }
- MEM_freeN(ibufs_arr);
- }
-
-finally:
- /* restore */
- scene->r.scemode = orig_data.scemode;
- scene->r.cfra = orig_data.cfra;
- scene->r.subframe = orig_data.subframe;
-
- if (is_frame_update && (depsgraph != NULL)) {
- BKE_scene_graph_update_for_newframe(depsgraph);
- }
-
-#ifdef DURIAN_CAMERA_SWITCH
- /* stooping to new low's in hackyness :( */
- scene->r.mode &= orig_data.mode | ~R_NO_CAMERA_SWITCH;
-#endif
-
- return ibuf;
-}
-
-/**
- * Used for meta-strips & scenes with #SEQ_SCENE_STRIPS flag set.
- */
-static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- float nr)
-{
- ImBuf *ibuf = NULL;
- ListBase *seqbase = NULL;
- int offset;
-
- seqbase = BKE_sequence_seqbase_get(seq, &offset);
-
- if (seqbase && !BLI_listbase_is_empty(seqbase)) {
-
- if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
- BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset);
- }
-
- ibuf = seq_render_strip_stack(context,
- state,
- seqbase,
- /* scene strips don't have their start taken into account */
- nr + offset,
- 0);
- }
-
- return ibuf;
-}
-
-static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- float cfra,
- bool *r_is_proxy_image)
-{
- ImBuf *ibuf = NULL;
- float nr = BKE_sequencer_give_stripelem_index(seq, cfra);
- int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
- switch (type) {
- case SEQ_TYPE_META: {
- ibuf = do_render_strip_seqbase(context, state, seq, nr);
- break;
- }
-
- case SEQ_TYPE_SCENE: {
- if (seq->flag & SEQ_SCENE_STRIPS) {
- if (seq->scene && (context->scene != seq->scene)) {
- /* recursive check */
- if (BLI_linklist_index(state->scene_parents, seq->scene) != -1) {
- break;
- }
- LinkNode scene_parent = {
- .next = state->scene_parents,
- .link = seq->scene,
- };
- state->scene_parents = &scene_parent;
- /* end check */
-
- /* Use the Scene Seq's scene for the context when rendering the scene's sequences
- * (necessary for Multicam Selector among others).
- */
- SeqRenderData local_context = *context;
- local_context.scene = seq->scene;
- local_context.skip_cache = true;
-
- ibuf = do_render_strip_seqbase(&local_context, state, seq, nr);
-
- /* step back in the list */
- state->scene_parents = state->scene_parents->next;
- }
- }
- else {
- /* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr, cfra);
- }
-
- break;
- }
-
- case SEQ_TYPE_EFFECT: {
- ibuf = seq_render_effect_strip_impl(context, state, seq, cfra);
- break;
- }
-
- case SEQ_TYPE_IMAGE: {
- ibuf = seq_render_image_strip(context, seq, nr, cfra, r_is_proxy_image);
- break;
- }
-
- case SEQ_TYPE_MOVIE: {
- ibuf = seq_render_movie_strip(context, seq, nr, cfra, r_is_proxy_image);
- break;
- }
-
- case SEQ_TYPE_MOVIECLIP: {
- ibuf = seq_render_movieclip_strip(context, seq, nr, r_is_proxy_image);
-
- if (ibuf) {
- /* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */
- ImBuf *i = IMB_dupImBuf(ibuf);
- IMB_freeImBuf(ibuf);
- ibuf = i;
-
- if (ibuf->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
- }
- }
-
- break;
- }
-
- case SEQ_TYPE_MASK: {
- /* ibuf is always new */
- ibuf = seq_render_mask_strip(context, seq, nr);
- break;
- }
- }
-
- if (ibuf) {
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
-
- return ibuf;
-}
-
-/* Estimate time spent by the program rendering the strip */
-static clock_t seq_estimate_render_cost_begin(void)
-{
- return clock();
-}
-
-static float seq_estimate_render_cost_end(Scene *scene, clock_t begin)
-{
- clock_t end = clock();
- float time_spent = (float)(end - begin);
- float time_max = (1.0f / scene->r.frs_sec) * CLOCKS_PER_SEC;
-
- if (time_max != 0) {
- return time_spent / time_max;
- }
-
- return 1;
-}
-
-static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- float cfra,
- clock_t begin,
- bool use_preprocess,
- const bool is_proxy_image)
-{
- if (context->is_proxy_render == false &&
- (ibuf->x != context->rectx || ibuf->y != context->recty)) {
- use_preprocess = true;
- }
-
- if (use_preprocess) {
- float cost = seq_estimate_render_cost_end(context->scene, begin);
-
- /* TODO(Richard): It should be possible to store in cache if image is proxy,
- * but it adds quite a bit of complexity. Since proxies are fast to read, I would
- * rather simplify existing code a bit. */
- if (!is_proxy_image) {
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
- }
-
- /* Reset timer so we can get partial render time. */
- begin = seq_estimate_render_cost_begin();
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image);
- }
-
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
- return ibuf;
-}
-
-static ImBuf *seq_render_strip(const SeqRenderData *context,
- SeqRenderState *state,
- Sequence *seq,
- float cfra)
-{
- ImBuf *ibuf = NULL;
- bool use_preprocess = false;
- bool is_proxy_image = false;
-
- clock_t begin = seq_estimate_render_cost_begin();
-
- ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
- if (ibuf != NULL) {
- return ibuf;
- }
-
- ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false);
- if (ibuf == NULL) {
- ibuf = do_render_strip_uncached(context, state, seq, cfra, &is_proxy_image);
- }
-
- if (ibuf) {
- use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- ibuf = seq_render_preprocess_ibuf(
- context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image);
- }
-
- if (ibuf == NULL) {
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
-
- return ibuf;
-}
-
-/*********************** strip stack rendering functions *************************/
-
-static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
-{
- bool swap_input = false;
-
- /* bad hack, to fix crazy input ordering of
- * those two effects */
-
- if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
- swap_input = true;
- }
-
- return swap_input;
-}
-
-static int seq_get_early_out_for_blend_mode(Sequence *seq)
-{
- struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int early_out = sh.early_out(seq, facf, facf);
-
- if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
- return early_out;
- }
-
- if (seq_must_swap_input_in_blend_mode(seq)) {
- if (early_out == EARLY_USE_INPUT_2) {
- return EARLY_USE_INPUT_1;
- }
- if (early_out == EARLY_USE_INPUT_1) {
- return EARLY_USE_INPUT_2;
- }
- }
- return early_out;
-}
-
-static ImBuf *seq_render_strip_stack_apply_effect(
- const SeqRenderData *context, Sequence *seq, float cfra, ImBuf *ibuf1, ImBuf *ibuf2)
-{
- ImBuf *out;
- struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int swap_input = seq_must_swap_input_in_blend_mode(seq);
-
- if (swap_input) {
- if (sh.multithreaded) {
- out = BKE_sequencer_effect_execute_threaded(
- &sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
- }
- else {
- out = sh.execute(context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
- }
- }
- else {
- if (sh.multithreaded) {
- out = BKE_sequencer_effect_execute_threaded(
- &sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
- }
- else {
- out = sh.execute(context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
- }
- }
-
- return out;
-}
-
-static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
- SeqRenderState *state,
- ListBase *seqbasep,
- float cfra,
- int chanshown)
-{
- Sequence *seq_arr[MAXSEQ + 1];
- int count;
- int i;
- ImBuf *out = NULL;
- clock_t begin;
-
- count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
-
- if (count == 0) {
- return NULL;
- }
-
- for (i = count - 1; i >= 0; i--) {
- int early_out;
- Sequence *seq = seq_arr[i];
-
- out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_COMPOSITE, false);
-
- if (out) {
- break;
- }
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- out = seq_render_strip(context, state, seq, cfra);
- break;
- }
-
- early_out = seq_get_early_out_for_blend_mode(seq);
-
- switch (early_out) {
- case EARLY_NO_INPUT:
- case EARLY_USE_INPUT_2:
- out = seq_render_strip(context, state, seq, cfra);
- break;
- case EARLY_USE_INPUT_1:
- if (i == 0) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
- break;
- case EARLY_DO_EFFECT:
- if (i == 0) {
- begin = seq_estimate_render_cost_begin();
-
- ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
-
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(
- context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost, false);
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
- break;
- }
- if (out) {
- break;
- }
- }
-
- i++;
- for (; i < count; i++) {
- begin = seq_estimate_render_cost_begin();
- Sequence *seq = seq_arr[i];
-
- if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
- ImBuf *ibuf1 = out;
- ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
-
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(
- context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost, false);
- }
-
- return out;
-}
-
-/*
- * returned ImBuf is refed!
- * you have to free after usage!
- */
-
-ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown)
-{
- Scene *scene = context->scene;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- ListBase *seqbasep;
-
- if (ed == NULL) {
- return NULL;
- }
-
- if ((chanshown < 0) && !BLI_listbase_is_empty(&ed->metastack)) {
- int count = BLI_listbase_count(&ed->metastack);
- count = max_ii(count + chanshown, 0);
- seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep;
- }
- else {
- seqbasep = ed->seqbasep;
- }
-
- SeqRenderState state;
- sequencer_state_init(&state);
- ImBuf *out = NULL;
- Sequence *seq_arr[MAXSEQ + 1];
- int count;
-
- count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
-
- if (count) {
- out = BKE_sequencer_cache_get(
- context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
- }
-
- BKE_sequencer_cache_free_temp_cache(context->scene, context->task_id, cfra);
-
- clock_t begin = seq_estimate_render_cost_begin();
- float cost = 0;
-
- if (count && !out) {
- BLI_mutex_lock(&seq_render_mutex);
- out = seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
- cost = seq_estimate_render_cost_end(context->scene, begin);
-
- if (context->is_prefetch_render) {
- BKE_sequencer_cache_put(
- context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost, false);
- }
- else {
- BKE_sequencer_cache_put_if_possible(
- context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost, false);
- }
- BLI_mutex_unlock(&seq_render_mutex);
- }
-
- BKE_sequencer_prefetch_start(context, cfra, cost);
-
- return out;
-}
-
-ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
- float cfra,
- int chan_shown,
- ListBase *seqbasep)
-{
- SeqRenderState state;
- sequencer_state_init(&state);
-
- return seq_render_strip_stack(context, &state, seqbasep, cfra, chan_shown);
-}
-
-ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context, float cfra, Sequence *seq)
-{
- SeqRenderState state;
- sequencer_state_init(&state);
-
- ImBuf *ibuf = seq_render_strip(context, &state, seq, cfra);
-
- return ibuf;
-}
-
/* check whether sequence cur depends on seq */
bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
{
@@ -5491,35 +2605,6 @@ void BKE_sequence_alpha_mode_from_extension(Sequence *seq)
}
}
-void BKE_sequence_init_colorspace(Sequence *seq)
-{
- if (seq->strip && seq->strip->stripdata) {
- char name[FILE_MAX];
- ImBuf *ibuf;
-
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
-
- /* initialize input color space */
- if (seq->type == SEQ_TYPE_IMAGE) {
- ibuf = IMB_loadiffname(
- name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name);
-
- /* byte images are default to straight alpha, however sequencer
- * works in premul space, so mark strip to be premultiplied first
- */
- seq->alpha_mode = SEQ_ALPHA_STRAIGHT;
- if (ibuf) {
- if (ibuf->flags & IB_alphamode_premul) {
- seq->alpha_mode = IMA_ALPHA_PREMUL;
- }
-
- IMB_freeImBuf(ibuf);
- }
- }
- }
-}
-
float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
{
switch (seq->type) {
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index 55e19f80fcd..d5220de809f 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -44,61 +44,10 @@ struct StripElem;
/* **********************************************************************
* sequencer.c
*
- * sequencer render functions
- * ********************************************************************** */
-
-struct ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
- float cfra,
- int chan_shown,
- struct ListBase *seqbasep);
-struct ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
- const SeqRenderData *context,
- struct Sequence *seq,
- float cfra,
- float facf0,
- float facf1,
- struct ImBuf *ibuf1,
- struct ImBuf *ibuf2,
- struct ImBuf *ibuf3);
-struct ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context,
- int mask_input_type,
- struct Sequence *mask_sequence,
- struct Mask *mask_id,
- int cfra,
- int fra_offset,
- bool make_float);
-void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb,
- struct ImBuf *ibuf,
- float mul,
- bool make_float,
- struct ImBuf *mask_input);
-
-/* **********************************************************************
- * sequencer.c
- *
- * sequencer color space functions
- * ********************************************************************** */
-
-void BKE_sequencer_imbuf_to_sequencer_space(struct Scene *scene,
- struct ImBuf *ibuf,
- bool make_float);
-
-/* **********************************************************************
- * sequencer.c
- *
* sequencer scene functions
* ********************************************************************** */
void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
-int BKE_sequencer_get_shown_sequences(struct ListBase *seqbasep,
- int cfra,
- int chanshown,
- struct Sequence **seq_arr_out);
-bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
- struct Sequence *seq,
- float cfra);
-float BKE_sequencer_give_stripelem_index(struct Sequence *seq, float cfra);
-
/* **********************************************************************
* image_cache.c
*
@@ -174,6 +123,16 @@ 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);
/* **********************************************************************
* sequencer.c