VSE: Refactor VSE strip loading code

Isolate RNA and operator logic from functions that create strips.
 - Operator specific code was removed from `SeqLoadInfo` structure and
   `SEQ_add_*` functions.
 - Strip loading code was removed from RNA and operator functions.
 - `SEQ_add_*` API was unified to work on `SeqLoadData` struct.
   Only exception is image strip, which require files to be loaded
   separately to strip creation itself. This is not ideal, but I think
   it's acceptable.
 - Some functions and variables were refactored so the code reads
   better.

There are minor functional changes (coincidental bugfixes):
 - Operator errors are reported per-strip. Previously they were not
   reported at all?
 - `new_sound()` RNA API function now create sound with length of 1
   if source file does not exist. Previously it created strip with
   length of 0.
 - Replace selection operator property wasn't working correctly.
   Fixed in this patch.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9760
This commit is contained in:
Richard Antalik 2021-03-02 12:08:16 +01:00
parent b279fef85d
commit bbb1936411
Notes: blender-bot 2023-02-14 04:40:22 +01:00
Referenced by commit 787350dde8, Fix T90737: VSE adding nested strips could have non-unique names
Referenced by commit f65a3172a8, Fix issues introduced strip loading refactoring
Referenced by issue #90737, Effect Strip added to a nested Metastrip gets duplicate name (thus inherits fcurves from other Strips)
5 changed files with 775 additions and 646 deletions

View File

