[Bf-blender-cvs] [2522e0d05da] temp-vse-fast-scrubbing: VSE/FFmpeg: Scrubbing performance optimization

Richard Antalik noreply at git.blender.org
Fri Feb 26 02:55:53 CET 2021


Commit: 2522e0d05da8466f5f1f80c6ffa69d598fdba1bc
Author: Richard Antalik
Date:   Fri Feb 26 02:20:51 2021 +0100
Branches: temp-vse-fast-scrubbing
https://developer.blender.org/rB2522e0d05da8466f5f1f80c6ffa69d598fdba1bc

VSE/FFmpeg: Scrubbing performance optimization

Decode only I-frames when scrubbing

This means, that scrubbing is as fast as possible, but not precise.

With some files with extreme GOP lengths, this may be not optimal, as
seeking would jump from one place to another.
Another issue is, that when zoomed in to movie strip, fine scrubbing is
not possible.

Both issues can be resolved by decoding exact frame on second request.
In first case this would cause UI to be laggy. In both cases this may
also cause glitchy behavior.

To eliminate glitchy behavior, there would have to be a buffer where
previous frames are stored and determine if seek has to be precise or
not. This analysis would have to be heuristic ultimately, and it could
significantly increase code complexity.

Also this analysis would be best done from VSE, because with imprecise
seeking, cache needs to be disabled, because image does not correspond
to what should be displayed.
If analysis is done on VSE side, when switching to precise scrubbing,
cache can remain active and scrubbing backwards, which is very likely
can be aided by cache. FFmpeg can't seek backwards efficiently.

Ultimately this patch assumes that files are encoded with fairly short
GOP sizes. If file is not optimal, proxy system is best solution for
achieving best performance.

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

M	source/blender/editors/space_sequencer/sequencer_buttons.c
M	source/blender/editors/space_sequencer/sequencer_draw.c
M	source/blender/editors/space_sequencer/sequencer_intern.h
M	source/blender/editors/util/ed_util_imbuf.c
M	source/blender/imbuf/IMB_imbuf.h
M	source/blender/imbuf/intern/anim_movie.c
M	source/blender/imbuf/intern/indexer.c
M	source/blender/sequencer/SEQ_render.h
M	source/blender/sequencer/intern/render.c

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

diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 11614d94862..81973bac7ed 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -86,7 +86,7 @@ static void metadata_panel_context_draw(const bContext *C, Panel *panel)
   /* NOTE: We disable multiview for drawing, since we don't know what is the
    * from the panel (is kind of all the views?). */
   ImBuf *ibuf = sequencer_ibuf_get(
-      bmain, region, depsgraph, scene, space_sequencer, scene->r.cfra, 0, "");
+      C, bmain, region, depsgraph, scene, space_sequencer, scene->r.cfra, 0, "");
   if (ibuf != NULL) {
     ED_region_image_metadata_panel_draw(ibuf, panel->layout);
     IMB_freeImBuf(ibuf);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b9fb577eb43..a660379b5a3 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1279,7 +1279,8 @@ void ED_sequencer_special_preview_clear(void)
  * TODO: do not rely on such hack and just update the \a ibuf outside of
  * the UI drawing code.
  */
-ImBuf *sequencer_ibuf_get(struct Main *bmain,
+ImBuf *sequencer_ibuf_get(const bContext *C,
+                          struct Main *bmain,
                           ARegion *region,
                           struct Depsgraph *depsgraph,
                           Scene *scene,
@@ -1312,6 +1313,15 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
       bmain, depsgraph, scene, rectx, recty, sseq->render_size, false, &context);
   context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
 
+  bScreen *screen = CTX_wm_screen(C);
+  if (screen->scrubbing) {
+    context.is_scrubbing = true;
+    context.skip_cache = true;
+  }
+  else {
+    context.is_scrubbing = false;
+  }
+
   /* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
    * by Escape pressed somewhere in the past. */
   G.is_break = false;
@@ -1841,8 +1851,15 @@ void sequencer_draw_preview(const bContext *C,
   }
 
   /* Get image. */
-  ibuf = sequencer_ibuf_get(
-      bmain, region, depsgraph, scene, sseq, timeline_frame, offset, names[sseq->multiview_eye]);
+  ibuf = sequencer_ibuf_get(C,
+                            bmain,
+                            region,
+                            depsgraph,
+                            scene,
+                            sseq,
+                            timeline_frame,
+                            offset,
+                            names[sseq->multiview_eye]);
 
   /* Setup off-screen buffers. */
   GPUViewport *viewport = WM_draw_region_get_viewport(region);
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 4c942a83f2b..2bd7a14582c 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -59,7 +59,8 @@ float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx)
 /* UNUSED */
 /* void seq_reset_imageofs(struct SpaceSeq *sseq); */
 
-struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
+struct ImBuf *sequencer_ibuf_get(const struct bContext *C,
+                                 struct Main *bmain,
                                  struct ARegion *region,
                                  struct Depsgraph *depsgraph,
                                  struct Scene *scene,
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index 0f2e280251f..52c6ff7e37b 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -307,7 +307,7 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
   Scene *scene = CTX_data_scene(C);
   SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
   ARegion *region = CTX_wm_region(C);
-  ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, CFRA, 0, NULL);
+  ImBuf *ibuf = sequencer_ibuf_get(C, bmain, region, depsgraph, scene, sseq, CFRA, 0, NULL);
   ImageSampleInfo *info = op->customdata;
   float fx, fy;
 
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index d131e4dacdc..2c1b3a914e2 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -395,6 +395,15 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
                                 IMB_Timecode_Type tc /* = 1 = IMB_TC_RECORD_RUN */,
                                 IMB_Proxy_Size preview_size /* = 0 = IMB_PROXY_NONE */);
 
