This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit e13b8370910351d9601dd9ead7d3ce77fff6869b
Author:     guy-with-a-why <[email protected]>
AuthorDate: Fri Aug 28 10:25:14 2026 +0100
Commit:     Timo Rothenpieler <[email protected]>
CommitDate: Mon Aug 31 18:13:21 2026 +0000

    avcodec/h264: derive nC for partitioned constrained-intra slices
    
    An inter neighbour must not contribute its coefficient count to nC for
    an intra macroblock when constrained intra prediction and data
    partitioning are both in use; otherwise decoding partitions A and B
    alone would depend on data that lives in partition C.
    
    The neighbour is kept available with nN = 0, which is what JM does and
    what the streams it produces expect. FF_BUG_H264_DP_NNZ selects that
    and is autodetected on the first partition A, while -bug 0 drops the
    neighbour from the average as 9.2.1 has it. Streams without data
    partitioning decode identically either way.
    
    This replaces a FIXME older than any data partitioning support.
    
    Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_mvpred.h | 28 ++++++++++++++++++++++------
 libavcodec/h264dec.c     |  4 ++++
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h
index 1fa5487322..1d5f22417e 100644
--- a/libavcodec/h264_mvpred.h
+++ b/libavcodec/h264_mvpred.h
@@ -668,10 +668,23 @@ static void fill_decode_caches(const H264Context *h, 
H264SliceContext *sl, int m
          * 4 L . .L . . . .
          * 5 L . .. . . . .
          */
-        /* FIXME: constraint_intra_pred & partitioning & nnz
-         * (let us hope this is just a typo in the spec) */
+        /* 9.2.1: with data partitioning and constrained intra prediction, an
+         * inter neighbour must not contribute to nC for an intra macroblock.
+         * Step 7 would drop it from the (nA + nB + 1) >> 1 average entirely,
+         * but JM's predict_nnz() counts it as present with zero coefficients.
+         * FF_BUG_H264_DP_NNZ picks JM, and is autodetected in h264dec.c. */
+        int nnz_mask     = -1;
+        int nnz_excluded = 64;      // 64: unavailable, 0: present but empty
+
+        if (sl->data_partitioning && h->ps.pps->constrained_intra_pred &&
+            IS_INTRA(mb_type)) {
+            nnz_mask = IS_INTRA(-1);
+            if (h->workaround_bugs & FF_BUG_H264_DP_NNZ)
+                nnz_excluded = 0;
+        }
+
         nnz_cache = sl->non_zero_count_cache;
-        if (top_type) {
+        if (top_type & nnz_mask) {
             nnz = h->non_zero_count[top_xy];
             AV_COPY32(&nnz_cache[4 + 8 * 0], &nnz[4 * 3]);
             if (!h->chroma_y_shift) {
@@ -682,14 +695,15 @@ static void fill_decode_caches(const H264Context *h, 
H264SliceContext *sl, int m
                 AV_COPY32(&nnz_cache[4 + 8 * 10], &nnz[4 * 9]);
             }
         } else {
-            uint32_t top_empty = CABAC(h) && !IS_INTRA(mb_type) ? 0 : 
0x40404040;
+            uint32_t top_empty = CABAC(h) && !IS_INTRA(mb_type) ? 0 :
+                                 top_type ? nnz_excluded * 0x01010101u : 
0x40404040;
             AV_WN32A(&nnz_cache[4 + 8 *  0], top_empty);
             AV_WN32A(&nnz_cache[4 + 8 *  5], top_empty);
             AV_WN32A(&nnz_cache[4 + 8 * 10], top_empty);
         }
 
         for (i = 0; i < 2; i++) {
-            if (left_type[LEFT(i)]) {
+            if (left_type[LEFT(i)] & nnz_mask) {
                 nnz = h->non_zero_count[left_xy[LEFT(i)]];
                 nnz_cache[3 + 8 * 1 + 2 * 8 * i] = nnz[left_block[8 + 0 + 2 * 
i]];
                 nnz_cache[3 + 8 * 2 + 2 * 8 * i] = nnz[left_block[8 + 1 + 2 * 
i]];
@@ -708,12 +722,14 @@ static void fill_decode_caches(const H264Context *h, 
H264SliceContext *sl, int m
                     nnz_cache[3 + 8 * 11 + 8 * i] = nnz[left_block[8 + 5 + 2 * 
i]];
                 }
             } else {
+                int empty = CABAC(h) && !IS_INTRA(mb_type) ? 0 :
+                            left_type[LEFT(i)] ? nnz_excluded : 64;
                 nnz_cache[3 + 8 *  1 + 2 * 8 * i] =
                 nnz_cache[3 + 8 *  2 + 2 * 8 * i] =
                 nnz_cache[3 + 8 *  6 + 2 * 8 * i] =
                 nnz_cache[3 + 8 *  7 + 2 * 8 * i] =
                 nnz_cache[3 + 8 * 11 + 2 * 8 * i] =
-                nnz_cache[3 + 8 * 12 + 2 * 8 * i] = CABAC(h) && 
!IS_INTRA(mb_type) ? 0 : 64;
+                nnz_cache[3 + 8 * 12 + 2 * 8 * i] = empty;
             }
         }
 
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 3e583ef6d2..0892850fe0 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -675,6 +675,10 @@ static int decode_nal_units(H264Context *h, AVBufferRef 
*buf_ref,
             h->has_slice = 1;
 
             if (nal->type == H264_NAL_DPA) {
+                /* partitioned streams all come from JM or a derivative */
+                if (h->workaround_bugs & FF_BUG_AUTODETECT)
+                    h->workaround_bugs |= FF_BUG_H264_DP_NNZ;
+
                 /* hwaccels take one self-contained slice NAL, not three */
                 if (avctx->hwaccel) {
                     avpriv_request_sample(avctx, "hardware accelerated data 
partitioning");

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to