PR #24155 opened by Kacper Michajłow (kasper93)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24155
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24155.patch


From f1d318e5eb2eb487d2be4b4b721b93ae76fd5ba7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]>
Date: Thu, 30 Jul 2026 17:29:04 +0200
Subject: [PATCH 1/2] avcodec/h264_slice: clear the ER picture when starting a
 second field
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

h264_frame_start() clears h->er.cur_pic, and decode_nal_units() only sets
it again for pictures that are not field coded, right before running error
concealment. A second field goes through neither, so h->er.cur_pic keeps
pointing at whatever frame coded picture the context decoded earlier.

With frame threading the two fields of a pair are decoded by different
contexts, so whether this triggers depends on what the context that picks
up the second field decoded before, which is why the number of bogus
warnings varies between runs.

Signed-off-by: Kacper Michajłow <[email protected]>
---
 libavcodec/h264_slice.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 9b5ed8f77e..a13047ffe8 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1627,6 +1627,10 @@ static int h264_field_start(H264Context *h, const 
H264SliceContext *sl,
         int field = h->picture_structure == PICT_BOTTOM_FIELD;
         release_unused_pictures(h, 0);
         h->cur_pic_ptr->tf.owner[field] = h->avctx;
+        /* h264_frame_start(), which clears this for every other picture, is
+         * not called for a second field. */
+        if (CONFIG_ERROR_RESILIENCE)
+            ff_h264_set_erpic(&h->er.cur_pic, NULL);
     }
     /* Some macroblocks can be accessed before they're available in case
     * of lost slices, MBAFF or threading. */
-- 
2.52.0


From c3a8a223b29260dc170d41c62f9b3b33f6b97b2d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]>
Date: Sat, 15 Aug 2026 00:36:22 +0200
Subject: [PATCH 2/2] avcodec/h264_direct: do not read the other field's rows
 of colocated mb_type
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

To determine whether the colocated picture is field coded, the temporal
and spatial direct setup peek at
sl->ref_list[1][0].parent->mb_type[mb_xy] before mb_xy has been remapped
to the colocated field's parity. That row belongs to the current field's
parity, while await_reference_mb_row() above waited on the parity of the
referenced field, so whenever the two differ the load is unsynchronised
and with frame threading can observe macroblocks of a field that is
still being decoded.

Every macroblock of a field picture has MB_TYPE_INTERLACED set, so
checking field_picture first gives the same result in all correctly
synchronized cases without touching the mb_type array.

This also fixes few TSAN reported warnings.

Fixes: https://trac.ffmpeg.org/ticket/10891
Signed-off-by: Kacper Michajłow <[email protected]>
---
 libavcodec/h264_direct.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c
index be388ada3a..1bc4f911ba 100644
--- a/libavcodec/h264_direct.c
+++ b/libavcodec/h264_direct.c
@@ -292,7 +292,8 @@ static void pred_spatial_direct_motion(const H264Context 
*const h, H264SliceCont
         return;
     }
 
-    if (IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // 
AFL/AFR/FR/FL -> AFL/FL
+    if (sl->ref_list[1][0].parent->field_picture ||
+        IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // 
AFL/AFR/FR/FL -> AFL/FL
         if (!IS_INTERLACED(*mb_type)) {                    //     AFR/FR    -> 
AFL/FL
             mb_y  = (sl->mb_y & ~1) + sl->col_parity;
             mb_xy = sl->mb_x +
@@ -510,7 +511,8 @@ static void pred_temp_direct_motion(const H264Context 
*const h, H264SliceContext
     await_reference_mb_row(h, &sl->ref_list[1][0],
                            sl->mb_y + !!IS_INTERLACED(*mb_type));
 
-    if (IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // 
AFL/AFR/FR/FL -> AFL/FL
+    if (sl->ref_list[1][0].parent->field_picture ||
+        IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // 
AFL/AFR/FR/FL -> AFL/FL
         if (!IS_INTERLACED(*mb_type)) {                    //     AFR/FR    -> 
AFL/FL
             mb_y  = (sl->mb_y & ~1) + sl->col_parity;
             mb_xy = sl->mb_x +
-- 
2.52.0

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

Reply via email to