PR #24267 opened by guy-with-a-why
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24267
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24267.patch

Implements slice data partitioning (NAL unit types 2 to 4) in the h264 decoder. 
Partition A carries the headers, B the intra residual and C the inter residual, 
chosen per macroblock from its type.

Partial support was removed in 
[167e004e1a](https://code.ffmpeg.org/FFmpeg/FFmpeg/commit/167e004e1aca7765686ed95d7cd8ea5064d4f6f6)
 as "does not work correctly and apparently never did". The defect was that 
partitions B and C were read from the start of the RBSP payload, skipping their 
`slice_id`, `colour_plane_id` and `redundant_pic_cnt` headers, so every 
residual read started at the wrong bit offset. Those headers are parsed here.

One divergence needs a decision. Clause 9.2.1 makes an inter neighbour 
unavailable for the `coeff_token` `nC` under constrained intra prediction, and 
step 7 then drops it from the `(nA + nB + 1) >> 1` average. JM instead treats 
it as available with `nN = 0`, so it still contributes to the average: the 
excluded neighbour increments the count that later triggers averaging, in both 
the reference [decoder][1] and [encoder][2]. This follows JM, since every 
partitioned stream comes from JM or a derivative, and the literal reading makes 
data_partitioning_cip.h264 fail. Two lines to flip if the spec text is 
preferred.

[1]: 
https://vcgit.hhi.fraunhofer.de/jvet/JM/-/blob/JM-19.0/ldecod/src/read_comp_cavlc.c#L61-66
[2]: 
https://vcgit.hhi.fraunhofer.de/jvet/JM/-/blob/JM-19.0/lencod/src/macroblock.c#L3890-3895

A missing partition fails the macroblock rather than concealing it; JM does not 
recover either. I've left as a follow-up.

```fate-samples
h264/data_partitioning.h264
h264/data_partitioning_ab.h264
h264/data_partitioning_cip.h264
```

The samples for data partitioning are JM 19.0 output derived from a synthetic 
clip and they have been sent to samples-request. The injected-samples CI step 
will fail until they land.


>From 92a941631832e00185e6f30c1abb85622db2636d Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:09:12 +0100
Subject: [PATCH 1/8] avcodec/h264dec: add data partitioning fields to
 H264SliceContext

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264dec.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 74fd09dfaa..4b3e423741 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -180,6 +180,15 @@ typedef struct H264SliceContext {
     GetBitContext gb;
     ERContext *er;
 
+    /* Data partitioning: residual comes from gb_dpb (intra) or gb_dpc (inter),
+     * chosen per macroblock. Values not pointers: this struct is memcpy'd. */
+    GetBitContext gb_dpb;
+    GetBitContext gb_dpc;
+    int data_partitioning;
+    int dpb_available;
+    int dpc_available;
+    unsigned slice_id;
+
     int slice_num;
     int slice_type;
     int slice_type_nos;         ///< S free slice type (SI/SP are remapped to 
I/P)
-- 
2.52.0


>From edc807f960df261500bce01a0766e8706a0c8522 Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:09:37 +0100
Subject: [PATCH 2/8] avcodec/h264_slice: parse slice_id from partition A

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_slice.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 9b5ed8f77e..429e955e6e 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -2073,6 +2073,32 @@ static int h264_slice_init(H264Context *h, 
H264SliceContext *sl,
     return 0;
 }
 
+/* slice_id follows slice_header() in a partition A (7.3.2.9.1). */
+static int h264_parse_slice_id(const H264Context *h, H264SliceContext *sl)
+{
+    const PPS *pps = h->ps.pps_list[sl->pps_id];
+    const SPS *sps = pps->sps;
+    unsigned nb_slice_ids = sps->mb_width * sps->mb_height;
+
+    if (pps->cabac) {
+        av_log(h->avctx, AV_LOG_ERROR, "Data partitioning requires CAVLC\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (sps->mb_aff && sl->picture_structure == PICT_FRAME)
+        nb_slice_ids /= 2;
+
+    sl->slice_id = get_ue_golomb_long(&sl->gb);
+    if (sl->slice_id >= nb_slice_ids) {
+        av_log(h->avctx, AV_LOG_ERROR, "slice_id %u out of range\n", 
sl->slice_id);
+        return AVERROR_INVALIDDATA;
+    }
+
+    sl->data_partitioning = 1;
+
+    return 0;
+}
+
 int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal)
 {
     H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued;
@@ -2081,10 +2107,20 @@ int ff_h264_queue_decode_slice(H264Context *h, const 
H2645NAL *nal)
 
     sl->gb = nal->gb;
 
+    sl->data_partitioning = 0;
+    sl->dpb_available     = 0;
+    sl->dpc_available     = 0;
+
     ret = h264_slice_header_parse(h, sl, nal);
     if (ret < 0)
         return ret;
 
+    if (nal->type == H264_NAL_DPA) {
+        ret = h264_parse_slice_id(h, sl);
+        if (ret < 0)
+            return ret;
+    }
+
     // discard redundant pictures
     if (sl->redundant_pic_count > 0) {
         sl->ref_count[0] = sl->ref_count[1] = 0;
-- 
2.52.0


>From c733de4f97e42ac0664dc1cdc2dbb4173f92532b Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:09:51 +0100
Subject: [PATCH 3/8] avcodec/h264dec: attach slice data partitions B and C

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_slice.c | 41 ++++++++++++++++++++++++++++++
 libavcodec/h264dec.c    | 55 ++++++++++++++++++++++++++++++++++++++---
 libavcodec/h264dec.h    |  7 ++++++
 3 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 429e955e6e..f64bb6a17e 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -2099,6 +2099,47 @@ static int h264_parse_slice_id(const H264Context *h, 
H264SliceContext *sl)
     return 0;
 }
 
+int ff_h264_attach_slice_partition(const H264Context *h, H264SliceContext *sl,
+                                   const H2645NAL *nal)
+{
+    const PPS *pps = h->ps.pps_list[sl->pps_id];
+    GetBitContext gb = nal->gb;
+    int redundant_pic_cnt = 0;
+    unsigned slice_id;
+
+    if (!sl->data_partitioning)
+        return AVERROR_INVALIDDATA;
+
+    slice_id = get_ue_golomb_long(&gb);
+    if (pps->sps->residual_color_transform_flag)
+        skip_bits(&gb, 2);                  // colour_plane_id
+    if (pps->redundant_pic_cnt_present)
+        redundant_pic_cnt = get_ue_golomb(&gb);
+
+    if (get_bits_left(&gb) < 0) {
+        av_log(h->avctx, AV_LOG_ERROR, "Truncated slice data partition\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    /* 7.4.2.9.2: B and C repeat the slice_id and redundant_pic_cnt of their 
A. */
+    if (slice_id != sl->slice_id || redundant_pic_cnt != 
sl->redundant_pic_count) {
+        av_log(h->avctx, AV_LOG_WARNING, "Slice data partition %c does not "
+               "match the preceding partition A\n",
+               nal->type == H264_NAL_DPB ? 'B' : 'C');
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (nal->type == H264_NAL_DPB) {
+        sl->gb_dpb        = gb;
+        sl->dpb_available = 1;
+    } else {
+        sl->gb_dpc        = gb;
+        sl->dpc_available = 1;
+    }
+
+    return 0;
+}
+
 int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal)
 {
     H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued;
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index b78b7989ea..1b8c1ecd92 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -580,12 +580,35 @@ static void debug_green_metadata(const 
H264SEIGreenMetaData *gm, void *logctx)
     }
 }
 
+/**
+ * Attach the partitions B and C following the partition A at idx; 7.4.1.2.3
+ * requires them to be adjacent, so no state is kept across NAL units.
+ *
+ * @return index of the last NAL absorbed, or idx if there were none.
+ */
+static int h264_attach_partitions(const H264Context *h, H264SliceContext *sl,
+                                  int idx)
+{
+    while (idx + 1 < h->pkt.nb_nals) {
+        const H2645NAL *nal = &h->pkt.nals[idx + 1];
+
+        if (nal->type != H264_NAL_DPB && nal->type != H264_NAL_DPC)
+            break;
+        if (ff_h264_attach_slice_partition(h, sl, nal) < 0)
+            break;
+        idx++;
+    }
+
+    return idx;
+}
+
 static int decode_nal_units(H264Context *h, AVBufferRef *buf_ref,
                             const uint8_t *buf, int buf_size)
 {
     AVCodecContext *const avctx = h->avctx;
     int nals_needed = 0; ///< number of NALs that need decoding before the 
next frame thread starts
     int idr_cleared=0;
+    int dp_attached_to = -1; ///< index of the last partition B/C claimed
     int i, ret = 0;
 
     h->has_slice = 0;
@@ -621,7 +644,7 @@ static int decode_nal_units(H264Context *h, AVBufferRef 
*buf_ref,
 
     for (i = 0; i < h->pkt.nb_nals; i++) {
         H2645NAL *nal = &h->pkt.nals[i];
-        int max_slice_ctx, err;
+        int max_slice_ctx, nb_queued, err;
 
         if (avctx->skip_frame >= AVDISCARD_NONREF &&
             nal->ref_idc == 0 && nal->type != H264_NAL_SEI)
@@ -647,14 +670,37 @@ static int decode_nal_units(H264Context *h, AVBufferRef 
*buf_ref,
             h->has_recovery_point = 1;
             av_fallthrough;
         case H264_NAL_SLICE:
+        case H264_NAL_DPA:
             h->has_slice = 1;
 
+            if (nal->type == H264_NAL_DPA) {
+                /* hwaccels take one self-contained slice NAL, not three */
+                if (avctx->hwaccel) {
+                    avpriv_request_sample(avctx, "hardware accelerated data 
partitioning");
+                    ret = AVERROR_PATCHWELCOME;
+                    goto end;
+                }
+                /* the lookahead needs all three partitions in one packet */
+                if (avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) {
+                    av_log(avctx, AV_LOG_ERROR, "Decoding in chunks is not "
+                           "supported for partitioned slices\n");
+                    ret = AVERROR(ENOSYS);
+                    goto end;
+                }
+            }
+
+            nb_queued = h->nb_slice_ctx_queued;
+
             if ((err = ff_h264_queue_decode_slice(h, nal))) {
                 H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued;
                 sl->ref_count[0] = sl->ref_count[1] = 0;
                 break;
             }
 
+            if (nal->type == H264_NAL_DPA && h->nb_slice_ctx_queued > 
nb_queued)
+                dp_attached_to = h264_attach_partitions(h,
+                    h->slice_ctx + h->nb_slice_ctx_queued - 1, i);
+
             if (h->current_slice == 1) {
                 if (avctx->active_thread_type & FF_THREAD_FRAME &&
                     i >= nals_needed && !h->setup_finished && h->cur_pic_ptr) {
@@ -679,10 +725,13 @@ static int decode_nal_units(H264Context *h, AVBufferRef 
*buf_ref,
                     goto end;
             }
             break;
-        case H264_NAL_DPA:
         case H264_NAL_DPB:
         case H264_NAL_DPC:
-            avpriv_request_sample(avctx, "data partitioning");
+            /* not claimed by the lookahead above, so it has no partition A */
+            if (i > dp_attached_to)
+                av_log(avctx, AV_LOG_WARNING, "Ignoring slice data partition "
+                       "%c without a matching partition A\n",
+                       nal->type == H264_NAL_DPB ? 'B' : 'C');
             break;
         case H264_NAL_SEI:
             if (h->setup_finished) {
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 4b3e423741..2212dfa2a7 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -700,6 +700,13 @@ void ff_h264_draw_horiz_band(const H264Context *h, 
H264SliceContext *sl, int y,
  * slices are queued for the previous field, they are decoded.
  */
 int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal);
+
+/**
+ * Attach a slice data partition B or C to the slice started by partition A.
+ */
+int ff_h264_attach_slice_partition(const H264Context *h, H264SliceContext *sl,
+                                   const H2645NAL *nal);
+
 int ff_h264_execute_decode_slices(H264Context *h);
 int ff_h264_update_thread_context(AVCodecContext *dst,
                                   const AVCodecContext *src);
-- 
2.52.0


>From 23d2bfee3677647330b25b0acd805a3a26a1833b Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:24:05 +0100
Subject: [PATCH 4/8] avcodec/h264_cavlc: read residual from the matching
 partition

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_cavlc.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c
index 09f7b42ba0..d3737166ad 100644
--- a/libavcodec/h264_cavlc.c
+++ b/libavcodec/h264_cavlc.c
@@ -662,6 +662,23 @@ int decode_luma_residual(const H264Context *h, 
H264SliceContext *sl,
     }
 }
 
+/* Residual is category 3 (intra) or 4 (inter), so it comes from partition B
+ * or C. NULL if that partition was not received. */
+static GetBitContext *mb_residual_gb(const H264Context *h, H264SliceContext 
*sl,
+                                     unsigned mb_type)
+{
+    int intra = IS_INTRA(mb_type);
+
+    if (!sl->data_partitioning)
+        return &sl->gb;
+    if (intra ? sl->dpb_available : sl->dpc_available)
+        return intra ? &sl->gb_dpb : &sl->gb_dpc;
+
+    av_log(h->avctx, AV_LOG_ERROR, "Missing slice data partition %c\n",
+           intra ? 'B' : 'C');
+    return NULL;
+}
+
 int ff_h264_decode_mb_cavlc(const H264Context *h, H264SliceContext *sl)
 {
     int mb_xy;
@@ -742,14 +759,18 @@ decode_intra_mb:
     if(IS_INTRA_PCM(mb_type)){
         const int mb_size = ff_h264_mb_sizes[h->ps.sps->chroma_format_idc] *
                             h->ps.sps->bit_depth_luma;
+        GetBitContext *gb = mb_residual_gb(h, sl, mb_type); // samples are 
category 3
+
+        if (!gb)
+            return AVERROR_INVALIDDATA;
 
         // We assume these blocks are very rare so we do not optimize it.
-        sl->intra_pcm_ptr = align_get_bits(&sl->gb);
-        if (get_bits_left(&sl->gb) < mb_size) {
+        sl->intra_pcm_ptr = align_get_bits(gb);
+        if (get_bits_left(gb) < mb_size) {
             av_log(h->avctx, AV_LOG_ERROR, "Not enough data for an intra PCM 
block.\n");
             return AVERROR_INVALIDDATA;
         }
-        skip_bits_long(&sl->gb, mb_size);
+        skip_bits_long(gb, mb_size);
 
         // In deblocking, the quantizer is 0
         h->cur_pic.qscale_table[mb_xy] = 0;
@@ -1067,10 +1088,13 @@ decode_intra_mb:
         int i4x4, i8x8, chroma_idx;
         int dquant;
         int ret;
-        GetBitContext *gb = &sl->gb;
+        GetBitContext *gb = mb_residual_gb(h, sl, mb_type);
         const uint8_t *scan, *scan8x8;
         const int max_qp = 51 + 6 * (h->ps.sps->bit_depth_luma - 8);
 
+        if (!gb)
+            return AVERROR_INVALIDDATA;
+
         dquant= get_se_golomb(&sl->gb);
 
         sl->qscale += (unsigned)dquant;
-- 
2.52.0


>From 8c6a8d6a5cc70d02b00a80980617d5b3acaa67e6 Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:24:05 +0100
Subject: [PATCH 5/8] avcodec/h264_parser: recognise partition A as a picture
 start

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_parser.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index af43cad609..56a8d830e2 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -360,6 +360,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
             p->poc.prev_poc_lsb          = 0;
             av_fallthrough;
         case H264_NAL_SLICE:
+        case H264_NAL_DPA:                // starts with a slice header too
             get_ue_golomb_long(&nal.gb);  // skip first_mb_in_slice
             slice_type   = get_ue_golomb_31(&nal.gb);
             s->pict_type = ff_h264_golomb_to_pict_type[slice_type % 5];
-- 
2.52.0


>From 74f9f416a5c638813b7479a83158487e34617e9d Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:37:41 +0100
Subject: [PATCH 6/8] avcodec/h264_mvpred: exclude inter neighbours from nC
 when partitioned

Signed-off-by: guy-with-a-why <[email protected]>
---
 libavcodec/h264_mvpred.h | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h
index 1fa5487322..3e4cde9625 100644
--- a/libavcodec/h264_mvpred.h
+++ b/libavcodec/h264_mvpred.h
@@ -668,10 +668,16 @@ 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,
+         * and real partitioned streams are encoded that way. Follow JM. */
+        int nnz_mask = sl->data_partitioning && 
h->ps.pps->constrained_intra_pred &&
+                       IS_INTRA(mb_type) ? IS_INTRA(-1) : -1;
+
         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 +688,14 @@ 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)) || top_type 
? 0 : 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 +714,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)) ||
+                            left_type[LEFT(i)] ? 0 : 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;
             }
         }
 
-- 
2.52.0


>From 1517b9b896f8aa8e0ccf13ab67667df1e17984f0 Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 14:42:02 +0100
Subject: [PATCH 7/8] Changelog,doc: note H.264 data partitioning support

Signed-off-by: guy-with-a-why <[email protected]>
---
 Changelog                 | 1 +
 doc/general_contents.texi | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Changelog b/Changelog
index 38f1e10263..bde534351e 100644
--- a/Changelog
+++ b/Changelog
@@ -10,6 +10,7 @@ version <next>:
 - latticepal filter
 - DVD-Audio LPCM decoder and demuxing support
 - AVFoundation input device selection by unique ID and USB serial number
+- H.264 data partitioning support
 
 
 version 9.0:
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index d81392e03f..d446391429 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -1059,7 +1059,8 @@ following image formats are supported:
 @item H.263 / H.263-1996     @tab  X  @tab  X
 @item H.263+ / H.263-1998 / H.263 version 2  @tab  X  @tab  X
 @item H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10  @tab  E  @tab  X
-    @tab encoding supported through external library libx264 and OpenH264
+    @tab encoding supported through external library libx264 and OpenH264,
+          decoding supports data partitioning
 @item HEVC                   @tab  X  @tab  X
     @tab encoding supported through external library libx265 and libkvazaar
 @item HNM version 4          @tab     @tab  X
-- 
2.52.0


>From 4a52755fda95d51b7910fbe351a7cc26e7a590d0 Mon Sep 17 00:00:00 2001
From: guy-with-a-why <[email protected]>
Date: Tue, 25 Aug 2026 15:36:17 +0100
Subject: [PATCH 8/8] fate/h264: add slice data partitioning tests

Signed-off-by: guy-with-a-why <[email protected]>
---
 tests/fate/h264.mak                       |  8 ++++++++
 tests/ref/fate/h264-data-partitioning     | 15 +++++++++++++++
 tests/ref/fate/h264-data-partitioning-ab  | 15 +++++++++++++++
 tests/ref/fate/h264-data-partitioning-cip | 15 +++++++++++++++
 4 files changed, 53 insertions(+)
 create mode 100644 tests/ref/fate/h264-data-partitioning
 create mode 100644 tests/ref/fate/h264-data-partitioning-ab
 create mode 100644 tests/ref/fate/h264-data-partitioning-cip

diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak
index dacaaab274..a42366f8eb 100644
--- a/tests/fate/h264.mak
+++ b/tests/fate/h264.mak
@@ -193,6 +193,9 @@ FATE_H264_REINIT_TESTS := large_420_8-to-small_420_8        
            \
                           small_422_9-to-small_420_9                    \
 
 FATE_H264  := $(FATE_H264:%=fate-h264-conformance-%)                    \
+              fate-h264-data-partitioning                               \
+              fate-h264-data-partitioning-ab                            \
+              fate-h264-data-partitioning-cip                           \
               fate-h264-intra-refresh-recovery                          \
               fate-h264-lossless                                        \
               fate-h264-3386                                            \
@@ -465,6 +468,11 @@ fate-h264-xavc-4389:                              CMD = 
framecrc -i $(TARGET_SAM
 fate-h264-attachment-631:                         CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/attachment631-small.mp4 -an -max_error_rate 0.96
 fate-h264-skip-nokey:                             CMD = framecrc -skip_frame 
nokey -i $(TARGET_SAMPLES)/h264/h264_intra_first-small.ts -vf scale -af 
aresample
 fate-h264-skip-nointra:                           CMD = framecrc -skip_frame 
nointra -i $(TARGET_SAMPLES)/h264/h264_intra_first-small.ts -vf scale -af 
aresample
+# slice data partitioning: A+B+C, and with partition C legitimately absent
+fate-h264-data-partitioning:                      CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/data_partitioning.h264
+fate-h264-data-partitioning-ab:                   CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/data_partitioning_ab.h264
+# constrained_intra_pred_flag=1, which changes the nC derivation (9.2.1)
+fate-h264-data-partitioning-cip:                  CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/data_partitioning_cip.h264
 fate-h264-intra-refresh-recovery:                 CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/intra_refresh.h264 -frames:v 10
 fate-h264-invalid-ref-mod:                        CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264refframeregression.mp4 -an -frames 10 -pix_fmt 
yuv420p10le -vf scale
 fate-h264-lossless:                               CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/lossless.h264
diff --git a/tests/ref/fate/h264-data-partitioning 
b/tests/ref/fate/h264-data-partitioning
new file mode 100644
index 0000000000..00a1b45f92
--- /dev/null
+++ b/tests/ref/fate/h264-data-partitioning
@@ -0,0 +1,15 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 176x144
+#sar 0: 0/1
+0,          0,          0,        1,    38016, 0x1b6c95f8
+0,          1,          1,        1,    38016, 0x3321d0ef
+0,          2,          2,        1,    38016, 0x8ab31546
+0,          3,          3,        1,    38016, 0x978d5bc8
+0,          4,          4,        1,    38016, 0xe3c1d02b
+0,          5,          5,        1,    38016, 0x11bafd04
+0,          6,          6,        1,    38016, 0x8760741a
+0,          7,          7,        1,    38016, 0x565ba13f
+0,          8,          8,        1,    38016, 0xdf66f465
+0,          9,          9,        1,    38016, 0x54bf06b8
diff --git a/tests/ref/fate/h264-data-partitioning-ab 
b/tests/ref/fate/h264-data-partitioning-ab
new file mode 100644
index 0000000000..6a430edda5
--- /dev/null
+++ b/tests/ref/fate/h264-data-partitioning-ab
@@ -0,0 +1,15 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 176x144
+#sar 0: 0/1
+0,          0,          0,        1,    38016, 0x1b6c95f8
+0,          1,          1,        1,    38016, 0xc732de4b
+0,          2,          2,        1,    38016, 0x34875d49
+0,          3,          3,        1,    38016, 0x76906edf
+0,          4,          4,        1,    38016, 0xe673e1a7
+0,          5,          5,        1,    38016, 0xc2f1f465
+0,          6,          6,        1,    38016, 0x08f49ac4
+0,          7,          7,        1,    38016, 0xee04b8ff
+0,          8,          8,        1,    38016, 0xf45202b2
+0,          9,          9,        1,    38016, 0x40051425
diff --git a/tests/ref/fate/h264-data-partitioning-cip 
b/tests/ref/fate/h264-data-partitioning-cip
new file mode 100644
index 0000000000..74f9ac0437
--- /dev/null
+++ b/tests/ref/fate/h264-data-partitioning-cip
@@ -0,0 +1,15 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 176x144
+#sar 0: 0/1
+0,          0,          0,        1,    38016, 0x1b6c95f8
+0,          1,          1,        1,    38016, 0x63e2d92f
+0,          2,          2,        1,    38016, 0x6f631a0f
+0,          3,          3,        1,    38016, 0xfee663ea
+0,          4,          4,        1,    38016, 0x3866d66c
+0,          5,          5,        1,    38016, 0xa918f919
+0,          6,          6,        1,    38016, 0xda56794e
+0,          7,          7,        1,    38016, 0x53d9abfc
+0,          8,          8,        1,    38016, 0x2deff2ec
+0,          9,          9,        1,    38016, 0xae1c0e66
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to