720 lines
22 KiB
C++
720 lines
22 KiB
C++
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
* SPDX-FileCopyrightText: 2003-2026 Blender Authors
|
|
* SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup sequencer
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_sequence_types.h"
|
|
|
|
#include "BLI_fileops.h"
|
|
#include "BLI_math_base.h"
|
|
#include "BLI_path_utils.hh"
|
|
#include "BLI_string.h"
|
|
|
|
#ifdef WIN32
|
|
# include "BLI_winstuff.h"
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#include "BKE_global.hh"
|
|
#include "BKE_image.hh"
|
|
#include "BKE_main.hh"
|
|
#include "BKE_scene.hh"
|
|
|
|
#include "WM_types.hh"
|
|
|
|
#include "IMB_imbuf.hh"
|
|
#include "IMB_imbuf_types.hh"
|
|
|
|
#include "MOV_read.hh"
|
|
|
|
#include "SEQ_proxy.hh"
|
|
#include "SEQ_relations.hh"
|
|
#include "SEQ_render.hh"
|
|
#include "SEQ_sequencer.hh"
|
|
#include "SEQ_time.hh"
|
|
|
|
#include "cache/intra_frame_cache.hh"
|
|
#include "multiview.hh"
|
|
#include "proxy.hh"
|
|
#include "render.hh"
|
|
#include "sequencer.hh"
|
|
#include "utils.hh"
|
|
|
|
namespace blender::seq {
|
|
|
|
struct ProxyBuildContext {
|
|
MovieProxyBuilder *movie_proxy_builder = nullptr;
|
|
|
|
int size_flags = 0;
|
|
int quality = 0;
|
|
bool overwrite = false;
|
|
int view_id = 0;
|
|
|
|
Main *bmain = nullptr;
|
|
Scene *scene = nullptr;
|
|
Strip *strip = nullptr;
|
|
};
|
|
|
|
IMB_Proxy_Size rendersize_to_proxysize(eSpaceSeq_Proxy_RenderSize 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;
|
|
default:
|
|
return IMB_PROXY_NONE;
|
|
}
|
|
}
|
|
|
|
float rendersize_to_scale_factor(eSpaceSeq_Proxy_RenderSize render_size)
|
|
{
|
|
switch (render_size) {
|
|
case SEQ_RENDER_SIZE_PROXY_25:
|
|
return 0.25f;
|
|
case SEQ_RENDER_SIZE_PROXY_50:
|
|
return 0.5f;
|
|
case SEQ_RENDER_SIZE_PROXY_75:
|
|
return 0.75f;
|
|
default:
|
|
return 1.0f;
|
|
}
|
|
}
|
|
|
|
bool seq_proxy_get_custom_file_filepath(const Strip *strip, char *filepath, const int view_id)
|
|
{
|
|
/* Ideally this would be #PROXY_MAXFILE however BLI_path_abs clamps to #FILE_MAX. */
|
|
char filepath_temp[FILE_MAX];
|
|
char suffix[24];
|
|
StripProxy *proxy = strip->data->proxy;
|
|
|
|
if (proxy == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
BLI_path_join(filepath_temp, sizeof(filepath_temp), proxy->dirpath, proxy->filename);
|
|
BLI_path_abs(filepath_temp, BKE_main_blendfile_path_from_global());
|
|
|
|
if (view_id > 0) {
|
|
SNPRINTF(suffix, "_%d", view_id);
|
|
/* This will actually append suffix after extension
|
|
* which is weird but how was originally coded in multi-view branch. */
|
|
BLI_snprintf(filepath, PROXY_MAXFILE, "%s_%s", filepath_temp, suffix);
|
|
}
|
|
else {
|
|
BLI_strncpy(filepath, filepath_temp, PROXY_MAXFILE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool seq_proxy_get_filepath_for_elem(const Scene *scene,
|
|
const Strip &strip,
|
|
const StripElem &strip_elem,
|
|
eSpaceSeq_Proxy_RenderSize render_size,
|
|
char *filepath,
|
|
const int view_id)
|
|
{
|
|
char dirpath[PROXY_MAXFILE];
|
|
char suffix[24] = {'\0'};
|
|
Editing *ed = editing_get(scene);
|
|
StripProxy *proxy = strip.data->proxy;
|
|
|
|
if (proxy == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
/* Multi-view suffix. */
|
|
if (view_id > 0) {
|
|
SNPRINTF(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_filepath(&strip, filepath, view_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
|
|
/* Per project default. */
|
|
if (ed->proxy_dir[0] == 0) {
|
|
STRNCPY(dirpath, "//BL_proxy");
|
|
}
|
|
else { /* Per project with custom dirpath. */
|
|
STRNCPY(dirpath, ed->proxy_dir);
|
|
}
|
|
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
|
|
}
|
|
else {
|
|
/* Pre strip with custom dir. */
|
|
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) {
|
|
STRNCPY(dirpath, strip.data->proxy->dirpath);
|
|
}
|
|
else { /* Per strip default. */
|
|
SNPRINTF(dirpath, "%s" SEP_STR "BL_proxy", strip.data->dirpath);
|
|
}
|
|
}
|
|
|
|
/* Proxy size number to be used in path. */
|
|
int proxy_size_number = rendersize_to_scale_factor(render_size) * 100;
|
|
|
|
BLI_snprintf(filepath,
|
|
PROXY_MAXFILE,
|
|
"%s" SEP_STR "images" SEP_STR "%d" SEP_STR "%s_proxy%s.jpg",
|
|
dirpath,
|
|
proxy_size_number,
|
|
strip_elem.filename,
|
|
suffix);
|
|
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
|
|
return true;
|
|
}
|
|
|
|
static bool seq_proxy_get_filepath(Scene *scene,
|
|
Strip *strip,
|
|
int timeline_frame,
|
|
eSpaceSeq_Proxy_RenderSize render_size,
|
|
char *filepath,
|
|
const int view_id)
|
|
{
|
|
if (strip->data->proxy == nullptr) {
|
|
return false;
|
|
}
|
|
return seq_proxy_get_filepath_for_elem(scene,
|
|
*strip,
|
|
*render_give_stripelem(scene, strip, timeline_frame),
|
|
render_size,
|
|
filepath,
|
|
view_id);
|
|
}
|
|
|
|
bool can_use_proxy(const RenderData *context, const Strip *strip, IMB_Proxy_Size psize)
|
|
{
|
|
if (strip->data->proxy == nullptr || !context->use_proxies) {
|
|
return false;
|
|
}
|
|
|
|
short size_flags = strip->data->proxy->build_size_flags;
|
|
return (strip->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE &&
|
|
(size_flags & psize) != 0;
|
|
}
|
|
|
|
ImBuf *seq_proxy_fetch(const RenderData *context, Strip *strip, int timeline_frame)
|
|
{
|
|
char filepath[PROXY_MAXFILE];
|
|
StripProxy *proxy = strip->data->proxy;
|
|
const eSpaceSeq_Proxy_RenderSize psize = eSpaceSeq_Proxy_RenderSize(
|
|
context->preview_render_size);
|
|
|
|
/* only use proxies, if they are enabled (even if present!) */
|
|
if (!can_use_proxy(context, strip, rendersize_to_proxysize(psize))) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
|
|
int frameno = round_fl_to_int(give_frame_index(context->scene, strip, timeline_frame)) +
|
|
strip->anim_startofs;
|
|
if (proxy->anim == nullptr) {
|
|
if (seq_proxy_get_filepath(
|
|
context->scene, strip, timeline_frame, psize, filepath, context->view_id) == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
/* Sequencer takes care of colorspace conversion of the result. The input is the best to be
|
|
* kept unchanged for the performance reasons. */
|
|
proxy->anim = openanim(
|
|
filepath, ImBufFlags::Zero, 0, true, strip->data->colorspace_settings.name);
|
|
}
|
|
if (proxy->anim == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
strip_open_anim_file(context->scene, strip, true);
|
|
return MOV_decode_frame(proxy->anim, frameno, IMB_PROXY_NONE);
|
|
}
|
|
|
|
if (seq_proxy_get_filepath(
|
|
context->scene, strip, timeline_frame, psize, filepath, context->view_id) == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if (BLI_exists(filepath)) {
|
|
/* Proxies are already be in the sequencer colorspace for fast loading, don't perform
|
|
* conversion of float to scene linear that would usually be done. */
|
|
char colorspace[IMA_MAX_SPACE];
|
|
STRNCPY(colorspace, context->scene->sequencer_colorspace_settings.name);
|
|
return IMB_load_image_from_filepath(filepath,
|
|
ImBufFlags::ByteData | ImBufFlags::Metadata |
|
|
ImBufFlags::NoColorspaceConvert,
|
|
colorspace);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/**
|
|
* Cache the result of #BKE_scene_multiview_view_prefix_get.
|
|
*/
|
|
struct MultiViewPrefixVars {
|
|
char prefix[FILE_MAX];
|
|
char ext[FILE_MAXFILE];
|
|
};
|
|
|
|
/**
|
|
* Returns whether the file this context would read from even exist,
|
|
* if not, don't create the context.
|
|
*
|
|
* \param prefix_vars: Stores prefix variables for reuse,
|
|
* these variables are for internal use, the caller must not depend on them.
|
|
*
|
|
* \note This function must first a `view_id` of zero, to initialize `prefix_vars`
|
|
* for use with other views.
|
|
*/
|
|
static bool seq_proxy_multiview_context_invalid(Strip *strip,
|
|
Scene *scene,
|
|
const int view_id,
|
|
MultiViewPrefixVars *prefix_vars)
|
|
{
|
|
if ((scene->r.scemode & R_MULTIVIEW) == 0) {
|
|
return false;
|
|
}
|
|
|
|
if ((strip->type == STRIP_TYPE_IMAGE) && (strip->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
|
|
if (view_id == 0) {
|
|
/* Clear on first use. */
|
|
prefix_vars->prefix[0] = '\0';
|
|
prefix_vars->ext[0] = '\0';
|
|
|
|
char filepath[FILE_MAX];
|
|
BLI_path_join(
|
|
filepath, sizeof(filepath), strip->data->dirpath, strip->data->stripdata->filename);
|
|
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&scene->id));
|
|
const char *ext_ptr = nullptr;
|
|
BKE_scene_multiview_view_prefix_get(scene, filepath, prefix_vars->prefix, &ext_ptr);
|
|
if (ext_ptr != nullptr) {
|
|
STRNCPY(prefix_vars->ext, ext_ptr);
|
|
}
|
|
}
|
|
|
|
if (prefix_vars->prefix[0] == '\0') {
|
|
return view_id != 0;
|
|
}
|
|
|
|
char filepath[FILE_MAX];
|
|
seq_multiview_name(scene, view_id, prefix_vars->prefix, prefix_vars->ext, filepath, FILE_MAX);
|
|
if (BLI_access(filepath, 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(Strip *strip, Scene *scene)
|
|
{
|
|
int num_views = 1;
|
|
|
|
if ((scene->r.scemode & R_MULTIVIEW) == 0) {
|
|
return 1;
|
|
}
|
|
|
|
switch (strip->type) {
|
|
case STRIP_TYPE_MOVIE: {
|
|
num_views = int(strip->runtime->movie_readers.size());
|
|
break;
|
|
}
|
|
case STRIP_TYPE_IMAGE: {
|
|
switch (strip->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;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return num_views;
|
|
}
|
|
|
|
static bool seq_proxy_need_rebuild(Strip *strip, MovieReader *anim)
|
|
{
|
|
if ((strip->data->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0) {
|
|
return true;
|
|
}
|
|
|
|
IMB_Proxy_Size required_proxies = IMB_Proxy_Size(strip->data->proxy->build_size_flags);
|
|
int built_proxies = MOV_get_existing_proxies(anim);
|
|
return (required_proxies & built_proxies) != required_proxies;
|
|
}
|
|
|
|
bool proxy_build_start(Main *bmain,
|
|
Scene *scene,
|
|
Strip *strip,
|
|
Set<std::string> *processed_paths,
|
|
bool build_only_on_bad_performance,
|
|
Vector<ProxyBuildContext *> &r_queue)
|
|
{
|
|
if (!strip->data || !strip->data->proxy) {
|
|
return true;
|
|
}
|
|
|
|
if (!(strip->flag & SEQ_USE_PROXY)) {
|
|
return true;
|
|
}
|
|
|
|
int num_files = seq_proxy_context_count(strip, scene);
|
|
|
|
MultiViewPrefixVars prefix_vars; /* Initialized by #seq_proxy_multiview_context_invalid. */
|
|
for (int i = 0; i < num_files; i++) {
|
|
if (seq_proxy_multiview_context_invalid(strip, scene, i, &prefix_vars)) {
|
|
continue;
|
|
}
|
|
|
|
/* Check if proxies are already built here, because actually opening anims takes a lot of
|
|
* time. */
|
|
strip_open_anim_file(scene, strip, false);
|
|
MovieReader *anim = strip->runtime->movie_reader_get(i);
|
|
if (anim && !seq_proxy_need_rebuild(strip, anim)) {
|
|
continue;
|
|
}
|
|
|
|
strip_free_movie_readers(strip);
|
|
|
|
ProxyBuildContext *context = MEM_new<ProxyBuildContext>("strip proxy rebuild context");
|
|
|
|
Strip *strip_new = strip_duplicate_recursive(
|
|
bmain, scene, scene, nullptr, strip, StripDuplicate::Selected);
|
|
|
|
context->size_flags = strip_new->data->proxy->build_size_flags;
|
|
context->quality = strip_new->data->proxy->quality;
|
|
context->overwrite = (strip_new->data->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
|
|
|
|
context->bmain = bmain;
|
|
context->scene = scene;
|
|
context->strip = strip_new;
|
|
|
|
context->view_id = i; /* only for images */
|
|
|
|
if (strip_new->type == STRIP_TYPE_MOVIE) {
|
|
strip_open_anim_file(scene, strip_new, true);
|
|
anim = strip_new->runtime->movie_reader_get(i);
|
|
if (anim) {
|
|
context->movie_proxy_builder = MOV_proxy_builder_start(anim,
|
|
context->size_flags,
|
|
context->quality,
|
|
context->overwrite,
|
|
processed_paths,
|
|
build_only_on_bad_performance);
|
|
}
|
|
if (!context->movie_proxy_builder) {
|
|
MEM_delete(context);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
r_queue.append(context);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void seq_proxy_build_frame(const Scene *scene,
|
|
const int view_id,
|
|
ImBuf *ibuf_full,
|
|
const Strip &strip,
|
|
const StripElem &strip_elem,
|
|
int proxy_render_size,
|
|
const bool overwrite)
|
|
{
|
|
char filepath[PROXY_MAXFILE];
|
|
|
|
if (!seq_proxy_get_filepath_for_elem(scene,
|
|
strip,
|
|
strip_elem,
|
|
eSpaceSeq_Proxy_RenderSize(proxy_render_size),
|
|
filepath,
|
|
view_id))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!overwrite && BLI_exists(filepath)) {
|
|
return;
|
|
}
|
|
|
|
const int rectx = (proxy_render_size * ibuf_full->x) / 100;
|
|
const int recty = (proxy_render_size * ibuf_full->y) / 100;
|
|
|
|
ImBuf *ibuf = ibuf_full;
|
|
if (ibuf_full->x != rectx || ibuf_full->y != recty) {
|
|
ibuf = IMB_scale_into_new(ibuf_full, rectx, recty, IMBScaleFilter::Nearest, true);
|
|
}
|
|
|
|
const int quality = strip.data->proxy->quality;
|
|
const bool save_float = ibuf->float_data() != nullptr;
|
|
ibuf->foptions.quality = quality;
|
|
if (save_float) {
|
|
/* Float image: save as EXR with FP16 data and DWAA compression. */
|
|
ibuf->ftype = IMB_FTYPE_OPENEXR;
|
|
ibuf->foptions.flag = OPENEXR_HALF | R_IMF_EXR_CODEC_DWAA;
|
|
}
|
|
else {
|
|
/* Byte image: save as JPG. */
|
|
ibuf->ftype = IMB_FTYPE_JPG;
|
|
if (ibuf->can_contain_alpha()) {
|
|
ibuf->color_mode = ImColorMode::RGB; /* JPGs do not support alpha. */
|
|
}
|
|
}
|
|
BLI_file_ensure_parent_dir_exists(filepath);
|
|
|
|
const bool ok = IMB_save_image(
|
|
ibuf, filepath, save_float ? ImBufFlags::FloatData : ImBufFlags::ByteData);
|
|
if (ok == false) {
|
|
perror(filepath);
|
|
}
|
|
|
|
if (ibuf != ibuf_full) {
|
|
IMB_freeImBuf(ibuf);
|
|
}
|
|
}
|
|
|
|
static ImBuf *render_image_strip_frame(const ProxyBuildContext &context,
|
|
const Strip &strip,
|
|
char *filepath,
|
|
char *prefix,
|
|
const char *ext,
|
|
int view_id)
|
|
{
|
|
ImBuf *ibuf = nullptr;
|
|
|
|
ImBufFlags flag = ImBufFlags::ByteData | ImBufFlags::Metadata | ImBufFlags::MultiLayer;
|
|
if (strip.alpha_mode == SEQ_ALPHA_PREMUL) {
|
|
flag |= ImBufFlags::AlphaPremul;
|
|
}
|
|
|
|
if (prefix[0] == '\0') {
|
|
ibuf = IMB_load_image_from_filepath(filepath, flag, strip.data->colorspace_settings.name);
|
|
}
|
|
else {
|
|
char filepath_view[FILE_MAX];
|
|
BKE_scene_multiview_view_prefix_get(context.scene, filepath, prefix, &ext);
|
|
seq_multiview_name(context.scene, view_id, prefix, ext, filepath_view, FILE_MAX);
|
|
ibuf = IMB_load_image_from_filepath(filepath_view, flag, strip.data->colorspace_settings.name);
|
|
}
|
|
if (ibuf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
convert_multilayer_ibuf(ibuf);
|
|
if (ibuf->float_data() != nullptr && ibuf->byte_data() != nullptr) {
|
|
IMB_free_byte_pixels(ibuf); /* If both float & byte exist, free byte buffer. */
|
|
}
|
|
ensure_ibuf_is_sequencer_space(context.scene, ibuf, false);
|
|
return ibuf;
|
|
}
|
|
|
|
static void image_proxy_builder_process(ProxyBuildContext &context,
|
|
const bool *job_stop,
|
|
bool *job_update_ui,
|
|
const FunctionRef<void(float progress)> set_progress_fn)
|
|
{
|
|
if (!context.strip || !context.strip->data) {
|
|
return;
|
|
}
|
|
const Strip &strip = *context.strip;
|
|
if (!(strip.flag & SEQ_USE_PROXY)) {
|
|
return;
|
|
}
|
|
|
|
/* If proxy is set to user-specified custom file, no need to rebuild anything. */
|
|
/* that's why it is called custom... */
|
|
if (strip.data->proxy && (strip.data->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
|
|
return;
|
|
}
|
|
|
|
const char *base_path = ID_BLEND_PATH_FROM_GLOBAL(&context.scene->id);
|
|
const int tot_views = BKE_scene_multiview_num_views_get(&context.scene->r);
|
|
|
|
for (int elem_index = 0; elem_index < strip.len; elem_index++) {
|
|
const StripElem &s_elem = strip.data->stripdata[elem_index];
|
|
|
|
char filepath[FILE_MAX];
|
|
const char *ext = nullptr;
|
|
char prefix[FILE_MAX];
|
|
|
|
ImBuf *ibuf = nullptr;
|
|
|
|
BLI_path_join(filepath, sizeof(filepath), strip.data->dirpath, s_elem.filename);
|
|
BLI_path_abs(filepath, base_path);
|
|
|
|
const int totfiles = seq_num_files(context.scene, strip.views_format, true);
|
|
bool is_multiview_render = seq_image_strip_is_multiview_render(
|
|
context.scene, &strip, totfiles, filepath, prefix, ext);
|
|
|
|
if (is_multiview_render) {
|
|
Array<ImBuf *> ibufs_arr(tot_views, nullptr);
|
|
|
|
for (int view_id = 0; view_id < totfiles; view_id++) {
|
|
ibufs_arr[view_id] = render_image_strip_frame(
|
|
context, strip, filepath, prefix, ext, view_id);
|
|
}
|
|
|
|
if (ibufs_arr[0] != nullptr) {
|
|
if (strip.views_format == R_IMF_VIEWS_STEREO_3D) {
|
|
IMB_ImBufFromStereo3d(strip.stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
|
|
}
|
|
|
|
/* Return the requested image; release the others. */
|
|
ibuf = ibufs_arr[context.view_id];
|
|
for (ImBuf *ib : ibufs_arr) {
|
|
if (ib != ibuf) {
|
|
IMB_freeImBuf(ib);
|
|
}
|
|
}
|
|
if (ibuf) {
|
|
seq_imbuf_assign_spaces(context.scene, ibuf);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ibuf = render_image_strip_frame(context, strip, filepath, prefix, ext, context.view_id);
|
|
}
|
|
|
|
if (ibuf != nullptr) {
|
|
if (context.size_flags & IMB_PROXY_25) {
|
|
seq_proxy_build_frame(
|
|
context.scene, context.view_id, ibuf, strip, s_elem, 25, context.overwrite);
|
|
}
|
|
if (context.size_flags & IMB_PROXY_50) {
|
|
seq_proxy_build_frame(
|
|
context.scene, context.view_id, ibuf, strip, s_elem, 50, context.overwrite);
|
|
}
|
|
if (context.size_flags & IMB_PROXY_75) {
|
|
seq_proxy_build_frame(
|
|
context.scene, context.view_id, ibuf, strip, s_elem, 75, context.overwrite);
|
|
}
|
|
if (context.size_flags & IMB_PROXY_100) {
|
|
seq_proxy_build_frame(
|
|
context.scene, context.view_id, ibuf, strip, s_elem, 100, context.overwrite);
|
|
}
|
|
|
|
if (set_progress_fn) {
|
|
float progress = float(elem_index) / float(strip.len);
|
|
set_progress_fn(progress);
|
|
}
|
|
|
|
*job_update_ui = true;
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
}
|
|
|
|
if (*job_stop || G.is_break) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void close_movie_proxy_builder(ProxyBuildContext *context, bool stop)
|
|
{
|
|
if (context->movie_proxy_builder == nullptr) {
|
|
return;
|
|
}
|
|
for (MovieReader *movie : context->strip->runtime->movie_readers) {
|
|
MOV_close_proxies(movie);
|
|
}
|
|
MOV_proxy_builder_finish(context->movie_proxy_builder, stop);
|
|
context->movie_proxy_builder = nullptr;
|
|
}
|
|
|
|
void proxy_build_process(ProxyBuildContext *context,
|
|
const bool *should_stop,
|
|
bool *has_updated,
|
|
const FunctionRef<void(float progress)> set_progress_fn)
|
|
{
|
|
if (context->strip->type == STRIP_TYPE_MOVIE) {
|
|
if (context->movie_proxy_builder) {
|
|
MOV_proxy_builder_process(
|
|
context->movie_proxy_builder, should_stop, has_updated, set_progress_fn);
|
|
close_movie_proxy_builder(context, *should_stop);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (context->strip->type == STRIP_TYPE_IMAGE) {
|
|
image_proxy_builder_process(*context, should_stop, has_updated, set_progress_fn);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void proxy_build_finish(ProxyBuildContext *context)
|
|
{
|
|
close_movie_proxy_builder(context, false);
|
|
seq_free_strip_recurse(nullptr, context->strip, true);
|
|
|
|
MEM_delete(context);
|
|
}
|
|
|
|
void proxy_set(Strip *strip, bool value)
|
|
{
|
|
if (value) {
|
|
strip->flag |= SEQ_USE_PROXY;
|
|
if (strip->data->proxy == nullptr) {
|
|
strip->data->proxy = seq_strip_proxy_alloc();
|
|
}
|
|
}
|
|
else {
|
|
strip->flag &= ~SEQ_USE_PROXY;
|
|
}
|
|
}
|
|
|
|
void seq_proxy_index_dir_set(MovieReader *anim, const char *base_dir)
|
|
{
|
|
char dirname[FILE_MAX];
|
|
char filename[FILE_MAXFILE];
|
|
|
|
MOV_get_filename(anim, filename, FILE_MAXFILE);
|
|
BLI_path_join(dirname, sizeof(dirname), base_dir, filename);
|
|
MOV_set_custom_proxy_dir(anim, dirname);
|
|
}
|
|
|
|
void free_strip_proxy(Strip *strip)
|
|
{
|
|
if (strip->data && strip->data->proxy && strip->data->proxy->anim) {
|
|
MOV_close(strip->data->proxy->anim);
|
|
strip->data->proxy->anim = nullptr;
|
|
}
|
|
}
|
|
|
|
} // namespace blender::seq
|