[Bf-blender-cvs] [b9f565881e1] master: VSE: Python API, allow creation of VSE Movie strips with missing file

Sybren A. Stüvel noreply at git.blender.org
Mon Jul 13 15:09:24 CEST 2020


Commit: b9f565881e15f13f5f30b6aca9fc656b3f92b900
Author: Sybren A. Stüvel
Date:   Mon Jul 13 15:02:25 2020 +0200
Branches: master
https://developer.blender.org/rBb9f565881e15f13f5f30b6aca9fc656b3f92b900

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

===================================================================

M	source/blender/blenkernel/BKE_sequencer.h
M	source/blender/blenkernel/intern/sequencer.c
M	source/blender/imbuf/IMB_imbuf.h
M	source/blender/imbuf/intern/anim_movie.c
M	source/blender/makesrna/intern/rna_sequencer.c
M	source/blender/makesrna/intern/rna_sequencer_api.c

===================================================================

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);



More information about the Bf-blender-cvs mailing list