The ladder's last rung no longer runs FFmpeg. H.264 decodes through openh264, AV1 through rav1d, and HEVC is refused outright: no permissively licensed software HEVC decoder exists, so an HEVC session that exhausts its hardware rungs now tears down and re-dials advertising HEVC-less caps, and the host picks H.264. The plan calls that a first-class path; it is one. swscale is deleted, and with it the BT.601 default that its correction code existed to undo. Colour on the H.264 lane now comes from the same pf-bitstream planner every hardware rung submits from — openh264 reports no VUI at all — and AV1's comes per-picture from the sequence header. One colour source, one CSC: the old default is unrepresentable rather than merely fixed. Frames reach the presenter as three tightly-packed planes through the planar CSC pass, which had to be un-gated from the pyrowave feature and its device probe, since the last rung must exist on devices that failed that probe. rav1d rather than the dav1d crate, deliberately and against the plan's literal wording: dav1d-sys is system-deps-only, so it would add a system library and a .pc file to every client package — in the milestone family whose excision checklist exists to delete exactly that. rav1d is the same decoder, same licence, statically linked. The cost is honest: no-asm builds on both decoders, and software throughput is still unmeasured. The colour test is the milestone's exit criterion, so it is built to fail. Three fixtures, and a mutation check: hardcoding the swscale default turns the red bar to [255,24,0], and swapping Cb/Cr turns red to blue — a silent error no metadata assertion could catch. Review then disproved the range half of it numerically: with eight saturated bars, decoding the full-range fixture with the wrong range gives max error ZERO, because a mismatch only pushes values outside [0,1] where the shader clamps. A mid-tone was added; the wrong range now costs 11, well past the tolerance. The exit criterion I set was satisfiable by a test that proved nothing. Two blocking defects, both emergent rather than local. Software AV1 on a 10-bit stream never reached its typed refusal: rav1d is built 8-bit-only and returns ENOPROTOOPT, which the send loop turned into a generic error, so the pump's typed downcast missed and every AU failed identically — a permanent freeze on precisely the shipping case, since AV1 is advertised only where hardware AV1 exists and hardware AV1 plus HDR is Main 10. The shape is now read from the sequence header before any byte reaches the decoder, exactly as the H.264 leg reads the active SPS. And the new Reconnecting phase was the first state that is not streaming, not connecting, and still holding a live stream — which opened all three guards that had made a second launch impossible. Pressing A assigned over `stream` where every other site shuts down first, and StreamState has no Drop, so the old pump was detached: a second live session still submitting to a Vulkan device that gets destroyed underneath it. Nothing about the reconnect was wrong in isolation; the defect lived between a new state and three guards nobody re-examined. Start is now defensive and the retry raises the connecting modal, so the UI matches the state and B can cancel. Also closed: retry_caps was computed, tested and never applied, so a shape refusal could end a session reporting no codec available while a working retry existed; the retry inherited force_software sticky-true, landing an HEVC→H.264 fallback on software H.264 with working hardware H.264; it re-dialled with a stale mode; the CPU present arm had no survivable-failure handling where the pyrowave arm — same pass — has it; HEVC is no longer advertised when the decoder is pinned to software; and the software rung now feeds the recovery-point SEI it already had in hand to the re-anchor gate. ⚠ Two host-side gaps found while tracing, neither in scope here: Hello::launch is NOT idempotent (gog:/custom: targets spawn a second copy on a retry; the field is kept verbatim because dropping it orphans the gamescope display whose reuse key includes the command), and a reconnected session can never adopt a game predating its own launch stamp, so it has no game-exit detection. ⚠ OWED: the on-glass software run. ~200 lines of new Vulkan on a path that only runs because the GPU already failed, and no driver has seen it. The review's minimum check is sync validation enabled, a non-multiple-of-16 mode, a mid-session resize and demotion, and both colour matrices. Gates: container clippy -D warnings over four crates, 236 tests, workspace check. pf-vkdecode and pf-bitstream are byte-for-byte untouched, so the hardware rungs' 250/250 stands.
50 lines
2.4 KiB
Bash
Executable File
50 lines
2.4 KiB
Bash
Executable File
#!/bin/sh
|
|
# Regenerate the software rung's colour fixtures (`video_software.rs`'s M8 exit test).
|
|
#
|
|
# Three single-IDR H.264 streams of the same NINE colour bars, whose VUIs differ ONLY in
|
|
# matrix coefficients and range. That is the point: the pictures are DIFFERENT code points
|
|
# that must converge on the SAME RGB once the signalled matrix and range are honoured —
|
|
# which is what makes the test able to fail against a hardcoded matrix (the swscale BT.601
|
|
# default the old libav rung needed correction code for).
|
|
#
|
|
# ⚠ The NINTH bar (192,128,64) is load-bearing and must not be dropped for tidiness. The
|
|
# eight before it are fully saturated primaries/secondaries plus black and white, and on
|
|
# THOSE a limited↔full range mistake only pushes values outside [0,1] — where the shader
|
|
# clamps — so the whole fixture set decodes with max error 0 under the WRONG range and the
|
|
# range axis could not fail. Measured on this fixture: (192,128,64) gives max error 13
|
|
# under the wrong range, while a 50% grey gives only 3, which is inside the test's ±4
|
|
# tolerance. So it has to be a non-neutral mid-tone, not just a mid-tone.
|
|
#
|
|
# Not lossless: x264 refuses qp 0 outside High 4:4:4 Predictive, which openh264 cannot
|
|
# decode. qp 1 over flat bars is exact to within a code point or two at the bar centres
|
|
# the test samples, and the test's tolerance is ±4.
|
|
#
|
|
# Needs: ffmpeg with libx264. Run from this directory; overwrites the three fixtures.
|
|
set -e
|
|
|
|
python3 - <<'PY'
|
|
BARS = [(255,255,255),(255,255,0),(0,255,255),(0,255,0),(255,0,255),(255,0,0),(0,0,255),(0,0,0),
|
|
(192,128,64)]
|
|
W, H = 32 * len(BARS), 64
|
|
row = bytearray()
|
|
for x in range(W):
|
|
row += bytes(BARS[x // 32])
|
|
open('bars.rgb', 'wb').write(bytes(row) * H)
|
|
print(f'{W}x{H}')
|
|
PY
|
|
|
|
# 288x64: nine 32-px bars. Both dimensions stay macroblock-aligned (18x4), so there is no
|
|
# encoder padding for the crop to have to undo.
|
|
for spec in "601-limited bt470bg tv" "709-limited bt709 tv" "709-full bt709 pc"; do
|
|
set -- $spec
|
|
name=$1; mtx=$2; rng=$3
|
|
ffmpeg -y -hide_banner -loglevel error -f rawvideo -pix_fmt rgb24 -s 288x64 -i bars.rgb \
|
|
-vf "scale=in_range=full:out_color_matrix=$mtx:out_range=$rng,format=yuv420p" \
|
|
-frames:v 1 -c:v libx264 -qp 1 -profile:v high \
|
|
-x264-params "keyint=1:no-scenecut=1:colorprim=bt709:transfer=bt709:colormatrix=$mtx" \
|
|
-color_primaries bt709 -color_trc bt709 -colorspace "$mtx" -color_range "$rng" \
|
|
-f h264 "bars-$name.h264"
|
|
done
|
|
rm -f bars.rgb
|
|
ls -l bars-*.h264
|