[FFmpeg-devel] [PATCH] avcodec/h264dec: add option to ignore in band parameter set

Zhao Zhili quinkblack at foxmail.com
Sun Feb 6 16:58:36 EET 2022


It works in three mode:
0: don't ignore in-band ps
1: ignore in-band ps
-1: if corrupted data is detected, then ignore in-band ps afterwards

h264dec working hard to do error resilience, it doesn't drop a
whole packet when error is detected in a nalu. Then there is a
higher chance for fake sps/pps be found and used. This happened
in a mp4 file. h264dec failed to recovery after broken data due
to the fake pps, while other H.264 decoders have no such problem.
---
 libavcodec/h264dec.c | 17 ++++++++++++++++-
 libavcodec/h264dec.h |  1 +
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index a47caa95e8..1ee2b68459 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -681,6 +681,10 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
             break;
         case H264_NAL_SPS: {
             GetBitContext tmp_gb = nal->gb;
+            if (h->ps.sps && h->ignore_in_band_ps == 1) {
+                av_log(h, AV_LOG_WARNING, "ignore in-band sps\n");
+                break;
+            }
             if (avctx->hwaccel && avctx->hwaccel->decode_params) {
                 ret = avctx->hwaccel->decode_params(avctx,
                                                     nal->type,
@@ -700,6 +704,10 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
             break;
         }
         case H264_NAL_PPS:
+            if (h->ps.pps && h->ignore_in_band_ps == 1) {
+                av_log(h, AV_LOG_WARNING, "ignore in-band pps\n");
+                break;
+            }
             if (avctx->hwaccel && avctx->hwaccel->decode_params) {
                 ret = avctx->hwaccel->decode_params(avctx,
                                                     nal->type,
@@ -726,6 +734,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
         }
 
         if (err < 0) {
+            if (h->ignore_in_band_ps == -1)
+                h->ignore_in_band_ps = 1;
             av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n");
         }
     }
@@ -1011,8 +1021,12 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
     }
 
     buf_index = decode_nal_units(h, buf, buf_size);
-    if (buf_index < 0)
+    if (buf_index < 0) {
+        /* If there is corrupted data, then don't trust the in-band ps. */
+        if (h->ignore_in_band_ps == -1)
+            h->ignore_in_band_ps = 1;
         return AVERROR_INVALIDDATA;
+    }
 
     if (!h->cur_pic_ptr && h->nal_unit_type == H264_NAL_END_SEQUENCE) {
         av_assert0(buf_index <= buf_size);
@@ -1055,6 +1069,7 @@ static const AVOption h264_options[] = {
     { "nal_length_size", "nal_length_size", OFFSET(nal_length_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, VDX },
     { "enable_er", "Enable error resilience on damaged frames (unsafe)", OFFSET(enable_er), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD },
     { "x264_build", "Assume this x264 version if no x264 version found in any SEI", OFFSET(x264_build), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VD },
+    { "ignore_in_band_ps", "ignore in-band parameter set", OFFSET(ignore_in_band_ps), AV_OPT_TYPE_INT, {.i64 = 0}, -1, 1, VD },
     { NULL },
 };
 
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 8168c8e97b..760540bc9d 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -448,6 +448,7 @@ typedef struct H264Context {
     int bit_depth_luma;         ///< luma bit depth from sps to detect changes
     int chroma_format_idc;      ///< chroma format from sps to detect changes
 
+    int ignore_in_band_ps;
     H264ParamSets ps;
 
     uint16_t *slice_table_base;
-- 
2.31.1



More information about the ffmpeg-devel mailing list