[Bf-blender-cvs] [79fa4f6623b] temp-VSE-fixes: Fix VSE seeking issues.

Sebastian Parborg noreply at git.blender.org
Fri Aug 13 15:39:36 CEST 2021


Commit: 79fa4f6623b0912f71561256a2cf64c9c4e10d4d
Author: Sebastian Parborg
Date:   Mon Jul 12 19:13:15 2021 +0200
Branches: temp-VSE-fixes
https://developer.blender.org/rB79fa4f6623b0912f71561256a2cf64c9c4e10d4d

Fix VSE seeking issues.

The seek pts was not correctly calculated.
In addition to that we were not seeking in the video pts time base.

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

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

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

diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index c08df2889de..fd96110b59e 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -1059,33 +1059,21 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
   return false;
 }
 
-static int64_t ffmpeg_get_seek_pos(struct anim *anim, int position)
+static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search)
 {
   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;
-  int64_t pos = (int64_t)(position)*AV_TIME_BASE;
-  /* Step back half a time base position to make sure that we get the requested
-   * frame and not the one after it.
+  AVRational frame_rate = v_st->r_frame_rate;
+  AVRational time_base = v_st->time_base;
+  double steps_per_frame = (double)(frame_rate.den * time_base.den) /
+                           (double)(frame_rate.num * time_base.num);
+  /* Step back half a frame position to make sure that we get the requested
+   * frame and not the one after it. This is a workaround as ffmpeg will
+   * sometimes not seek to a frame after the requested pts even if
+   * AVSEEK_FLAG_BACKWARD is specified.
    */
-  pos -= (AV_TIME_BASE / 2);
-  pos /= frame_rate;
+  int64_t pts = pts_to_search - (steps_per_frame / 2);
 
-  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);
-
-  if (pos < 0) {
-    pos = 0;
-  }
-
-  if (st_time != AV_NOPTS_VALUE) {
-    pos += st_time;
-  }
-
-  return pos;
+  return pts;
 }
 
 /* This gives us an estimate of which pts our requested frame will have.
@@ -1102,17 +1090,18 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
     pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index);
   }
   else {
-    int64_t st_time = anim->pFormatCtx->start_time;
     AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
-    AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL);
+    int64_t start_pts = v_st->start_time;
+    AVRational frame_rate = v_st->r_frame_rate;
     AVRational time_base = v_st->time_base;
 
-    int64_t steps_per_frame = (frame_rate.den * time_base.den) / (frame_rate.num * time_base.num);
-    pts_to_search = position * steps_per_frame;
+    double steps_per_frame = (double)(frame_rate.den * time_base.den) /
+                             (double)(frame_rate.num * time_base.num);
+
+    pts_to_search = round(position * steps_per_frame);
 
-    if (st_time != AV_NOPTS_VALUE && st_time != 0) {
-      int64_t start_frame = (double)st_time / AV_TIME_BASE * av_q2d(frame_rate);
-      pts_to_search += start_frame * steps_per_frame;
+    if (start_pts != AV_NOPTS_VALUE) {
+      pts_to_search += start_pts;
     }
   }
   return pts_to_search;
@@ -1196,23 +1185,29 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
  * decoded will be read. See https://trac.ffmpeg.org/ticket/1607 and
  * https://developer.blender.org/T86944. */
 static int ffmpeg_generic_seek_workaround(struct anim *anim,
-                                          int64_t *requested_pos,
+                                          int64_t *requested_pts,
                                           int64_t pts_to_search)
 {
   AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
-  double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
-  int64_t current_pos = *requested_pos;
+  AVRational frame_rate = v_st->r_frame_rate;
+  AVRational time_base = v_st->time_base;
+
+  double steps_per_frame = (double)(frame_rate.den * time_base.den) /
+                           (double)(frame_rate.num * time_base.num);
+
+  int64_t current_pts = *requested_pts;
   int64_t offset = 0;
 
   int64_t cur_pts, prev_pts = -1;
 
   /* Step backward frame by frame until we find the key frame we are looking for. */
-  while (current_pos != 0) {
-    current_pos = *requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate);
-    current_pos = max_ii(current_pos, 0);
+  while (current_pts != 0) {
+    current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame);
+    current_pts = max_ii(current_pts, 0);
 
     /* Seek to timestamp. */
-    if (av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD) < 0) {
+    if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) <
+        0) {
       break;
     }
 
@@ -1249,10 +1244,10 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim,
     offset++;
   }
 
-  *requested_pos = current_pos;
+  *requested_pts = current_pts;
 
   /* Re-seek to timestamp that gave I-frame, so it can be read by decode function. */
-  return av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD);
+  return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD);
 }
 
 /* Seek to last necessary key frame. */
@@ -1300,13 +1295,13 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim,
   else {
     /* We have to manually seek with ffmpeg to get to the key frame we want to start decoding from.
      */
-    pos = ffmpeg_get_seek_pos(anim, position);
+    pos = ffmpeg_get_seek_pts(anim, pts_to_search);
     av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos);
 
     AVFormatContext *format_ctx = anim->pFormatCtx;
 
     if (format_ctx->iformat->read_seek2 || format_ctx->iformat->read_seek) {
-      ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
+      ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD);
     }
     else {
       ret = ffmpeg_generic_seek_workaround(anim, &pos, pts_to_search);
@@ -1351,7 +1346,7 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim,
 
       anim->cur_key_frame_pts = gop_pts;
       /* Seek back so we are at the correct position after we decoded a frame. */
-      av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
+      av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD);
     }
   }
 
@@ -1391,18 +1386,18 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
   struct anim_index *tc_index = IMB_anim_open_index(anim, tc);
   int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
   AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
-  double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
+  double frame_rate = av_q2d(v_st->r_frame_rate);
   double pts_time_base = av_q2d(v_st->time_base);
-  int64_t st_time = anim->pFormatCtx->start_time;
+  int64_t start_pts = v_st->start_time;
 
   av_log(anim->pFormatCtx,
          AV_LOG_DEBUG,
-         "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64
+         "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64
          ")\n",
          (int64_t)pts_to_search,
          pts_time_base,
          frame_rate,
-         st_time);
+         start_pts);
 
   if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) {
     av_log(anim->pFormatCtx,
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 27195b294d6..bbb0f3b5b22 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -1022,7 +1022,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
 
   stream_size = avio_size(context->iFormatCtx->pb);
 
-  context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL));
+  context->frame_rate = av_q2d(context->iStream->r_frame_rate);
   context->pts_time_base = av_q2d(context->iStream->time_base);
 
   while (av_read_frame(context->iFormatCtx, next_packet) >= 0) {



More information about the Bf-blender-cvs mailing list