diff options
author | Richard Antalik <richardantalik@gmail.com> | 2021-11-15 22:20:33 +0300 |
---|---|---|
committer | Richard Antalik <richardantalik@gmail.com> | 2021-11-15 22:20:33 +0300 |
commit | d3c45e1c391eaafd9c54dba5b574b1a7ee23c82a (patch) | |
tree | 874cea7188bd56ccddcb59151d5d46e29f469b77 /source/blender/imbuf/intern | |
parent | ef8240e64c9f7805ef65d9f7599bfb3eca97566c (diff) |
Fix T91405: Block artefacts in WEBM video
Issue was caused by incorrect FFmpeg asynchronous decoding API. In most
cases, decoder returns 1 frame each time it is fed by 1 packet. Here
decoder wanted to return more frames, but our code always expected only
one.
Before sending new packets to decoder, check if there are frames to
receive. If there are, process them, otherwise continue decoding as
usual.
Reviewed By: zeddb, sergey
Differential Revision: https://developer.blender.org/D13079
Diffstat (limited to 'source/blender/imbuf/intern')
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 54 |
1 files changed, 27 insertions, 27 deletions
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index c11c6d778a1..87f2fd124c0 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -939,14 +939,36 @@ static void ffmpeg_postprocess(struct anim *anim) } } -/* decode one video frame also considering the packet read into cur_packet */ +static void ffmpeg_decode_store_frame_pts(struct anim *anim) +{ + anim->cur_pts = av_get_pts_from_frame(anim->pFrame); + + if (anim->pFrame->key_frame) { + anim->cur_key_frame_pts = anim->cur_pts; + } + + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", + (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, + (int64_t)anim->cur_pts); +} +/* decode one video frame also considering the packet read into cur_packet */ static int ffmpeg_decode_video_frame(struct anim *anim) { - int rval = 0; - av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n"); + /* Sometimes, decoder returns more than one frame per sent packet. Check if frames are available. + * This frames must be read, otherwise decoding will fail. See T91405. */ + anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; + if (anim->pFrameComplete) { + av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE FROM CODEC BUFFER\n"); + ffmpeg_decode_store_frame_pts(anim); + return 1; + } + + int rval = 0; if (anim->cur_packet->stream_index == anim->videoStream) { av_packet_unref(anim->cur_packet); anim->cur_packet->stream_index = -1; @@ -963,22 +985,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim) (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts, (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); if (anim->cur_packet->stream_index == anim->videoStream) { - anim->pFrameComplete = 0; - avcodec_send_packet(anim->pCodecCtx, anim->cur_packet); anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFrame); - - if (anim->pFrame->key_frame) { - anim->cur_key_frame_pts = anim->cur_pts; - } - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (int64_t)anim->cur_pts); + ffmpeg_decode_store_frame_pts(anim); break; } } @@ -988,22 +999,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim) if (rval == AVERROR_EOF) { /* Flush any remaining frames out of the decoder. */ - anim->pFrameComplete = 0; - avcodec_send_packet(anim->pCodecCtx, NULL); anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFrame); - - if (anim->pFrame->key_frame) { - anim->cur_key_frame_pts = anim->cur_pts; - } - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (int64_t)anim->cur_pts); + ffmpeg_decode_store_frame_pts(anim); rval = 0; } } |