+/**
+ *
+ * \attention Defined in anim_movie.c
+ */
+
+struct ImBuf *IMB_anim_absolute_fast_imprecise(struct anim *anim,
+                                               int position,
+                                               IMB_Timecode_Type tc,
+                                               IMB_Proxy_Size preview_size);
 /**
  *
  * \attention Defined in anim_movie.c
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 28bf26aa343..12d8ab6ff5a 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -969,6 +969,55 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
   return (rval >= 0);
 }
 
+/* Decode first I-frame only and quit. */
+static bool ffmpeg_decode_video_frame_scan_fast(struct anim *anim, int64_t pts_to_search)
+{
+  int rval = 0;
+
+  av_log(anim->pFormatCtx, AV_LOG_DEBUG, "  SCAN FAST\n");
+
+  if (anim->next_packet.stream_index == anim->videoStream) {
+    av_free_packet(&anim->next_packet);
+    anim->next_packet.stream_index = -1;
+  }
+
+  while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
+    if (anim->next_packet.stream_index != anim->videoStream) {
+      continue;
+    }
+    if ((anim->next_packet.flags & AV_PKT_FLAG_KEY) == 0) {
+      continue;
+    }
+    printf("fast decode\n");
+    anim->pFrameComplete = 0;
+    avcodec_decode_video2(
+        anim->pCodecCtx, anim->pFrame, &anim->pFrameComplete, &anim->next_packet);
+
+    if (anim->pFrameComplete) {
+      anim->next_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+      break;
+    }
+    av_free_packet(&anim->next_packet);
+    anim->next_packet.stream_index = -1;
+  }
+
+  if (rval == AVERROR_EOF) {
+    /* Must not happen... */
+  }
+
+  if (rval < 0) {
+    anim->next_packet.stream_index = -1;
+
+    av_log(anim->pFormatCtx,
+           AV_LOG_ERROR,
+           "  DECODE READ FAILED: av_read_frame() "
+           "returned error: %d\n",
+           rval);
+  }
+
+  return (rval >= 0);
+}
+
 static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search)
 {
   /* there seem to exist *very* silly GOP lengths out in the wild... */
@@ -1049,37 +1098,18 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
   return false;
 }
 
-static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc)
+static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
+                                        struct anim_index *tc_index,
+                                        int position)
 {
-  int64_t pts_to_search = 0;
-  double frame_rate;
-  double pts_time_base;
-  int64_t st_time;
-  struct anim_index *tc_index = 0;
-  AVStream *v_st;
-  int new_frame_index = 0; /* To quiet gcc barking... */
-  int old_frame_index = 0; /* To quiet gcc barking... */
-
-  if (anim == NULL) {
-    return 0;
-  }
-
-  av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);
-
-  if (tc != IMB_TC_NONE) {
-    tc_index = IMB_anim_open_index(anim, tc);
-  }
-
-  v_st = anim->pFormatCtx->streams[anim->videoStream];
-
-  frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
-
-  st_time = anim->pFormatCtx->start_time;
-  pts_time_base = av_q2d(v_st->time_base);
+  int64_t pts_to_search;
+  int64_t st_time = anim->pFormatCtx->start_time;
+  AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
+  double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
+  double pts_time_base = av_q2d(v_st->time_base);
 
   if (tc_index) {
-    new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
-    old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->curposition);
+    int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
     pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index);
   }
   else {
@@ -1089,122 +1119,189 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
       pts_to_search += st_time / pts_time_base / AV_TIME_BASE;
     }
   }
+  return pts_to_search;
+}
 
-  av_log(anim->pFormatCtx,
-         AV_LOG_DEBUG,
-         "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64
-         ")\n",
-         (int64_t)pts_to_search,
-         pts_time_base,
-         frame_rate,
-         st_time);
+static bool ffmpeg_can_seek_by_scan(struct anim *anim, int position, struct anim_index *tc_index)
+{
+  if (position > anim->curposition + 1 && anim->preseek && !tc_index &&
+      position - (anim->curposition + 1) < anim->preseek) {
+    return true;
+  }
 
-  if (anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search) {
-    av_log(anim->pFormatCtx,
-           AV_LOG_DEBUG,
-           "FETCH: frame repeat: last: %" PRId64 " next: %" PRId64 "\n",
-           (int64_t)anim->last_pts,
-           (int64_t)anim->next_pts);
-    IMB_refImBuf(anim->last_frame);
-    anim->curposition = position;
-    return anim->last_frame;
+  if (tc_index == NULL) {
+    return false;
   }
 
-  if (position > anim->curposition + 1 && anim->preseek && !tc_index &&
-      position - (anim->curposition + 1) < anim->preseek) {
-    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval (no index)\n");
+  int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
+  int old_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list