[Bf-blender-cvs] [847002e1f88] master: FFMPEG: refactor seeking

Richard Antalik noreply at git.blender.org
Fri Mar 26 12:46:30 CET 2021


Commit: 847002e1f88b6f4906ce039b3cd69570664052d5
Author: Richard Antalik
Date:   Fri Mar 26 12:40:46 2021 +0100
Branches: master
https://developer.blender.org/rB847002e1f88b6f4906ce039b3cd69570664052d5

FFMPEG: refactor seeking

Split seeking section of `ffmpeg_fetchibuf()` function into multiple
smaller functions.

Conditional statements are moved to own funtions with human readable
names, so code flow is more clear.

To remove one branch of seeking, first frame is now decoded by
scanning, which will do only one iteration. So nothing has technically
changed.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10638

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

M	source/blender/imbuf/intern/anim_movie.c

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

diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index d36c7bbe486..3a19bc36f6c 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -969,44 +969,6 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
   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... */
-  int count = 1000;
-
-  av_log(anim->pFormatCtx,
-         AV_LOG_DEBUG,
-         "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n",
-         (int64_t)anim->next_pts,
-         (int64_t)pts_to_search);
-
-  while (count > 0 && anim->next_pts < pts_to_search) {
-    av_log(anim->pFormatCtx,
-           AV_LOG_DEBUG,
-           "  WHILE: pts=%" PRId64 " in search of %" PRId64 "\n",
-           (int64_t)anim->next_pts,
-           (int64_t)pts_to_search);
-    if (!ffmpeg_decode_video_frame(anim)) {
-      break;
-    }
-    count--;
-  }
-  if (count == 0) {
-    av_log(anim->pFormatCtx,
-           AV_LOG_ERROR,
-           "SCAN failed: completely lost in stream, "
-           "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n",
-           (int64_t)anim->next_pts,
-           (int64_t)pts_to_search);
-  }
-  if (anim->next_pts == pts_to_search) {
-    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
-  }
-  else {
-    av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
-  }
-}
-
 static int match_format(const char *name, AVFormatContext *pFormatCtx)
 {
   const char *p;
@@ -1049,37 +1011,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,117 +1032,211 @@ 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_pts_matches_last_frame(struct anim *anim, int64_t pts_to_search)
+{
+  return anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search;
+}
 
-  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;
-  }
+/* Requested video frame is expected to be found within different GOP as last decoded frame.
+ * Seeking to new position and scanning is fastest way to get requested frame.
+ * Check whether ffmpeg_can_scan() and ffmpeg_pts_matches_last_frame() is false before using this
+ * function. */
+static bool ffmpeg_can_seek(struct anim *anim, int position)
+{
+  return position != anim->curposition + 1;
+}
 
+/* Requested video frame is expected to be found within same GOP as last decoded frame.
+ * Decoding frames in sequence until frame matches requested one is fastest way to get it. */
+static bool ffmpeg_can_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) {
-    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval (no index)\n");
+    return true;
+  }
 
-    ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+  if (tc_index == NULL) {
+    return false;
   }
-  else if (tc_index && IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index)) {
+
+  int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
+  int old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->curposition);
+  return IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index);
+}
+
+static bool ffmpeg_is_first_frame_decode(struct anim *anim, int position)
+{
+  return position == 0 && anim->curposition == -1;
+}
+
+/* Decode frames one by one until its PTS matches pts_to_search. */
+static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search)
+{
+  av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval\n");
+
+  /* there seem to exist *very* silly GOP lengths out in the wild... */
+  int count = 1000;
+
+  av_log(anim->pFormatCtx,
+         AV_LOG_DEBUG,
+         "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n",
+         (int64_t)anim->next_pts,
+         (int64_t)pts_to_search);
+
+  while (count > 0 && anim->next_pts < pts_to_search) {
     av_log(anim->pFormatCtx,
            AV_LOG_DEBUG,
-           "FETCH: within preseek interval "
-           "(index tells us)\n");
-
-    ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+           "  WHILE: pts=%" PRId64 " in search of %" PRId64 "\n",
+           (int64_t)anim->next_pts,
+           (int64_t)pts_to_search);
+    if (!ffmpeg_decode_video_frame(anim)) {
+      break;
+    }
+    count--;
+  }
+  if (count == 0) {
+    av_log(anim->pFormatCtx,
+           AV_LOG_ERROR,
+           "SCAN failed: completely lost in stream, "
+           "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n",
+           (int64_t)anim->next_pts,
+           (int64_t)pts_to_search);
+  }
+  if (anim->next_pts == pts_to_search) {
+    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
+  }
+  else {
+    av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
   }
-  else if (position != anim->curposition + 1) {
-    int64_t pos;
-    int ret;
+}
 
-    if (tc_index) {
-      uint64_t dts;
+/* Seek to last necessary I-frame and scan-decode until requested frame is found. */
+static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_index *tc_index)
+{
+  AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
+  double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
+  int64_t st_time = anim->pFormatCtx->start_time;
 
-      pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index);
-      dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
+  int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
 
-      av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos);
-      av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts);
+  int64_t pos;
+  int ret;
 
-      if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
-        av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n");
+  if (tc_index) {
+    int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
+    uint64_t dts;
 
-        ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BYTE);
-        av_update_cur_dts(anim->pFormatCtx, v_st, dts);
-      }
-      else {
-        av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using DTS pos\n");
-        ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, dts, AVSEEK_FLAG_BACKWARD);
-      }
-    }
-    else {
-      pos = (int64_t)position * AV_TIME_BASE / frame_rate;
+    pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index);
+    dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
 
-      av_log(anim->pFormatCtx,
-             AV_LOG_DEBUG,
-             "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n",
-             pos,
-             (st_time != AV_NOPTS_VALUE) ? st_time : 0);
+    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos);
+    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts);
 
-      if (pos < 0) {
-        pos = 0;
-      }
+    if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
+      av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n");
 
-      if (st_time != AV_NOPTS_VALUE) {
-        pos += st_time;
-      }
+      ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BYTE);
+      av_update_cur_dts(anim->pFormatCtx, v_st, dts);
+    }
+    else {
+      av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using DTS pos\n");
+      ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, dts, AVSEEK_FLAG_BACKWARD);
+    }
+  }
+  else {
+    pos = (int64_t)(position)*AV_TIME_BASE / frame_rate;
 
-      av_log(

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list