[PR] h264: give frame num gap dummies the duplicated picture's hwaccel state and POCs (PR #23982)

Lynne via ffmpeg-devel <[email protected]> Sun, 02 Aug 2026 13:14:22 -0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178567646323.59.11560332156867549116@29965ddac10e>
PR #23982 opened by Lynne
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23982
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23982.patch

The dummies created for gaps in frame_num duplicate the previous
reference's frame, but kept their own freshly-allocated
hwaccel_picture_private and their field POCs at INT_MAX. Hardware
decoders locate reference pictures through hwaccel_picture_private and
order them by the field POCs, so predicting from a dummy read
unrelated or uninitialized memory, and streams with lost frames
decoded to garbage from the first gap onwards.

Carry the duplicated picture's hwaccel state over to the dummy, which
also keeps it valid after the duplicated picture leaves the DPB, and
give the dummy sane field POCs.

Fixes https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/23930


>From 2ced61ca80624f9dd50b699c65ae4efb0ca7e328 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Thu, 30 Jul 2026 18:16:58 +0900
Subject: [PATCH] h264: give frame num gap dummies the duplicated picture's
 hwaccel state and POCs

The dummies created for gaps in frame_num duplicate the previous
reference's frame, but kept their own freshly-allocated
hwaccel_picture_private and their field POCs at INT_MAX. Hardware
decoders locate reference pictures through hwaccel_picture_private and
order them by the field POCs, so predicting from a dummy read
unrelated or uninitialized memory, and streams with lost frames
decoded to garbage from the first gap onwards.

Carry the duplicated picture's hwaccel state over to the dummy, which
also keeps it valid after the duplicated picture leaves the DPB, and
give the dummy sane field POCs.
---
 libavcodec/h264_slice.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 9b5ed8f77e..1d344f99da 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1564,7 +1564,18 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl,
                 if (ret < 0)
                     return ret;
                 h->short_ref[0]->poc = prev->poc + 2U;
+                /* The frame POC is all hwaccels see; leaving the field POCs
+                 * at their INT_MAX init value breaks their reference
+                 * ordering. */
+                h->short_ref[0]->field_poc[0] = h->short_ref[0]->poc;
+                h->short_ref[0]->field_poc[1] = h->short_ref[0]->poc;
                 h->short_ref[0]->gray = prev->gray;
+                /* Hardware decoders keep DPB state (e.g. separate reference
+                 * images) in hwaccel_picture_private; carry the duplicated
+                 * picture's over so references to the dummy read its pixels,
+                 * even after the duplicated picture leaves the DPB. */
+                av_refstruct_replace(&h->short_ref[0]->hwaccel_picture_private,
+                                     prev->hwaccel_picture_private);
                 ff_thread_report_progress(&h->short_ref[0]->tf, INT_MAX, 0);
                 if (h->short_ref[0]->field_picture)
                     ff_thread_report_progress(&h->short_ref[0]->tf, INT_MAX, 1);
-- 
2.52.0

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