[PR] Allow out-of-range ph_recovery_poc_cnt in non-strict mode (PR #24304)
jianhuaw via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
PR #24304 opened by jianhuaw URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24304 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24304.patch This patch allows non-conforming VVC streams with an out-of-range ph_recovery_poc_cnt to be parsed and decoded in non-strict mode, since this field does not affect entropy decoding. Strict mode still rejects the value according to H.266 7.4.3.8, while the derived recovery POC remains checked against FFmpeg's internal POC range. Tested with `FFmpeg/ffmpeg -hide_banner -loglevel warning -flags +output_corrupt -threads:v 1 -i /tmp/NetflixAerial_422_10b_4Mbps_4K_gdr.vvc -f null -`, which warns and continues decoding; adding -strict strict reports ph_recovery_poc_cnt ... must be in [0,15] and rejects the non-conforming value. >From e21c134f4c85a454a606c14dd3ce766b25117d8e Mon Sep 17 00:00:00 2001 From: Wu Jianhua <[email protected]> Date: Thu, 27 Aug 2026 04:08:10 +0800 Subject: [PATCH] avcodec/vvc: allow out-of-range ph_recovery_poc_cnt in non-strict mode Signed-off-by: Wu Jianhua <[email protected]> --- libavcodec/cbs_h266.h | 2 +- libavcodec/cbs_h266_syntax_template.c | 5 +-- libavcodec/vvc/ps.c | 45 ++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h index 67a3ff6151..65f73f5366 100644 --- a/libavcodec/cbs_h266.h +++ b/libavcodec/cbs_h266.h @@ -681,7 +681,7 @@ typedef struct H266RawPictureHeader { uint8_t ph_intra_slice_allowed_flag; uint8_t ph_pic_parameter_set_id; uint16_t ph_pic_order_cnt_lsb; - uint8_t ph_recovery_poc_cnt; + uint32_t ph_recovery_poc_cnt; uint8_t ph_extra_bit[16]; uint8_t ph_poc_msb_cycle_present_flag; uint8_t ph_poc_msb_cycle_val; diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index 32703d4493..ca18f691e8 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -2679,8 +2679,9 @@ static int FUNC(picture_header) (CodedBitstreamContext *ctx, RWContext *rw, ub(sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4, ph_pic_order_cnt_lsb); if (current->ph_gdr_pic_flag) - ue(ph_recovery_poc_cnt, 0, - 1 << (sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4)); + // H.266 7.4.3.8: ph_recovery_poc_cnt shall be in [0, MaxPicOrderCntLsb - 1]. + // The range check is deferred to decode_recovery_poc(). + ue(ph_recovery_poc_cnt, 0, UINT32_MAX - 1); for (i = 0; i < sps->sps_num_extra_ph_bytes * 8; i++) { if (sps->sps_extra_ph_bit_present_flag[i]) diff --git a/libavcodec/vvc/ps.c b/libavcodec/vvc/ps.c index d9f46b219a..9ec2f51e1e 100644 --- a/libavcodec/vvc/ps.c +++ b/libavcodec/vvc/ps.c @@ -20,6 +20,7 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <limits.h> #include <stdbool.h> #include "libavcodec/cbs_h266.h" @@ -1047,14 +1048,47 @@ static void decode_recovery_flag(VVCContext *s) s->no_output_before_recovery_flag = s->last_eos; } -static void decode_recovery_poc(VVCContext *s, const VVCPH *ph) +static int decode_recovery_poc(VVCContext *s, const VVCFrameParamSets *fps) { + const VVCPH *ph = &fps->ph; + + if (IS_GDR(s)) { + const uint32_t recovery_poc_cnt = ph->r->ph_recovery_poc_cnt; + const uint32_t max_recovery_poc_cnt = fps->sps->max_pic_order_cnt_lsb - 1; + + const int64_t recovery_poc = (int64_t)ph->poc + recovery_poc_cnt; + if (recovery_poc_cnt > max_recovery_poc_cnt && + s->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) { + av_log(s->avctx, AV_LOG_ERROR, + "ph_recovery_poc_cnt out of range: %"PRIu32 + ", but must be in [0,%"PRIu32"].\n", + recovery_poc_cnt, max_recovery_poc_cnt); + return AVERROR_INVALIDDATA; + } + + if (recovery_poc <= INT_MIN || recovery_poc > INT_MAX) { + av_log(s->avctx, AV_LOG_ERROR, + "Recovery point POC out of range: %"PRId64".\n", + recovery_poc); + return AVERROR_INVALIDDATA; + } + + if (recovery_poc_cnt > max_recovery_poc_cnt) + av_log(s->avctx, AV_LOG_WARNING, + "ph_recovery_poc_cnt out of range: %"PRIu32 + ", expected [0,%"PRIu32"].\n", + recovery_poc_cnt, max_recovery_poc_cnt); + + if (s->no_output_before_recovery_flag) + s->gdr_recovery_point_poc = recovery_poc; + } + if (s->no_output_before_recovery_flag) { - if (IS_GDR(s)) - s->gdr_recovery_point_poc = ph->poc + ph->r->ph_recovery_poc_cnt; if (!GDR_IS_RECOVERED(s) && s->gdr_recovery_point_poc <= ph->poc) GDR_SET_RECOVERED(s); } + + return 0; } int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) @@ -1072,7 +1106,10 @@ int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) return ret; ret = decode_frame_ps(fps, ps, h266, s->poc_tid0, is_clvss); - decode_recovery_poc(s, &fps->ph); + if (ret < 0) + return ret; + + ret = decode_recovery_poc(s, fps); return ret; } -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]