ffmpeg-v4l2-request-fourier: restore AV_CODEC_FLAG_LOW_DELAY in H.264 decoder #87

Merged
marfrit merged 1 commits from claude-noether/marfrit-packages:noether/ffmpeg-fourier-restore-low-delay into main 2026-05-22 14:27:44 +00:00
Owner

Bug: 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.

Evidence:

$ grep AV_CODEC_FLAG_LOW_DELAY libavcodec/h264*.c     # → zero hits in 8.1
$ grep -n h264_select_output_frame libavcodec/h264_slice.c
1301:static int h264_select_output_frame(H264Context *h)
  → uses avctx->has_b_frames + POC reorder; no flag check

Fix

0006-h264-restore-low-delay.patch touches libavcodec/h264_slice.c:

  • h264_select_output_frame: early-exit when AV_CODEC_FLAG_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.

Verify post-merge

After deploying on higgs, Firefox YouTube on an H.264 stream with B-frames (any standard YouTube codec=avc1) should play in display order — no visible 2-1-4-3 pair-swap.

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)
**Bug**: 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. **Evidence**: ``` $ grep AV_CODEC_FLAG_LOW_DELAY libavcodec/h264*.c # → zero hits in 8.1 $ grep -n h264_select_output_frame libavcodec/h264_slice.c 1301:static int h264_select_output_frame(H264Context *h) → uses avctx->has_b_frames + POC reorder; no flag check ``` ## Fix `0006-h264-restore-low-delay.patch` touches `libavcodec/h264_slice.c`: - `h264_select_output_frame`: early-exit when `AV_CODEC_FLAG_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. ## Verify post-merge After deploying on higgs, Firefox YouTube on an H.264 stream with B-frames (any standard YouTube codec=avc1) should play in display order — no visible 2-1-4-3 pair-swap. ## 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)
marfrit added 1 commit 2026-05-22 12:21:01 +00:00
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).
marfrit merged commit cf9eef6cfa into main 2026-05-22 14:27:44 +00:00
marfrit deleted branch noether/ffmpeg-fourier-restore-low-delay 2026-05-22 14:27:44 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marfrit/marfrit-packages#87