[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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.