VSE: Python API, allow creation of VSE Movie strips with missing file
It was already possible to create Sound and Image strips that reference non-existing files. Now it's also possible to create Movie strips referencing missing files via the Python API call `Sequences.new_movie()`. In this case, the duration of the strip will be set to 1 frame. Note that this commit does not change anything in the user interface. The Python API of the `MovieStrip` class is extended with a function `reload_if_needed()`. This function only performs disk I/O if the movie strip cannot produce frames, that is either when its filepath points to a non-existing file, or when the video sequence editor has not been shown yet (for example because it is in an inactive workspace). This allows for the following: ``` import bpy scene = bpy.context.scene vse = scene.sequence_editor_create() filepath = bpy.path.abspath('//demo.mkv') strip = vse.sequences.new_movie("movie", filepath, channel=2, frame_start=47, file_must_exist=False) strip.frame_final_end = 327 ``` This will create a new movie strip, even when `demo.mkv` does not exist. Once `demo.mkv` has appeared at the expected location, either `strip.reload_if_needed()` or `strip.filepath = strip.filepath` will load it. Differential Revision: https://developer.blender.org/D8257 Reviewed By: Sergey, ISS
This commit is contained in:
parent
9db0c36af1
commit
b9f565881e
Notes:
blender-bot
2023-02-14 08:38:14 +01:00
Referenced by issue #78768, Allow creation of VSE strips referencing a non-existent file
|
@ -285,6 +285,11 @@ void BKE_sequence_reload_new_file(struct Main *bmain,
|
|||
struct Scene *scene,
|
||||
struct Sequence *seq,
|
||||
const bool lock_range);
|
||||
void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct Sequence *seq,
|
||||
bool *r_was_reloaded,
|
||||
bool *r_can_produce_frames);
|
||||
int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
|
||||
int BKE_sequencer_get_shown_sequences(struct ListBase *seqbasep,
|
||||
int cfra,
|
||||
|
|
|
@ -1090,6 +1090,64 @@ void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, cons
|
|||
BKE_sequence_calc(scene, seq);
|
||||
}
|
||||
|
||||
void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct Sequence *seq,
|
||||
bool *r_was_reloaded,
|
||||
bool *r_can_produce_frames)
|
||||
{
|
||||
BLI_assert(seq->type == SEQ_TYPE_MOVIE ||
|
||||
!"This function is only implemented for movie strips.");
|
||||
|
||||
bool must_reload = false;
|
||||
|
||||
/* The Sequence struct allows for multiple anim structs to be associated with one strip. This
|
||||
* function will return true only if there is at least one 'anim' AND all anims can produce
|
||||
* frames. */
|
||||
|
||||
if (BLI_listbase_is_empty(&seq->anims)) {
|
||||
/* No anim present, so reloading is always necessary. */
|
||||
must_reload = true;
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
|
||||
if (!IMB_anim_can_produce_frames(sanim->anim)) {
|
||||
/* Anim cannot produce frames, try reloading. */
|
||||
must_reload = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!must_reload) {
|
||||
/* There are one or more anims, and all can produce frames. */
|
||||
*r_was_reloaded = false;
|
||||
*r_can_produce_frames = true;
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_sequence_reload_new_file(bmain, scene, seq, true);
|
||||
*r_was_reloaded = true;
|
||||
|
||||
if (BLI_listbase_is_empty(&seq->anims)) {
|
||||
/* No anims present after reloading => no frames can be produced. */
|
||||
*r_can_produce_frames = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if there are still anims that cannot produce frames. */
|
||||
LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
|
||||
if (!IMB_anim_can_produce_frames(sanim->anim)) {
|
||||
/* There still is an anim that cannot produce frames. */
|
||||
*r_can_produce_frames = false;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/* There are one or more anims, and all can produce frames. */
|
||||
*r_can_produce_frames = true;
|
||||
}
|
||||
|
||||
void BKE_sequencer_sort(Scene *scene)
|
||||
{
|
||||
/* all strips together per kind, and in order of y location ("machine") */
|
||||
|
|
|
@ -367,6 +367,7 @@ struct anim *IMB_open_anim(const char *name,
|
|||
void IMB_suffix_anim(struct anim *anim, const char *suffix);
|
||||
void IMB_close_anim(struct anim *anim);
|
||||
void IMB_close_anim_proxies(struct anim *anim);
|
||||
bool IMB_anim_can_produce_frames(const struct anim *anim);
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -304,6 +304,21 @@ struct anim *IMB_open_anim(const char *name,
|
|||
return (anim);
|
||||
}
|
||||
|
||||
bool IMB_anim_can_produce_frames(const struct anim *anim)
|
||||
{
|
||||
#ifdef WITH_AVI
|
||||
if (anim->avi != NULL) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_FFMPEG
|
||||
if (anim->pCodecCtx != NULL) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void IMB_suffix_anim(struct anim *anim, const char *suffix)
|
||||
{
|
||||
BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
|
||||
|
|
|
@ -749,6 +749,25 @@ static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
|
|||
return seq->prop;
|
||||
}
|
||||
|
||||
static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain)
|
||||
{
|
||||
Scene *scene = (Scene *)scene_id;
|
||||
bool has_reloaded;
|
||||
bool can_produce_frames;
|
||||
|
||||
BKE_sequence_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames);
|
||||
|
||||
if (has_reloaded && can_produce_frames) {
|
||||
BKE_sequence_calc(scene, seq);
|
||||
BKE_sequence_invalidate_cache_raw(scene, seq);
|
||||
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
|
||||
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
|
||||
}
|
||||
|
||||
return can_produce_frames;
|
||||
}
|
||||
|
||||
static PointerRNA rna_MovieSequence_metadata_get(Sequence *seq)
|
||||
{
|
||||
if (seq == NULL || seq->anims.first == NULL) {
|
||||
|
@ -2385,6 +2404,13 @@ static void rna_def_movie(BlenderRNA *brna)
|
|||
"rna_Sequence_filepath_set");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
|
||||
|
||||
func = RNA_def_function(srna, "reload_if_needed", "rna_MovieSequence_reload_if_needed");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
/* return type */
|
||||
parm = RNA_def_boolean(
|
||||
func, "can_produce_frames", 0, "True if the strip can produce frames, False otherwise", "");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
/* metadata */
|
||||
func = RNA_def_function(srna, "metadata", "rna_MovieSequence_metadata_get");
|
||||
RNA_def_function_ui_description(func, "Retrieve metadata of the movie file");
|
||||
|
|
|
@ -205,33 +205,28 @@ static Sequence *rna_Sequences_new_image(ID *id,
|
|||
return seq;
|
||||
}
|
||||
|
||||
static Sequence *rna_Sequences_new_movie(ID *id,
|
||||
Editing *ed,
|
||||
ReportList *reports,
|
||||
const char *name,
|
||||
const char *file,
|
||||
int channel,
|
||||
int frame_start)
|
||||
static Sequence *rna_Sequences_new_movie(
|
||||
ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start)
|
||||
{
|
||||
Scene *scene = (Scene *)id;
|
||||
Sequence *seq;
|
||||
StripAnim *sanim;
|
||||
|
||||
struct anim *an = openanim(file, IB_rect, 0, NULL);
|
||||
|
||||
if (an == NULL) {
|
||||
BKE_report(reports, RPT_ERROR, "Sequences.new_movie: unable to open movie file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
|
||||
|
||||
sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
|
||||
BLI_addtail(&seq->anims, sanim);
|
||||
sanim->anim = an;
|
||||
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->anim_preseek = IMB_anim_get_preseek(an);
|
||||
seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
|
||||
}
|
||||
|
||||
BKE_sequence_calc_disp(scene, seq);
|
||||
BKE_sequence_invalidate_cache_composite(scene, seq);
|
||||
|
@ -667,7 +662,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
|
|||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "new_movie", "rna_Sequences_new_movie");
|
||||
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue