[Bf-blender-cvs] [d3c45e1c391] blender-v3.0-release: Fix T91405: Block artefacts in WEBM video

Richard Antalik noreply at git.blender.org
Mon Nov 15 20:32:38 CET 2021


Commit: d3c45e1c391eaafd9c54dba5b574b1a7ee23c82a
Author: Richard Antalik
Date:   Mon Nov 15 20:20:33 2021 +0100
Branches: blender-v3.0-release
https://developer.blender.org/rBd3c45e1c391eaafd9c54dba5b574b1a7ee23c82a

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

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

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 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;
     }
   }



More information about the Bf-blender-cvs mailing list