Opened 2 weeks ago

#10965 new defect

avcodec: h.264 decoder flags result as ER error_occurred with frame threading

Reported by: jeeb Owned by:
Priority: normal Component: avcodec
Version: git-master Keywords: avcodec h264
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

With sample https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264 , in case of frame threading being enabled, the H.264 decoder flags multiple output frames with decode_error_flags: FF_DECODE_ERROR_DECODE_SLICES (8) before the sudden end at the end of the sample (where there are actual MB decoding errors), while disabling threading leads to this flagging not happening

The data seems to match between these two cases and there is no visual corruption, so either both are fine or both are in some manner broken. I have not compared against the JM reference decoder yet.

How to reproduce:

% ffmpeg -threads:v 2 -i "https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264" -f null pipe:
ffmpeg version N-114837-g257bc2a82a Copyright (c) 2000-2024 the FFmpeg developers
  built with gcc 14 (GCC)
  configuration: --prefix=/home/jeeb/ownapps/encoding_prefix/ --enable-static --disable-doc --disable-stripping --enable-gpl --enable-version3 --enable-vaapi --enable-zlib --enable-libdav1d --enable-libx264 --enable-libsvtav1 --enable-libx265 --enable-libzimg --enable-gnutls --enable-libplacebo
  libavutil      59. 15.100 / 59. 15.100
  libavcodec     61.  5.103 / 61.  5.103
  libavformat    61.  3.100 / 61.  3.100
  libavdevice    61.  2.100 / 61.  2.100
  libavfilter    10.  2.101 / 10.  2.101
  libswscale      8.  2.100 /  8.  2.100
  libswresample   5.  2.100 /  5.  2.100
  libpostproc    58.  2.100 / 58.  2.100
[h264 @ 0x5475300] Stream #0: not enough frames to estimate rate; consider increasing probesize
Input #0, h264, from 'https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, top first), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 50 tbr, 1200k tbn
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
Press [q] to stop, [?] for help
Output #0, null, to 'pipe:':
  Metadata:
    encoder         : Lavf61.3.100
  Stream #0:0: Video: wrapped_avframe, yuv420p(tv, bt709, top coded first (swapped)), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 25 fps, 25 tbn
      Metadata:
        encoder         : Lavc61.5.103 wrapped_avframe
[vist#0:0/h264 @ 0x6144c80] [dec:h264 @ 0x551c4c0] corrupt decoded frame
    Last message repeated 7 times
[h264 @ 0x60bee40] error while decoding MB 64 10, bytestream -16 speed=1.92x    
[h264 @ 0x60bee40] concealing 6945 DC, 6945 AC, 6945 MV errors in P frame
[vist#0:0/h264 @ 0x6144c80] [dec:h264 @ 0x551c4c0] corrupt decoded frame
[out#0/null @ 0x5517800] video:18KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
frame=   42 fps=0.0 q=-0.0 Lsize=N/A time=00:00:01.68 bitrate=N/A speed=2.51x

Comparison with threading disabled:

ffmpeg -threads:v 1 -i "https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264" -f null pipe:
ffmpeg version N-114837-g257bc2a82a Copyright (c) 2000-2024 the FFmpeg developers
  built with gcc 14 (GCC)
  configuration: --prefix=/home/jeeb/ownapps/encoding_prefix/ --enable-static --disable-doc --disable-stripping --enable-gpl --enable-version3 --enable-vaapi --enable-zlib --enable-libdav1d --enable-libx264 --enable-libsvtav1 --enable-libx265 --enable-libzimg --enable-gnutls --enable-libplacebo
  libavutil      59. 15.100 / 59. 15.100
  libavcodec     61.  5.103 / 61.  5.103
  libavformat    61.  3.100 / 61.  3.100
  libavdevice    61.  2.100 / 61.  2.100
  libavfilter    10.  2.101 / 10.  2.101
  libswscale      8.  2.100 /  8.  2.100
  libswresample   5.  2.100 /  5.  2.100
  libpostproc    58.  2.100 / 58.  2.100
[h264 @ 0x605b300] Stream #0: not enough frames to estimate rate; consider increasing probesize
Input #0, h264, from 'https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, top first), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 50 tbr, 1200k tbn
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
Press [q] to stop, [?] for help
Output #0, null, to 'pipe:':
  Metadata:
    encoder         : Lavf61.3.100
  Stream #0:0: Video: wrapped_avframe, yuv420p(tv, bt709, top coded first (swapped)), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 25 fps, 25 tbn
      Metadata:
        encoder         : Lavc61.5.103 wrapped_avframe
[h264 @ 0x6de1580] error while decoding MB 64 10, bytestream -16 speed=1.16x    
[h264 @ 0x6de1580] concealing 6945 DC, 6945 AC, 6945 MV errors in P frame
[vist#0:0/h264 @ 0x6d2ac80] [dec:h264 @ 0x61024c0] corrupt decoded frame
[out#0/null @ 0x60fd800] video:18KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
frame=   42 fps= 34 q=-0.0 Lsize=N/A time=00:00:01.68 bitrate=N/A speed=1.37x

Some changes I have applied to check values:

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 70de151301..5be43910ad 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -731,7 +731,8 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame)
 
         if (frame->decode_error_flags || (frame->flags & AV_FRAME_FLAG_CORRUPT)) {
             av_log(dp, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
-                   "corrupt decoded frame\n");
+                   "corrupt decoded frame. decode_error_flags: %d, AV_FRAME_FLAG_CORRUPT: %d\n",
+                   frame->decode_error_flags, (frame->flags & AV_FRAME_FLAG_CORRUPT));
             if (exit_on_error)
                 return AVERROR_INVALIDDATA;
         }
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 727dc1a662..f31c936595 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -756,6 +756,9 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
         if (h->cur_pic_ptr->decode_error_flags) {
             /* Frame-threading in use */
             atomic_int *decode_error = h->cur_pic_ptr->decode_error_flags;
+            av_log(h->avctx, AV_LOG_WARNING,
+                   "threaded error case: ret: %d, ER error_occurred: %d, decode_error_flags : %d\n",
+                   ret, h->er.error_occurred, *h->cur_pic_ptr->decode_error_flags);
             /* Using atomics here is not supposed to provide syncronisation;
              * they are merely used to allow to set decode_error from both
              * decoding threads in case of coded slices. */

Example of checking that the output is the same between the two cases:

ffmpeg -threads:v 1 -i "https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264" -f framehash pipe: > 01-hashes_threadless.txt
ffmpeg -threads:v 2 -i "https://megumin.fushizen.eu/samples/2024-04-15-framethread_causes_er_errors.264" -f framehash pipe: > 02-hashes_threaded.txt
git diff --no-index 01-hashes_threadless.txt 02-hashes_threaded.txt

Change History (0)

Note: See TracTickets for help on using tickets.