diff options
author | Sybren A. Stüvel <sybren@blender.org> | 2020-07-13 16:02:25 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2020-07-13 16:09:18 +0300 |
commit | b9f565881e15f13f5f30b6aca9fc656b3f92b900 (patch) | |
tree | a070bb7b6df13030a81c80a0cbf0d19784156723 /source/blender | |
parent | 9db0c36af1140082b8e4bcf42564482eb477a682 (diff) |
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
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_sequencer.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/sequencer.c | 58 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 1 | ||||
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 15 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_sequencer.c | 26 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_sequencer_api.c | 33 |
6 files changed, 119 insertions, 19 deletions
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index a50f9b24c61..107a27b00ab 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -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, diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index bde94f366b9..7339c887151 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -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") */ diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 8fb6c1ba1e1..fc7e03c3073 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -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); /** * diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 11b30a24cde..220801137f5 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -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)); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 7342879e9e6..de225e3c685 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -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"); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 0fb582c41fd..4157747455d 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -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); + seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file); + 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; + /* 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 = 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; - - 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); |