From 0b1a608d20249951887d319acae48aa1b8d2dc3d Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 7 Nov 2026 08:15:18 -0800 Subject: [PATCH 1/4] chore(quest): claim quest/m1/vaapi-radeonsi.md Quest-Claim: 229e6d8775d21b03 From 2220cc3d293d6a799c7ab26625d3d77c79fe0628 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 7 Nov 2026 09:01:29 -0800 Subject: [PATCH 2/4] quest: radeonsi VA-API encode waits on the moq-vaapi release Co-Authored-By: Claude Opus 5.5 --- quest/m1/vaapi-radeonsi.md | 73 +++++++++++++++----------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/quest/m1/vaapi-radeonsi.md b/quest/m1/vaapi-radeonsi.md index 3762d34aaaa..ac1e2633ee4 100644 --- a/quest/m1/vaapi-radeonsi.md +++ b/quest/m1/vaapi-radeonsi.md @@ -1,56 +1,41 @@ -# [M] VA-API encode is correct on radeonsi +# [S] VA-API encode is correct on radeonsi ## Goal -On an AMD RX 9070 (radeonsi), moq-video's VA-API H.264 encoder either -produces a stream that ffmpeg decodes, or refuses the node, so `Kind::Auto` -falls to the next H.264 encoder (OpenH264 in a build that has it; a build -without one gets `NoEncoder` naming the refused driver). Its VPP NV12 conversion carries no chroma offset, and its -rate control stays near the target bitrate. The ignored VA-API encode tests -in `rs/moq-video/src/encode/backend/vaapi.rs` pass on that card with -`MOQ_VAAPI_DEVICE` naming its node, or skip with a reason that names the -refused driver. +On an AMD RX 9070 (radeonsi), moq-video's VA-API H.264 encoder produces a +stream that ffmpeg decodes, its VPP NV12 conversion matches the space it +labels, and its rate control stays near the target bitrate. The VA-API +tests in `rs/moq-video/src/encode/backend/vaapi.rs`, ignored ones included, +pass on that card with `MOQ_VAAPI_DEVICE` naming its node. ## Plan -Found 2026-11-06 in [moq-dev/moq#8013](https://github.com/moq-dev/moq/pull/8013)'s -hardware run on an RX 9070 (Mesa 26.0.8, `renderD129`): 6 of 19 VA-API tests -failed, all of them H.264 encode. A 320x240 dump gives ffprobe -`Invalid data found when processing input`, and its first NAL unit has type -0. This also reproduces on main's moq-vaapi. H.265 encode and both decoders -pass there. [moq-dev/vaapi#10](https://github.com/moq-dev/vaapi/pull/10) -also noted a chroma offset in radeonsi's VPP NV12 output and a bitrate -overshoot. - -Decided 2026-11-06 (maintainer, /quest-unblock): ✅ keep #8013 queued, which -puts `vaapi` on by default in moq-cli and moq-transcode, and fix this in m1. -Until it lands, an AMD-only host encodes H.264 through VA-API and publishes -a stream nobody can decode; moq-c and moq-ffi already did. Not chosen: -pulling #8013 to refuse radeonsi first, or keeping `vaapi` opt-in. Also -decided: ✅ find the root cause in m1. Not chosen: m3 beside -[Vulkan Video encode on AMD](/quest/m3/vulkan-encode.md), or only a note -there. - -- Find whether the H.264 bytes are ours. NAL type 0 at the start points at - how moq-vaapi reads the coded buffer (a segment's `bit_offset`, or more - than one segment) or at packed headers radeonsi does not take for H.264. - [moq-dev/vaapi#10](https://github.com/moq-dev/vaapi/pull/10) had to - require packed H.265 parameter sets for the same reason. Compare against - `ffmpeg -c:v h264_vaapi` on the same node. -- If it is moq-vaapi's, fix it there with a test, release the crate, and bump - `moq-vaapi` here. If it is the driver's, refuse a radeonsi node for H.264 - encode, using the driver's vendor string, so the candidate fails to open and - OpenH264 takes over. Then link the Mesa issue. -- Fix the chroma offset and the bitrate overshoot if they are ours. If the - chroma offset is the driver's VPP, skip VPP on radeonsi and convert to NV12 - before upload. If the overshoot is the driver's, refuse a radeonsi node for - that encode, as for the H.264 bytes, so `Kind::Auto` moves on. Link the - Mesa issue either way. -- Vulkan Video still replaces VA-API on AMD later; this quest does not wait - on it. +The causes were in moq-vaapi and are fixed in +[moq-dev/vaapi#13](https://github.com/moq-dev/vaapi/pull/13). With it patched +in, all 19 of moq-video's VA-API tests pass on the RX 9070 (`renderD129`, +Mesa 26.2.5); on moq-vaapi 0.2.0, 7 fail. That PR's body has the evidence. + +- H.264 bytes: radeonsi writes the packed SPS and PPS, and the slice's NAL + header, only from a packed slice header, which moq-vaapi did not send. +- Bitrate: moq-vaapi's QP ceiling of 36 set a smallest picture on both iHD + and radeonsi; it is now 51. +- Chroma: not an offset. Mesa's VPP reads the BT.601 standard as SMPTE 170M + primaries and gamut-maps; moq-vaapi now names each side explicitly on Mesa. + +What remains here: bump `moq-vaapi` in the root `Cargo.toml` to the release +with #13, and say in the module docs of +`rs/moq-video/src/encode/backend/vaapi.rs` that the tests pass on radeonsi. +Then delete this quest. Public API: none. Wire: none. +## Waiting + +- Maintainer: merge [moq-dev/vaapi#13](https://github.com/moq-dev/vaapi/pull/13) + and publish it as moq-vaapi 0.2.1 (a patch: no public API change). Version + bumps are a person's call, so an agent does not cut the release. Check that + `cargo search moq-vaapi` lists 0.2.1. + ## Related - [Vulkan Video encode on AMD](/quest/m3/vulkan-encode.md) - AMD's long-term encode path From 99690fdcfbc2befdffbc669bdb312ac8b48e75e8 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 7 Nov 2026 10:35:22 -0800 Subject: [PATCH 3/4] quest: index line states only the remaining radeonsi outcome Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quest/m1/README.md b/quest/m1/README.md index 90202de1b48..6cd43f06a36 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -51,7 +51,7 @@ moves what remains of them once their claims merge. - [Session policy lives in moq-net](/quest/m1/session-policy/README.md) - accept and connect deadlines, admission, window widening and reconnect live once in moq-net; moq-tokio and moq-relay's io_uring path call them - [Vendor and trim the WebRTC stack](/quest/m1/webrtc-vendor.md) - str0m, dimpl, `is`, and sctp-proto live in moq-webrtc with unused code removed, so moq-webrtc can take rind - [MoQ on rind](/quest/m1/rind/README.md) - every MoQ crate takes its crypto from rind, a pure-Rust graviola fork, so no build compiles C crypto -- [VA-API encode is correct on radeonsi](/quest/m1/vaapi-radeonsi.md) - AMD's VA-API H.264 encode decodes, or the node is refused for OpenH264 +- [VA-API encode is correct on radeonsi](/quest/m1/vaapi-radeonsi.md) - AMD's VA-API H.264 encode decodes, once moq-vaapi 0.2.1 ships - [Tests run on a mocked clock](/quest/m1/mock-clock-tests/README.md) - about 300 tests stop proving nothing happened by waiting, sleeping to settle, or asserting on elapsed time - [moq-mux reads H.265 SPS without scuffle](/quest/m1/h265-sps-reader.md) - moq-mux's own SPS reader replaces scuffle-h265 and scuffle-expgolomb, and the fuzz regressions still pass - [QMux reads the app-limited flag on big-endian Linux](/quest/m1/qmux-app-limited-endian.md) - the send-rate filter's app-limited mask follows the target's byte order From 973afeab521b1791dbb44d04de2c2bca804ccae1 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 7 Nov 2026 10:47:40 -0800 Subject: [PATCH 4/4] quest: radeonsi quest names the lockfile refresh and checks 0.2.1 directly Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 2 +- quest/m1/vaapi-radeonsi.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/quest/m1/README.md b/quest/m1/README.md index 6cd43f06a36..3520bfcac53 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -51,7 +51,7 @@ moves what remains of them once their claims merge. - [Session policy lives in moq-net](/quest/m1/session-policy/README.md) - accept and connect deadlines, admission, window widening and reconnect live once in moq-net; moq-tokio and moq-relay's io_uring path call them - [Vendor and trim the WebRTC stack](/quest/m1/webrtc-vendor.md) - str0m, dimpl, `is`, and sctp-proto live in moq-webrtc with unused code removed, so moq-webrtc can take rind - [MoQ on rind](/quest/m1/rind/README.md) - every MoQ crate takes its crypto from rind, a pure-Rust graviola fork, so no build compiles C crypto -- [VA-API encode is correct on radeonsi](/quest/m1/vaapi-radeonsi.md) - AMD's VA-API H.264 encode decodes, once moq-vaapi 0.2.1 ships +- [VA-API encode is correct on radeonsi](/quest/m1/vaapi-radeonsi.md) - AMD's VA-API H.264 encode decodes, once moq takes moq-vaapi 0.2.1 - [Tests run on a mocked clock](/quest/m1/mock-clock-tests/README.md) - about 300 tests stop proving nothing happened by waiting, sleeping to settle, or asserting on elapsed time - [moq-mux reads H.265 SPS without scuffle](/quest/m1/h265-sps-reader.md) - moq-mux's own SPS reader replaces scuffle-h265 and scuffle-expgolomb, and the fuzz regressions still pass - [QMux reads the app-limited flag on big-endian Linux](/quest/m1/qmux-app-limited-endian.md) - the send-rate filter's app-limited mask follows the target's byte order diff --git a/quest/m1/vaapi-radeonsi.md b/quest/m1/vaapi-radeonsi.md index ac1e2633ee4..b5cae63f4a8 100644 --- a/quest/m1/vaapi-radeonsi.md +++ b/quest/m1/vaapi-radeonsi.md @@ -23,7 +23,7 @@ Mesa 26.2.5); on moq-vaapi 0.2.0, 7 fail. That PR's body has the evidence. primaries and gamut-maps; moq-vaapi now names each side explicitly on Mesa. What remains here: bump `moq-vaapi` in the root `Cargo.toml` to the release -with #13, and say in the module docs of +with #13, refresh `Cargo.lock` with it, and say in the module docs of `rs/moq-video/src/encode/backend/vaapi.rs` that the tests pass on radeonsi. Then delete this quest. @@ -34,7 +34,7 @@ Public API: none. Wire: none. - Maintainer: merge [moq-dev/vaapi#13](https://github.com/moq-dev/vaapi/pull/13) and publish it as moq-vaapi 0.2.1 (a patch: no public API change). Version bumps are a person's call, so an agent does not cut the release. Check that - `cargo search moq-vaapi` lists 0.2.1. + `cargo info moq-vaapi@0.2.1` finds it. ## Related