@ -36,6 +36,7 @@
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_sound_types.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
@ -44,6 +45,8 @@
#include "BKE_movieclip.h"
#include "BKE_report.h"
#include "IMB_imbuf.h"
#include "WM_api.h"
#include "WM_types.h"
@ -89,8 +92,6 @@ typedef struct SequencerAddData {
#define SEQPROP_NOCHAN (1 << 3)
#define SEQPROP_FIT_METHOD (1 << 4)
#define SELECT 1
static const EnumPropertyItem scale_fit_methods[] = {
{SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},
{SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"},
@ -216,7 +217,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i
}
}
static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperator *op)
static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@ -224,69 +225,56 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
const bool relative = (prop = RNA_struct_find_property(op->ptr, "relative_path")) &&
RNA_property_boolean_get(op->ptr, prop);
int is_file = -1;
memset(seq_load, 0, sizeof(SeqLoadInfo));
memset(load_data, 0, sizeof(SeqLoadData));
seq_load->start_frame = RNA_int_get(op->ptr, "frame_start");
seq_load->end_frame = seq_load->start_frame;
seq_load->channel = RNA_int_get(op->ptr, "channel");
seq_load->len = 1;
seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method");
SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method);
load_data->start_frame = RNA_int_get(op->ptr, "frame_start");
load_data->channel = RNA_int_get(op->ptr, "channel");
load_data->image.end_frame = load_data->start_frame;
load_data->image.len = 1;
load_data->fit_method = RNA_enum_get(op->ptr, "fit_method");
SEQ_tool_settings_fit_method_set(CTX_data_scene(C), load_data->fit_method);
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
/* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
RNA_property_string_get(op->ptr, prop, load_data->path);
is_file = 1;
}
else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
/* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
RNA_property_string_get(op->ptr, prop, load_data->path);
is_file = 0;
}
if ((is_file != -1) && relative) {
BLI_path_rel(seq_load->path, BKE_main_blendfile_path(bmain));
BLI_path_rel(load_data->path, BKE_main_blendfile_path(bmain));
}
if ((prop = RNA_struct_find_property(op->ptr, "frame_end"))) {
seq_load->end_frame = RNA_property_int_get(op->ptr, prop);
}
if ((prop = RNA_struct_find_property(op->ptr, "replace_sel")) &&
RNA_property_boolean_get(op->ptr, prop)) {
seq_load->flag |= SEQ_LOAD_REPLACE_SEL;
load_data->image.end_frame = RNA_property_int_get(op->ptr, prop);
}
if ((prop = RNA_struct_find_property(op->ptr, "cache")) &&
RNA_property_boolean_get(op->ptr, prop)) {
seq_load->flag |= SEQ_LOAD_SOUND_CACHE;
load_data->flags |= SEQ_LOAD_SOUND_CACHE;
}
if ((prop = RNA_struct_find_property(op->ptr, "mono")) &&
RNA_property_boolean_get(op->ptr, prop)) {
seq_load->flag |= SEQ_LOAD_SOUND_MONO;
}
if ((prop = RNA_struct_find_property(op->ptr, "sound")) &&
RNA_property_boolean_get(op->ptr, prop)) {
seq_load->flag |= SEQ_LOAD_MOVIE_SOUND;
load_data->flags |= SEQ_LOAD_SOUND_MONO;
}
if ((prop = RNA_struct_find_property(op->ptr, "use_framerate")) &&
RNA_property_boolean_get(op->ptr, prop)) {
seq_load->flag |= SEQ_LOAD_SYNC_FPS;
load_data->flags |= SEQ_LOAD_MOVIE_SYNC_FPS;
}
/* Create consecutive array of strips. */
seq_load->flag |= SEQ_LOAD_FRAME_ADVANCE;
if (is_file == 1) {
BLI_strncpy(seq_load->name, BLI_path_basename(seq_load->path), sizeof(seq_load->name));
BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name));
}
else if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *name = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
BLI_strncpy(seq_load->name, name, sizeof(seq_load->name));
BLI_strncpy(load_data->name, name, sizeof(load_data->name));
MEM_freeN(name);
break;
}
@ -299,21 +287,27 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
SequencerAddData *sad = op->customdata;
ImageFormatData *imf = &sad->im_format;
seq_load->views_format = imf->views_format;
seq_load->flag |= SEQ_USE_VIEWS;
seq_load->stereo3d_format = &imf->stereo3d_format;
load_data->use_multiview = true;
load_data->views_format = imf->views_format;
load_data->stereo3d_format = &imf->stereo3d_format;
}
}
}
/**
* Apply generic operator options.
*/
static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *seq)
static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence *seq)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
if (seq == NULL) {
return;
}
if (RNA_boolean_get(op->ptr, "replace_sel")) {
seq->flag |= SELECT;
SEQ_select_active_set(scene, seq);
}
if (RNA_boolean_get(op->ptr, "overlap") == false) {
if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
@ -321,17 +315,6 @@ static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *s
}
}
static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequence *seq)
{
Scene *scene = CTX_data_scene(C);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
SEQ_select_active_set(scene, seq);
seq->flag |= SELECT;
}
}
static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
wmOperator *op,
const PropertyRNA *prop)
@ -356,34 +339,24 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
Scene *sce_seq;
Sequence *seq;
int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
const Editing *ed = SEQ_editing_get(scene, true);
Scene *sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
if (sce_seq == NULL) {
BKE_report(op->reports, RPT_ERROR, "Scene not found");
return OPERATOR_CANCELLED;
}
seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->scene = sce_seq;
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
load_data.scene = sce_seq;
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(scene);
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
Sequence *seq = SEQ_add_scene_strip(scene, ed->seqbasep, &load_data);
seq_load_apply_generic_options(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
@ -430,36 +403,24 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
MovieClip *clip;
Sequence *seq;
int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip"));
const Editing *ed = SEQ_editing_get(scene, true);
MovieClip *clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip"));
if (clip == NULL) {
BKE_report(op->reports, RPT_ERROR, "Movie clip not found");
return OPERATOR_CANCELLED;
}
seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
seq->len = BKE_movieclip_get_duration(clip);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
id_us_ensure_real(&seq->clip->id);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
load_data.clip = clip;
BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2);
SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(scene);
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
Sequence *seq = SEQ_add_movieclip_strip(scene, ed->seqbasep, &load_data);
seq_load_apply_generic_options(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@ -506,36 +467,24 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
Mask *mask;
Sequence *seq;
int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask"));
const Editing *ed = SEQ_editing_get(scene, true);
Mask *mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask"));
if (mask == NULL) {
BKE_report(op->reports, RPT_ERROR, "Mask not found");
return OPERATOR_CANCELLED;
}
seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
seq->len = BKE_mask_get_duration(mask);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
id_us_ensure_real(&seq->mask->id);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
load_data.mask = mask;
BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2);
SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(scene);
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
Sequence *seq = SEQ_add_mask_strip(scene, ed->seqbasep, &load_data);
seq_load_apply_generic_options(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@ -577,75 +526,6 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
SeqLoadInfo seq_load;
int tot_files;
seq_load_operator_info(&seq_load, C, op);
if (seq_load.flag & SEQ_LOAD_REPLACE_SEL) {
ED_sequencer_deselect_all(scene);
}
tot_files = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
RNA_BEGIN (op->ptr, itemptr, "files") {
Sequence *seq;
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only);
/* Set seq_load.name, otherwise all video/audio files get the same name. */
BLI_strncpy(seq_load.name, file_only, sizeof(seq_load.name));
seq = seq_load_fn(C, ed->seqbasep, &seq_load);
if (seq) {
if (seq_load.seq_sound) {
sequencer_add_apply_overlap(C, op, seq_load.seq_sound);
}
sequencer_add_apply_overlap(C, op, seq);
}
}
RNA_END;
}
else { /* Single file./ */
Sequence *seq;
seq = seq_load_fn(C, ed->seqbasep, &seq_load);
if (seq) {
if (seq_load.seq_sound) {
sequencer_add_apply_overlap(C, op, seq_load.seq_sound);
}
sequencer_add_apply_overlap(C, op, seq);
}
}
if (op->customdata) {
MEM_freeN(op->customdata);
}
if (seq_load.tot_success == 0) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", seq_load.path);
return OPERATOR_CANCELLED;
}
SEQ_sort(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
{
op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
@ -668,9 +548,98 @@ static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr),
return !(STR_ELEM(prop_id, "filepath", "directory", "filename"));
}
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene, true);
RNA_BEGIN (op->ptr, itemptr, "files") {
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data);
load_data->channel--;
if (seq_movie == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
}
else {
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
}
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
}
}
RNA_END;
}
static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene, true);
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data);
load_data->channel--;
if (seq_movie == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
return false;
}
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
}
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
return true;
}
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, SEQ_add_movie_strip);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
const int tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
sequencer_add_movie_multiple_strips(C, op, &load_data);
}
else {
if (!sequencer_add_movie_single_strip(C, op, &load_data)) {
return OPERATOR_CANCELLED;
}
}
if (op->customdata) {
MEM_freeN(op->customdata);
}
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
static int sequencer_add_movie_strip_invoke(bContext *C,
@ -681,7 +650,8 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
/* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */
/* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user.
*/
if (ed && ed->seqbasep && ed->seqbasep->first) {
RNA_boolean_set(op->ptr, "use_framerate", false);
}
@ -761,9 +731,80 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
"Use framerate from the movie to keep sound and video in sync");
}
static void sequencer_add_sound_multiple_strips(bContext *C,
wmOperator *op,
SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
RNA_BEGIN (op->ptr, itemptr, "files") {
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
if (seq == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
}
else {
seq_load_apply_generic_options(C, op, seq);
load_data->start_frame += seq->enddisp - seq->startdisp;
}
}
RNA_END;
}
static bool sequencer_add_sound_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
if (seq == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
return false;
}
seq_load_apply_generic_options(C, op, seq);
return true;
}
static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, SEQ_add_sound_strip);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
const int tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
sequencer_add_sound_multiple_strips(C, op, &load_data);
}
else {
if (!sequencer_add_sound_single_strip(C, op, &load_data)) {
return OPERATOR_CANCELLED;
}
}
if (op->customdata) {
MEM_freeN(op->customdata);
}
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
static int sequencer_add_sound_strip_invoke(bContext *C,
@ -873,78 +914,86 @@ void sequencer_image_seq_reserve_frames(
}
}
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
static int sequencer_add_image_strip_calculate_length(wmOperator *op,
const int start_frame,
int *minframe,
int *numdigits)
{
int minframe, numdigits;
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
SeqLoadInfo seq_load;
Sequence *seq;
Strip *strip;
StripElem *se;
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, C, op);
/* Images are unique in how they handle this - 1 per strip elem. */
if (use_placeholders) {
seq_load.len = sequencer_image_seq_get_minmax_frame(
op, seq_load.start_frame, &minframe, &numdigits);
return sequencer_image_seq_get_minmax_frame(op, start_frame, minframe, numdigits);
}
else {
seq_load.len = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
}
}
if (seq_load.len == 0) {
return OPERATOR_CANCELLED;
}
static void sequencer_add_image_strip_load_files(bContext *C,
wmOperator *op,
Sequence *seq,
SeqLoadData *load_data,
const int minframe,
const int numdigits)
{
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
if (seq_load.flag & SEQ_LOAD_REPLACE_SEL) {
ED_sequencer_deselect_all(scene);
}
/* Main adding function. */
seq = SEQ_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
SEQ_add_image_set_directory(seq, load_data->path);
if (use_placeholders) {
sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits);
sequencer_image_seq_reserve_frames(
op, seq->strip->stripdata, load_data->image.len, minframe, numdigits);
}
else {
size_t strip_frame = 0;
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
BLI_strncpy(se->name, filename, sizeof(se->name));
SEQ_add_image_load_file(seq, strip_frame, filename);
MEM_freeN(filename);
se++;
strip_frame++;
}
RNA_END;
}
}
if (seq_load.len == 1) {
if (seq_load.start_frame < seq_load.end_frame) {
seq->endstill = seq_load.end_frame - seq_load.start_frame;
}
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
int minframe, numdigits;
load_data.image.len = sequencer_add_image_strip_calculate_length(
op, load_data.start_frame, &minframe, &numdigits);
if (load_data.image.len == 0) {
return OPERATOR_CANCELLED;
}
SEQ_render_init_colorspace(seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(scene);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
/* Last active name. */
BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir));
sequencer_add_apply_overlap(C, op, seq);
Sequence *seq = SEQ_add_image_strip(CTX_data_main(C), scene, ed->seqbasep, &load_data);
sequencer_add_image_strip_load_files(C, op, seq, &load_data, minframe, numdigits);
SEQ_add_image_init_alpha_mode(seq);
/* Adjust length. */
if (load_data.image.len == 1) {
SEQ_transform_set_right_handle_frame(seq, load_data.image.end_frame);
SEQ_time_update_sequence(scene, seq);
}
seq_load_apply_generic_options(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
if (op->customdata) {
MEM_freeN(op->customdata);
}
SEQ_relations_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
@ -1016,80 +1065,46 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
Sequence *seq;
struct SeqEffectHandle sh;
Sequence *seq1, *seq2, *seq3;
const char *error_msg;
int start_frame, end_frame, channel, type;
start_frame = RNA_int_get(op->ptr, "frame_start");
end_frame = RNA_int_get(op->ptr, "frame_end");
channel = RNA_int_get(op->ptr, "channel");
type = RNA_enum_get(op->ptr, "type");
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
load_data.effect.type = RNA_enum_get(op->ptr, "type");
if (!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) {
Sequence *seq1, *seq2, *seq3;
if (!seq_effect_find_selected(
scene, NULL, load_data.effect.type, &seq1, &seq2, &seq3, &error_msg)) {
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
/* Check its start and end frames are valid. */
if (seq1 == NULL && end_frame <= start_frame) {
end_frame = start_frame + 1;
RNA_int_set(op->ptr, "frame_end", end_frame);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
ED_sequencer_deselect_all(scene);
}
seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, type);
BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2);
SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq);
sh = SEQ_effect_handle_get(seq);
sh.init(seq);
seq->seq1 = seq1;
seq->seq2 = seq2;
seq->seq3 = seq3;
if (!seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
SEQ_transform_set_right_handle_frame(seq, end_frame);
}
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
SEQ_time_update_sequence(scene, seq);
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_TEXT) {
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
else if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq1->blend_mode;
}
load_data.effect.seq1 = seq1;
load_data.effect.seq2 = seq2;
load_data.effect.seq3 = seq3;
/* Set channel. If unset, use lowest free one above strips. */
if (!RNA_struct_property_is_set(op->ptr, "channel")) {
if (seq->seq1) {
int chan = max_iii(seq->seq1 ? seq->seq1->machine : 0,
seq->seq2 ? seq->seq2->machine : 0,
seq->seq3 ? seq->seq3->machine : 0);
if (seq1 != NULL) {
int chan = max_iii(
seq1 ? seq1->machine : 0, seq2 ? seq2->machine : 0, seq3 ? seq3->machine : 0);
if (chan < MAXSEQ) {
seq->machine = chan;
load_data.channel = chan;
}
}
}
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
Sequence *seq = SEQ_add_effect_strip(scene, ed->seqbasep, &load_data);
seq_load_apply_generic_options(C, op, seq);
SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */
SEQ_sort(scene);
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
}
SEQ_relations_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);

