From 5c694607223d9355e625985abaa2af0f2a4f17e8 Mon Sep 17 00:00:00 2001 From: claude-noether Date: Fri, 22 May 2026 14:20:37 +0200 Subject: [PATCH] ffmpeg-v4l2-request-fourier: restore AV_CODEC_FLAG_LOW_DELAY in H.264 decoder 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 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). --- .../0006-h264-restore-low-delay.patch | 82 +++++++++++++++++++ arch/ffmpeg-v4l2-request-fourier/PKGBUILD | 8 +- .../0006-h264-restore-low-delay.patch | 82 +++++++++++++++++++ .../ffmpeg-v4l2-request-fourier/build-deb.sh | 15 ++-- .../debian/changelog | 25 ++++++ 5 files changed, 202 insertions(+), 10 deletions(-) create mode 100644 arch/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch create mode 100644 debian/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch diff --git a/arch/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch b/arch/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch new file mode 100644 index 000000000..552351166 --- /dev/null +++ b/arch/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch @@ -0,0 +1,82 @@ +From 0d1292ea99bc4e5fa2da438259fa01a2374e3e04 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +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 + diff --git a/arch/ffmpeg-v4l2-request-fourier/PKGBUILD b/arch/ffmpeg-v4l2-request-fourier/PKGBUILD index c113842cd..fb927e8d7 100644 --- a/arch/ffmpeg-v4l2-request-fourier/PKGBUILD +++ b/arch/ffmpeg-v4l2-request-fourier/PKGBUILD @@ -24,7 +24,7 @@ _srcname=FFmpeg _version='8.1' _commit='b57fbbe50c9b2656fad86a1a7eeabfd2b2a50935' # v4l2-request-n8.1 tip 2026-04-24 pkgver=8.1.r123329.b57fbbe -pkgrel=8 # pkgrel=8 — H.264 luma-v deblock daedalus-fourier substitution (cycle 8, 2026-05-22) +pkgrel=9 # pkgrel=9 — restore AV_CODEC_FLAG_LOW_DELAY for H.264 (2026-05-22) epoch=2 # daedalus-fourier pin — first kernel substitution in libavcodec @@ -92,8 +92,9 @@ source=("git+https://github.com/Kwiboo/FFmpeg.git#commit=${_commit}" '0002-nv15-to-p010-unpack.patch' '0003-h264-idct4-daedalus-fourier.patch' '0004-h264-idct8-daedalus-fourier.patch' - '0005-h264-deblock-luma-v-daedalus-fourier.patch') -sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP') + '0005-h264-deblock-luma-v-daedalus-fourier.patch' + '0006-h264-restore-low-delay.patch') +sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP') pkgver() { cd "${_srcname}" @@ -109,6 +110,7 @@ prepare() { patch -Np1 -i "${srcdir}/0003-h264-idct4-daedalus-fourier.patch" patch -Np1 -i "${srcdir}/0004-h264-idct8-daedalus-fourier.patch" patch -Np1 -i "${srcdir}/0005-h264-deblock-luma-v-daedalus-fourier.patch" + patch -Np1 -i "${srcdir}/0006-h264-restore-low-delay.patch" } build() { diff --git a/debian/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch b/debian/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch new file mode 100644 index 000000000..552351166 --- /dev/null +++ b/debian/ffmpeg-v4l2-request-fourier/0006-h264-restore-low-delay.patch @@ -0,0 +1,82 @@ +From 0d1292ea99bc4e5fa2da438259fa01a2374e3e04 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +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 + diff --git a/debian/ffmpeg-v4l2-request-fourier/build-deb.sh b/debian/ffmpeg-v4l2-request-fourier/build-deb.sh index c9add2eba..b7bb34fb4 100755 --- a/debian/ffmpeg-v4l2-request-fourier/build-deb.sh +++ b/debian/ffmpeg-v4l2-request-fourier/build-deb.sh @@ -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 diff --git a/debian/ffmpeg-v4l2-request-fourier/debian/changelog b/debian/ffmpeg-v4l2-request-fourier/debian/changelog index c9bd89376..90e6b7800 100644 --- a/debian/ffmpeg-v4l2-request-fourier/debian/changelog +++ b/debian/ffmpeg-v4l2-request-fourier/debian/changelog @@ -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 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 —