ffmpeg-v4l2-request-fourier: restore AV_CODEC_FLAG_LOW_DELAY in H.264 decoder
FFmpeg 8.x dropped the H.264 decoder's low_delay code path — AV_CODEC_FLAG_LOW_DELAY no longer prevents h264_select_output_frame from running the display-order DPB output queue. The daedalus-v4l2 daemon's `ctx->flags |= AV_CODEC_FLAG_LOW_DELAY` at daemon/src/decoder.c:202 has been a silent no-op since the SONAME 61→62 jump landed in reauktion/daedalus-v4l2 PR #16; on Firefox YouTube this re-introduced the 2-1-4-3 B-frame pair-swap that PR #12's daemon flag was supposed to prevent. Fix lives in libavcodec, not the daemon: restore the documented LOW_DELAY semantics so the daemon (and any other V4L2-stateless- style consumer) keeps the one-frame-per-send_packet decode-order output contract it already declares. ## Patch 0006-h264-restore-low-delay.patch touches libavcodec/h264_slice.c: - h264_select_output_frame: early-exit when LOW_DELAY is set. Emit the just-decoded picture as next_output_pic, mirror the corruption / recovery-point tracking the main path performs, skip delayed_pic[] / POC reorder machinery entirely. - h264_field_start: suppress the SPS-driven `has_b_frames = sps->num_reorder_frames` clobber when LOW_DELAY is set. Without this the per-slice bitstream_restriction_flag re-pickup would reintroduce a nonzero reorder buffer mid-stream even after the daemon set has_b_frames=0 at avcodec_open2. ## Why not daemon-side A daemon SPS-rewrite (`num_reorder_frames=0`) was considered but rejected: it works only for the daemon's reconstructed SPS NAL, not for any in-band SPS the daemon dlopens libavformat to parse in other code paths. Restoring documented FFmpeg flag semantics is the smaller, more durable change and keeps the daemon interface stable. ## Packaging - PKGREL/pkgrel bump to 9. - No new build-deps, no Depends change. - Substitution arc cycles 6/7/8 unchanged. ## Refs - reauktion/daedalus-v4l2#11 / #12 (LOW_DELAY half-measure on daemon side, originally landed against FFmpeg 7.x). - daemon/src/decoder.c:202 (`ctx->flags |= AV_CODEC_FLAG_LOW_DELAY` for H.264 only — unchanged, but now actually has effect again).
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
From 0d1292ea99bc4e5fa2da438259fa01a2374e3e04 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Fritsche <mfritsche@reauktion.de>
|
||||
Date: Fri, 22 May 2026 14:18:25 +0200
|
||||
Subject: [PATCH] avcodec/h264: restore AV_CODEC_FLAG_LOW_DELAY semantics
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
FFmpeg 8.x dropped the H.264 decoder's low_delay path —
|
||||
AV_CODEC_FLAG_LOW_DELAY no longer prevents
|
||||
h264_select_output_frame from running the display-order DPB
|
||||
output queue. V4L2-stateless-style consumers (daedalus-v4l2
|
||||
daemon, libva-v4l2-request-fourier) that set the flag end up
|
||||
seeing the 2-1-4-3 pair-swap pattern on B-frame streams again.
|
||||
|
||||
Restore the documented semantics:
|
||||
|
||||
- Early-exit at the top of h264_select_output_frame when the
|
||||
flag is set: emit the just-decoded picture immediately as
|
||||
next_output_pic, mirror the corruption / recovery-point
|
||||
tracking the main path performs, and skip the entire
|
||||
delayed_pic[] / POC reorder machinery.
|
||||
|
||||
- Suppress the SPS-driven has_b_frames clobber in
|
||||
h264_field_start when the flag is set, so the per-slice
|
||||
bitstream_restriction_flag re-pickup cannot reintroduce a
|
||||
nonzero reorder buffer mid-stream.
|
||||
|
||||
This is a fork-only change required by the daedalus-v4l2 daemon's
|
||||
one-frame-per-send_packet contract; upstream FFmpeg consumers that
|
||||
expect display-order output remain untouched (flag default = off).
|
||||
|
||||
Refs reauktion/daedalus-v4l2#11 — substitution arc step 2 deblock
|
||||
+ flag-restoration follow-up.
|
||||
---
|
||||
libavcodec/h264_slice.c | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
|
||||
index 97fab70..a7bfbd6 100644
|
||||
--- a/libavcodec/h264_slice.c
|
||||
+++ b/libavcodec/h264_slice.c
|
||||
@@ -1308,6 +1308,28 @@ static int h264_select_output_frame(H264Context *h)
|
||||
cur->mmco_reset = h->mmco_reset;
|
||||
h->mmco_reset = 0;
|
||||
|
||||
+ /* AV_CODEC_FLAG_LOW_DELAY restore (FFmpeg 8.x dropped the H.264
|
||||
+ * decoder's low_delay path). Bypass the display-order DPB
|
||||
+ * output queue: emit the just-decoded picture immediately, in
|
||||
+ * decode order, one per send_packet. V4L2-stateless-style
|
||||
+ * consumers (daedalus-v4l2 daemon, libva-v4l2-request-fourier)
|
||||
+ * do their own POC-based reorder downstream and require this
|
||||
+ * behaviour. */
|
||||
+ if (h->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) {
|
||||
+ h->next_output_pic = cur;
|
||||
+ h->next_outputed_poc = cur->poc;
|
||||
+ h->frame_recovered |= cur->recovered;
|
||||
+ cur->recovered |= h->frame_recovered & FRAME_RECOVERED_SEI;
|
||||
+ if (!cur->recovered) {
|
||||
+ if (!(h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) &&
|
||||
+ !(h->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL))
|
||||
+ h->next_output_pic = NULL;
|
||||
+ else
|
||||
+ cur->f->flags |= AV_FRAME_FLAG_CORRUPT;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (sps->bitstream_restriction_flag ||
|
||||
h->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
|
||||
h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, sps->num_reorder_frames);
|
||||
@@ -1415,6 +1437,7 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl,
|
||||
sps = h->ps.sps;
|
||||
|
||||
if (sps->bitstream_restriction_flag &&
|
||||
+ !(h->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) &&
|
||||
h->avctx->has_b_frames < sps->num_reorder_frames) {
|
||||
h->avctx->has_b_frames = sps->num_reorder_frames;
|
||||
}
|
||||
--
|
||||
2.47.3
|
||||
|
||||
+8
-7
@@ -33,13 +33,13 @@ FFMPEG_VERSION=8.1
|
||||
# epoch 2 matches Debian's stock ffmpeg (currently 7:7.1.x in trixie);
|
||||
# +rfourier suffix to avoid colliding with upstream/Debian rebuilds.
|
||||
PKGVER=2:${FFMPEG_VERSION}+rfourier+gb57fbbe
|
||||
PKGREL=8 # pkgrel=8 — H.264 luma-v deblock daedalus-fourier substitution
|
||||
# (cycle 8, non-intra bS<4 vertical luma). Stacks on cycles
|
||||
# 6/7 (IDCT 4x4 + 8x8). Wires H264DSPContext.v_loop_filter_luma
|
||||
# through daedalus_recipe_dispatch_h264_deblock_luma_v.
|
||||
# ctx stays no-QPU until a separate change gates Vulkan init
|
||||
# on a feature flag; cycle-8 dispatch is NEON-by-recipe for
|
||||
# now. (2026-05-22)
|
||||
PKGREL=9 # pkgrel=9 — restore AV_CODEC_FLAG_LOW_DELAY semantics in the
|
||||
# H.264 decoder (FFmpeg 8.x dropped them). Fixes the 2-1-4-3
|
||||
# B-frame pair-swap that re-appeared in Firefox YouTube after
|
||||
# the SONAME 61→62 jump (PR #75) silently neutered the
|
||||
# daemon's ctx->flags |= AV_CODEC_FLAG_LOW_DELAY at
|
||||
# daemon/src/decoder.c:202. Substitution arc unchanged.
|
||||
# (2026-05-22)
|
||||
|
||||
# daedalus-fourier pin — first kernel substitution in libavcodec (cycle 6
|
||||
# H.264 IDCT 4x4). Same SHA as the daedalus-v4l2 daemon already ships
|
||||
@@ -71,6 +71,7 @@ patch -Np1 -i "$HERE/0002-nv15-to-p010-unpack.patch"
|
||||
patch -Np1 -i "$HERE/0003-h264-idct4-daedalus-fourier.patch"
|
||||
patch -Np1 -i "$HERE/0004-h264-idct8-daedalus-fourier.patch"
|
||||
patch -Np1 -i "$HERE/0005-h264-deblock-luma-v-daedalus-fourier.patch"
|
||||
patch -Np1 -i "$HERE/0006-h264-restore-low-delay.patch"
|
||||
|
||||
# --- daedalus-fourier: fetch + build static .a with PIC, install to a
|
||||
# per-build prefix; libavcodec.so links it into the shared object so
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
ffmpeg-v4l2-request-fourier (2:8.1+rfourier+gb57fbbe-9) bookworm trixie; urgency=medium
|
||||
|
||||
* Add 0006-h264-restore-low-delay.patch — restore the documented
|
||||
AV_CODEC_FLAG_LOW_DELAY semantics in the H.264 decoder. FFmpeg
|
||||
8.x dropped the H.264 low_delay code path entirely; setting the
|
||||
flag at avcodec_open2 no longer prevents the display-order DPB
|
||||
output queue from running. Visible on Firefox YouTube as the
|
||||
2-1-4-3 B-frame pair-swap, re-introduced silently by the
|
||||
SONAME 61→62 jump in daedalus-v4l2 PR #16.
|
||||
* h264_select_output_frame: early-exit when LOW_DELAY is set;
|
||||
emit the just-decoded picture as next_output_pic, mirror the
|
||||
corruption / recovery-point tracking, skip delayed_pic[] and
|
||||
the POC reorder machinery entirely.
|
||||
* h264_field_start: suppress the SPS-driven
|
||||
has_b_frames = sps->num_reorder_frames clobber when LOW_DELAY
|
||||
is set — without this the per-slice bitstream_restriction_flag
|
||||
re-pickup would reintroduce a nonzero reorder buffer mid-
|
||||
stream.
|
||||
* Restores the same one-frame-per-send_packet contract the
|
||||
daedalus-v4l2 daemon's decoder.c already relies on (the flag
|
||||
is set unconditionally for H.264). No daemon side change.
|
||||
* No SONAME change, no Depends change.
|
||||
|
||||
-- Markus Fritsche <mfritsche@reauktion.de> Fri, 22 May 2026 13:30:00 +0000
|
||||
|
||||
ffmpeg-v4l2-request-fourier (2:8.1+rfourier+gb57fbbe-8) bookworm trixie; urgency=medium
|
||||
|
||||
* Add 0005-h264-deblock-luma-v-daedalus-fourier.patch —
|
||||
|
||||
Reference in New Issue
Block a user