View File

@ -53,6 +53,7 @@
# include "SEQ_add.h"
# include "SEQ_edit.h"
# include "SEQ_effects.h"
# include "SEQ_relations.h"
# include "SEQ_render.h"
# include "SEQ_sequencer.h"
@ -80,34 +81,6 @@ static void rna_Sequence_swap_internal(Sequence *seq_self,
}
}
static Sequence *alloc_generic_sequence(
ListBase *seqbase, const char *name, int frame_start, int channel, int type, const char *file)
{
Sequence *seq;
StripElem *se;
seq = SEQ_sequence_alloc(seqbase, frame_start, channel, type);
BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2);
SEQ_sequence_base_unique_name_recursive(seqbase, seq);
Strip *strip = seq->strip;
/* Don't allocate StripElem for clip, mask and scene types. This struct is not handled in
* seq_dupli() function. */
if (file && !ELEM(type, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK, SEQ_TYPE_SCENE)) {
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(file, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
SEQ_render_init_colorspace(seq);
}
else {
strip->stripdata = NULL;
}
return seq;
}
static Sequence *rna_Sequences_new_clip(ID *id,
ListBase *seqbase,
Main *bmain,
@ -117,15 +90,10 @@ static Sequence *rna_Sequences_new_clip(ID *id,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
seq = alloc_generic_sequence(
seqbase, name, frame_start, channel, SEQ_TYPE_MOVIECLIP, clip->filepath);
seq->clip = clip;
seq->len = BKE_movieclip_get_duration(clip);
id_us_plus((ID *)clip);
SEQ_time_update_sequence_bounds(scene, seq);
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel);
load_data.clip = clip;
Sequence *seq = SEQ_add_movieclip_strip(scene, seqbase, &load_data);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -165,15 +133,10 @@ static Sequence *rna_Sequences_new_mask(ID *id,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_MASK, mask->id.name);
seq->mask = mask;
seq->len = BKE_mask_get_duration(mask);
id_us_plus((ID *)mask);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel);
load_data.mask = mask;
Sequence *seq = SEQ_add_mask_strip(scene, seqbase, &load_data);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -202,15 +165,10 @@ static Sequence *rna_Sequences_new_scene(ID *id,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_SCENE, NULL);
seq->scene = sce_seq;
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
id_us_plus((ID *)sce_seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel);
load_data.scene = sce_seq;
Sequence *seq = SEQ_add_scene_strip(scene, seqbase, &load_data);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -251,20 +209,17 @@ static Sequence *rna_Sequences_new_image(ID *id,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_IMAGE, file);
seq->len = 1;
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.image.len = 1;
Sequence *seq = SEQ_add_image_strip(bmain, scene, seqbase, &load_data);
if (seq->strip->stripdata->name[0] == '\0') {
BKE_report(reports, RPT_ERROR, "Sequences.new_image: unable to open image file");
BLI_remlink(seqbase, seq);
SEQ_sequence_free(scene, seq, true);
return NULL;
}
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
char dir[FILE_MAX], filename[FILE_MAX];
BLI_split_dirfile(file, dir, filename, sizeof(dir), sizeof(filename));
SEQ_add_image_set_directory(seq, dir);
SEQ_add_image_load_file(seq, 0, filename);
SEQ_add_image_init_alpha_mode(seq);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -299,48 +254,47 @@ static Sequence *rna_Sequences_meta_new_image(ID *id,
id, &seq->seqbase, bmain, reports, name, file, channel, frame_start);
}
static Sequence *rna_Sequences_new_movie(
ID *id, ListBase *seqbase, const char *name, const char *file, int channel, int frame_start)
static Sequence *rna_Sequences_new_movie(ID *id,
ListBase *seqbase,
Main *bmain,
const char *name,
const char *file,
int channel,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
StripAnim *sanim;
seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
struct anim *an = openanim(file, IB_rect, 0, NULL);
if (an == NULL) {
/* Without anim, the strip gets duration 0, which makes it impossible to select in the UI. */
seq->len = 1;
}
else {
sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
BLI_addtail(&seq->anims, sanim);
sanim->anim = an;
seq->anim_preseek = IMB_anim_get_preseek(an);
seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
}
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.allow_invalid_file = true;
Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
return seq;
}
static Sequence *rna_Sequences_editing_new_movie(
ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start)
static Sequence *rna_Sequences_editing_new_movie(ID *id,
Editing *ed,
Main *bmain,
const char *name,
const char *file,
int channel,
int frame_start)
{
return rna_Sequences_new_movie(id, &ed->seqbase, name, file, channel, frame_start);
return rna_Sequences_new_movie(id, &ed->seqbase, bmain, name, file, channel, frame_start);
}
static Sequence *rna_Sequences_meta_new_movie(
ID *id, Sequence *seq, const char *name, const char *file, int channel, int frame_start)
static Sequence *rna_Sequences_meta_new_movie(ID *id,
Sequence *seq,
Main *bmain,
const char *name,
const char *file,
int channel,
int frame_start)
{
return rna_Sequences_new_movie(id, &seq->seqbase, name, file, channel, frame_start);
return rna_Sequences_new_movie(id, &seq->seqbase, bmain, name, file, channel, frame_start);
}
# ifdef WITH_AUDASPACE
@ -354,22 +308,15 @@ static Sequence *rna_Sequences_new_sound(ID *id,
int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.allow_invalid_file = true;
Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data);
bSound *sound = BKE_sound_new_file(bmain, file);
SoundInfo info;
if (!BKE_sound_info_get(bmain, sound, &info)) {
BKE_id_free(bmain, sound);
if (seq == NULL) {
BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file");
return NULL;
}
seq = alloc_generic_sequence(
seqbase, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->filepath);
seq->sound = sound;
seq->len = ceil((double)info.length * FPS);
SEQ_time_update_sequence_bounds(scene, seq);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -432,8 +379,7 @@ static Sequence *rna_Sequences_new_effect(ID *id,
{
Scene *scene = (Scene *)id;
Sequence *seq;
struct SeqEffectHandle sh;
int num_inputs = SEQ_effect_get_num_inputs(type);
const int num_inputs = SEQ_effect_get_num_inputs(type);
switch (num_inputs) {
case 0:
@ -469,26 +415,14 @@ static Sequence *rna_Sequences_new_effect(ID *id,
return NULL;
}
seq = alloc_generic_sequence(seqbase, name, frame_start, channel, type, NULL);
sh = SEQ_effect_handle_get(seq);
seq->seq1 = seq1;
seq->seq2 = seq2;
seq->seq3 = seq3;
sh.init(seq);
if (!seq1) { /* effect has no deps */
seq->len = 1;
SEQ_transform_set_right_handle_frame(seq, frame_end);
}
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
SEQ_time_update_sequence(scene, seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel);
load_data.effect.end_frame = frame_end;
load_data.effect.type = type;
load_data.effect.seq1 = seq1;
load_data.effect.seq2 = seq2;
load_data.effect.seq3 = seq3;
seq = SEQ_add_effect_strip(scene, seqbase, &load_data);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
@ -865,7 +799,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastri
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_movie", new_movie_func_name);
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Add a new movie sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);

View File

@ -32,48 +32,73 @@ struct Scene;
struct Sequence;
struct bContext;
/* api for adding new sequence strips */
typedef struct SeqLoadInfo {
int start_frame;
int end_frame;
int channel;
int flag; /* use sound, replace sel */
int type;
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
eSeqImageFitMethod fit_method;
/* SeqLoadData.flags */
typedef enum eSeqLoadFlags {
SEQ_LOAD_SOUND_CACHE = (1 << 1),
SEQ_LOAD_SOUND_MONO = (1 << 2),
SEQ_LOAD_MOVIE_SYNC_FPS = (1 << 3),
} eSeqLoadFlags;
/* multiview */
/* Api for adding new sequence strips. */
typedef struct SeqLoadData {
int start_frame;
int channel;
char name[64]; /* Strip name. */
char path[1024]; /* 1024 = FILE_MAX */
struct {
int len;
int end_frame;
} image; /* Only for image strips. */
struct Scene *scene; /* Only for scene strips. */
struct MovieClip *clip; /* Only for clip strips. */
struct Mask *mask; /* Only for mask strips. */
struct {
int type;
int end_frame;
struct Sequence *seq1;
struct Sequence *seq2;
struct Sequence *seq3;
} effect; /* Only for effect strips. */
eSeqLoadFlags flags;
eSeqImageFitMethod fit_method;
bool use_multiview;
char views_format;
struct Stereo3dFormat *stereo3d_format;
bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */
} SeqLoadData;
/* return values */
char name[64];
struct Sequence *seq_sound; /* for movie's */
int tot_success;
int tot_error;
} SeqLoadInfo;
/* SeqLoadInfo.flag */
#define SEQ_LOAD_REPLACE_SEL (1 << 0)
#define SEQ_LOAD_FRAME_ADVANCE (1 << 1)
#define SEQ_LOAD_MOVIE_SOUND (1 << 2)
#define SEQ_LOAD_SOUND_CACHE (1 << 3)
#define SEQ_LOAD_SYNC_FPS (1 << 4)
#define SEQ_LOAD_SOUND_MONO (1 << 5)
/* use as an api function */
typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *);
struct Sequence *SEQ_add_image_strip(struct bContext *C,
ListBase *seqbasep,
struct SeqLoadInfo *seq_load);
struct Sequence *SEQ_add_sound_strip(struct bContext *C,
ListBase *seqbasep,
struct SeqLoadInfo *seq_load);
struct Sequence *SEQ_add_movie_strip(struct bContext *C,
ListBase *seqbasep,
struct SeqLoadInfo *seq_load);
void SEQ_add_load_data_init(struct SeqLoadData *load_data,
const char *name,
const char *path,
const int start_frame,
const int channel);
struct Sequence *SEQ_add_image_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_movieclip_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_mask_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_effect_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
void SEQ_add_image_set_directory(struct Sequence *seq, char *path);
void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename);
void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,

View File

@ -203,34 +203,6 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4
}
}
void SEQ_render_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);
}
}
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
@ -54,7 +55,9 @@
#include "IMB_metadata.h"
#include "SEQ_add.h"
#include "SEQ_effects.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@ -65,168 +68,369 @@
#include "proxy.h"
#include "utils.h"
static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
/**
* Initialize common SeqLoadData members
*
* \param load_data: SeqLoadData to be initialized
* \param name: strip name (can be NULL)
* \param path: path to file that is used as strip input (can be NULL)
* \param start_frame: timeline frame where strip will be created
* \param channel: timeline channel where strip will be created
*
*/
void SEQ_add_load_data_init(SeqLoadData *load_data,
const char *name,
const char *path,
const int start_frame,
const int channel)
{
if (seq) {
BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
memset(load_data, 0, sizeof(SeqLoadData));
if (name != NULL) {
BLI_strncpy(load_data->name, name, sizeof(load_data->name));
}
if (path != NULL) {
BLI_strncpy(load_data->path, path, sizeof(load_data->path));
}
load_data->start_frame = start_frame;
load_data->channel = channel;
}
if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) {
seq_load->start_frame += (seq->enddisp - seq->startdisp);
}
static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq)
{
SEQ_sequence_base_unique_name_recursive(seqbase, seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(scene);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) {
seq_load->flag |= SELECT;
SEQ_select_active_set(scene, seq);
}
if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
seq->sound->flags |= SOUND_FLAGS_MONO;
BKE_sound_load(bmain, seq->sound);
}
if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
if (seq->sound) {
seq->sound->flags |= SOUND_FLAGS_CACHING;
}
}
seq_load->tot_success++;
static void seq_add_set_name(Sequence *seq, SeqLoadData *load_data)
{
if (load_data->name != NULL) {
BLI_strncpy(seq->name + 2, load_data->name, sizeof(seq->name) - 2);
}
else {
seq_load->tot_error++;
if (seq->type == SEQ_TYPE_SCENE) {
BLI_strncpy(seq->name + 2, load_data->scene->id.name + 2, sizeof(seq->name) - 2);
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
BLI_strncpy(seq->name + 2, load_data->clip->id.name + 2, sizeof(seq->name) - 2);
}
else if (seq->type == SEQ_TYPE_MASK) {
BLI_strncpy(seq->name + 2, load_data->mask->id.name + 2, sizeof(seq->name) - 2);
}
else if ((seq->type & SEQ_TYPE_EFFECT) != 0) {
BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2);
}
else { /* Image, sound and movie. */
BLI_strncpy_utf8(seq->name + 2, load_data->name, sizeof(seq->name) - 2);
BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
}
}
}
/* NOTE: this function doesn't fill in image names */
Sequence *SEQ_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
/**
* Add scene strip.
*
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Scene *scene = CTX_data_scene(C); /* only for active seq */
Sequence *seq;
Strip *strip;
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
/**
* Add movieclip strip.
*
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
/* basic defaults */
seq->len = seq_load->len ? seq_load->len : 1;
/**
* Add mask strip.
*
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
strip = seq->strip;
strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
/**
* Add effect strip.
*
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, load_data->effect.type);
if (seq_load->stereo3d_format) {
*seq->stereo3d_format = *seq_load->stereo3d_format;
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
struct SeqEffectHandle sh = SEQ_effect_handle_get(seq);
sh.init(seq);
seq->seq1 = load_data->effect.seq1;
seq->seq2 = load_data->effect.seq2;
seq->seq3 = load_data->effect.seq3;
if (seq->type == SEQ_TYPE_COLOR) {
seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_TEXT) {
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
else if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq->seq1->blend_mode;
}
seq->views_format = seq_load->views_format;
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
SEQ_transform_set_right_handle_frame(seq, load_data->image.end_frame);
}
SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
return seq;
}
/**
* Set directory used by image strip.
*
* \param seq: image strip to be changed
* \param path: directory path
*/
void SEQ_add_image_set_directory(Sequence *seq, char *path)
{
BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
}
/**
* Set directory used by image strip.
*
* \param seq: image strip to be changed
* \param strip_frame: frame index of strip to be changed
* \param filename: image filename (only filename, not complete path)
*/
void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename)
{
StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame);
BLI_strncpy(se->name, filename, sizeof(se->name));
}
/**
* Set image strip alpha mode
*
* \param seq: image strip to be changed
*/
void SEQ_add_image_init_alpha_mode(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);
}
}
}
}
/**
* Add image strip.
* NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
*
* \param main: Main reference
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE);
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->len = load_data->image.len;
Strip *strip = seq->strip;
strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem");
/* Multiview settings. */
if (load_data->use_multiview) {
seq->flag |= SEQ_USE_VIEWS;
seq->views_format = load_data->views_format;
}
if (load_data->stereo3d_format) {
seq->stereo3d_format = load_data->stereo3d_format;
}
/* Set initial scale based on load_data->fit_method. */
char file_path[FILE_MAX];
BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name);
BLI_path_abs(file_path, BKE_main_blendfile_path(CTX_data_main(C)));
BLI_join_dirfile(file_path, sizeof(file_path), load_data->path, load_data->name);
BLI_path_abs(file_path, BKE_main_blendfile_path(bmain));
ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name);
if (ibuf != NULL) {
SEQ_set_scale_to_fit(
seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method);
seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, load_data->fit_method);
IMB_freeImBuf(ibuf);
}
SEQ_relations_invalidate_cache_composite(scene, seq);
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir));
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
#ifdef WITH_AUDASPACE
Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
/**
* Add sound strip.
* NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
*
* \param main: Main reference
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C); /* only for sound */
Editing *ed = SEQ_editing_get(scene, false);
bSound *sound;
Sequence *seq; /* generic strip vars */
Strip *strip;
StripElem *se;
sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
bSound *sound = BKE_sound_new_file(bmain, load_data->path); /* Handles relative paths. */
SoundInfo info;
if (!BKE_sound_info_get(bmain, sound, &info)) {
bool sound_loaded = BKE_sound_info_get(bmain, sound, &info);
if (!sound_loaded && !load_data->allow_invalid_file) {
BKE_id_free(bmain, sound);
return NULL;
}
if (info.specs.channels == SOUND_CHANNELS_INVALID) {
if (info.specs.channels == SOUND_CHANNELS_INVALID && !load_data->allow_invalid_file) {
BKE_id_free(bmain, sound);
return NULL;
}
seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM);
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SOUND_RAM);
seq->sound = sound;
BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2);
SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
/* basic defaults */
/* We add a very small negative offset here, because
* ceil(132.0) == 133.0, not nice with videos, see T47135. */
seq->len = (int)ceil((double)info.length * FPS - 1e-4);
strip = seq->strip;
/* we only need 1 element to store the filename */
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
seq->scene_sound = NULL;
SEQ_time_update_sequence_bounds(scene, seq);
/* We add a very small negative offset here, because
* ceil(132.0) == 133.0, not nice with videos, see T47135. */
seq->len = MAX2(1, (int)ceil((double)info.length * FPS - 1e-4));
/* last active name */
BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
Strip *strip = seq->strip;
/* We only need 1 element to store the filename. */
StripElem *se = strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
seq_load_apply(bmain, scene, seq, seq_load);
if (seq != NULL && seq->sound != NULL) {
if (load_data->flags & SEQ_LOAD_SOUND_MONO) {
seq->sound->flags |= SOUND_FLAGS_MONO;
}
/* TODO(sergey): Shall we tag here or in the operator? */
DEG_relations_tag_update(bmain);
if (load_data->flags & SEQ_LOAD_SOUND_CACHE) {
if (seq->sound) {
seq->sound->flags |= SOUND_FLAGS_CACHING;
}
}
}
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR);
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
#else // WITH_AUDASPACE
Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
(void)C;
(void)seqbasep;
(void)seq_load;
return NULL;
}
Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain),
Scene *UNUSED(scene),
ListBase *UNUSED(seqbase),
const SeqLoadData *UNUSED(load_data))
#endif // WITH_AUDASPACE
Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
/**
* Add movie strip.
*
* \param main: Main reference
* \param scene: Scene where strips will be added
* \param seqbase: ListBase where strips will be added
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C); /* only for sound */
char path[sizeof(seq_load->path)];
Sequence *seq; /* generic strip vars */
Strip *strip;
StripElem *se;
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
bool is_multiview_loaded = false;
const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
struct anim **anim_arr;
int i;
BLI_strncpy(path, seq_load->path, sizeof(path));
char path[sizeof(load_data->path)];
BLI_strncpy(path, load_data->path, sizeof(path));
BLI_path_abs(path, BKE_main_blendfile_path(bmain));
anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
bool is_multiview_loaded = false;
const int totfiles = seq_num_files(scene, load_data->views_format, load_data->use_multiview);
struct anim **anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
int i;
if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
if (load_data->use_multiview && (load_data->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
char prefix[FILE_MAX];
const char *ext = NULL;
size_t j = 0;
@ -245,38 +449,30 @@ Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_
j++;
}
}
if (j == 0) {
MEM_freeN(anim_arr);
return NULL;
}
is_multiview_loaded = true;
}
}
if (is_multiview_loaded == false) {
anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
if (anim_arr[0] == NULL) {
MEM_freeN(anim_arr);
return NULL;
}
}
if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
seq_load->channel++;
if (anim_arr[0] == NULL && !load_data->allow_invalid_file) {
MEM_freeN(anim_arr);
return NULL;
}
seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE);
/* multiview settings */
if (seq_load->stereo3d_format) {
*seq->stereo3d_format = *seq_load->stereo3d_format;
seq->views_format = seq_load->views_format;
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIE);
/* Multiview settings. */
if (load_data->use_multiview) {
seq->flag |= SEQ_USE_VIEWS;
seq->views_format = load_data->views_format;
}
if (load_data->stereo3d_format) {
seq->stereo3d_format = load_data->stereo3d_format;
}
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
seq->type = SEQ_TYPE_MOVIE;
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
for (i = 0; i < totfiles; i++) {
if (anim_arr[i]) {
@ -289,51 +485,38 @@ Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_
}
}
IMB_anim_load_metadata(anim_arr[0]);
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
if (anim_arr[0] != NULL) {
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
const float width = IMB_anim_get_image_width(anim_arr[0]);
const float height = IMB_anim_get_image_height(anim_arr[0]);
SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, seq_load->fit_method);
IMB_anim_load_metadata(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
/* Adjust scene's frame rate settings to match. */
if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
}
/* adjust scene's frame rate settings to match */
if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
/* Set initial scale based on load_data->fit_method. */
const float width = IMB_anim_get_image_width(anim_arr[0]);
const float height = IMB_anim_get_image_height(anim_arr[0]);
SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, load_data->fit_method);
}
/* basic defaults */
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
strip = seq->strip;
seq->len = MAX2(1, seq->len);
BLI_strncpy(seq->strip->colorspace_settings.name,
colorspace,
sizeof(seq->strip->colorspace_settings.name));
/* we only need 1 element for MOVIE strips */
Strip *strip = seq->strip;
/* We only need 1 element for MOVIE strips. */
StripElem *se;
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
SEQ_time_update_sequence_bounds(scene, seq);
if (seq_load->name[0] == '\0') {
BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name));
}
if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
int start_frame_back = seq_load->start_frame;
seq_load->channel--;
seq_load->seq_sound = SEQ_add_sound_strip(C, seqbasep, seq_load);
seq_load->start_frame = start_frame_back;
}
/* can be NULL */
seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
SEQ_relations_invalidate_cache_composite(scene, seq);
seq_add_set_name(seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
MEM_freeN(anim_arr);
return seq;
@ -525,9 +708,9 @@ void SEQ_add_movie_reload_if_needed(struct Main *bmain,
bool must_reload = false;
/* The Sequence struct allows for multiple anim structs to be associated with one strip. This
* function will return true only if there is at least one 'anim' AND all anims can produce
* frames. */
/* The Sequence struct allows for multiple anim structs to be associated with one strip.
* This function will return true only if there is at least one 'anim' AND all anims can
* produce frames. */
if (BLI_listbase_is_empty(&seq->anims)) {
/* No anim present, so reloading is always necessary. */