diff options
author | Sebastian Parborg <darkdefende@gmail.com> | 2021-06-09 22:03:07 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2021-06-11 15:04:48 +0300 |
commit | 4adbe31e2fc98f982aed3d97505513750ec348d4 (patch) | |
tree | 002cc553168d9712b6b935fcb3acae09fb55fc99 /source/blender/imbuf/intern/anim_movie.c | |
parent | 1fb2eaf1c5ed4f7fc121c24c9b6daa37331cf8ee (diff) |
Fix: VSE indexer seeking not working correctly
Because of the added sanity checks in rB14508ef100c9 (D11492), seeking
in proxies would not work correctly any more. This is because it wasn't
working as intended before, but in most cases this wouldn't be
noticeable. However now when the sanity checks are tripped it is very
noticeable that something is wrong
The indexer tried to use dts values for time stamps when we used pts in
our decode functions to get the time positions. This would make it
start in the wrong GOP frames when searching. Now that we enforce no
crossing of GOP frames when decoding after seek, this would lead to
issues.
Now we correctly use pts (or dts if pts is not available) and thus we
don't have any seeking issues because of time stamp format missmatch.
Reviewed By: Richard Antalik
Differential Revision: http://developer.blender.org/D11561
Diffstat (limited to 'source/blender/imbuf/intern/anim_movie.c')
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index b65c3e364db..739ec988121 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -924,7 +924,7 @@ static int ffmpeg_decode_video_frame(struct anim *anim) anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame); + anim->cur_pts = av_get_pts_from_frame(anim->pFrame); if (anim->pFrame->key_frame) { anim->cur_key_frame_pts = anim->cur_pts; @@ -949,7 +949,7 @@ static int ffmpeg_decode_video_frame(struct anim *anim) anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame); + anim->cur_pts = av_get_pts_from_frame(anim->pFrame); if (anim->pFrame->key_frame) { anim->cur_key_frame_pts = anim->cur_pts; @@ -1164,6 +1164,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_ if (anim->cur_packet->stream_index == anim->videoStream) { break; } + av_packet_unref(read_packet); } /* If this packet contains I-frame, exit loop. This should be the frame that we need. */ @@ -1197,14 +1198,17 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim /* No need to seek, return early. */ return 0; } + uint64_t pts; uint64_t dts; pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index); + pts = IMB_indexer_get_seek_pos_pts(tc_index, new_frame_index); dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index); - anim->cur_key_frame_pts = pos; + anim->cur_key_frame_pts = timestamp_from_pts_or_dts(pts, dts); av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pts = %" PRIu64 "\n", pts); av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts); if (ffmpeg_seek_by_byte(anim->pFormatCtx)) { @@ -1214,8 +1218,9 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim 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); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using PTS pos\n"); + ret = av_seek_frame( + anim->pFormatCtx, anim->videoStream, anim->cur_key_frame_pts, AVSEEK_FLAG_BACKWARD); } } else { @@ -1243,24 +1248,29 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim } av_packet_unref(current_gop_start_packet); } - bool same_gop = current_gop_start_packet->pts == anim->cur_key_frame_pts; + int64_t gop_pts = timestamp_from_pts_or_dts(current_gop_start_packet->pts, + current_gop_start_packet->dts); + + av_packet_free(¤t_gop_start_packet); + bool same_gop = gop_pts == anim->cur_key_frame_pts; if (same_gop && position > anim->cur_position) { /* Change back to our old frame position so we can simply continue decoding from there. */ AVPacket *temp = av_packet_alloc(); while (av_read_frame(anim->pFormatCtx, temp) >= 0) { - if (temp->stream_index == anim->videoStream && temp->pts == anim->cur_packet->pts) { + int64_t temp_pts = timestamp_from_pts_or_dts(temp->pts, temp->dts); + int64_t cur_pts = timestamp_from_pts_or_dts(anim->cur_packet->pts, + anim->cur_packet->dts); + if (temp->stream_index == anim->videoStream && temp_pts == cur_pts) { break; } av_packet_unref(temp); } - av_packet_free(¤t_gop_start_packet); av_packet_free(&temp); return 0; } - anim->cur_key_frame_pts = current_gop_start_packet->pts; - av_packet_free(¤t_gop_start_packet); + 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); } @@ -1278,6 +1288,8 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim pts_to_search, ret); } + /* Flush the internal buffers of ffmpeg. This needs to be done after seeking to avoid decoding + * errors. */ avcodec_flush_buffers(anim->pCodecCtx); anim->cur_pts = -1; |