From 333f66b45b46dcdf70285778f3ab026fa2ce965d Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 20 Jun 2026 11:52:17 +0000 Subject: [PATCH] fix(host/serverinfo): don't advertise an empty codec mask when the VAAPI probe finds nothing The Phase 3 GPU-aware codec mask (6922e1c) probes VAAPI on any non-NVIDIA host. On a GPU-less box (CI container: no /dev/nvidia* -> `auto` picks VAAPI, but there's no VA display) the probe returns all-false, so the mask was 0 -- the host advertised NO codecs, and the serverinfo unit test failed. Fall back to the static superset when the probe yields nothing (VAAPI wasn't usable, not "the GPU encodes nothing"); quiet ffmpeg's expected "No VA display" error during the probe; and assert the test against codec_mode_support() rather than a hardcoded 65793 so it's deterministic regardless of the build host's GPU. Co-Authored-By: Claude Opus 4.8 --- crates/punktfunk-host/src/encode/vaapi.rs | 16 ++++++++++++---- .../punktfunk-host/src/gamestream/serverinfo.rs | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/punktfunk-host/src/encode/vaapi.rs b/crates/punktfunk-host/src/encode/vaapi.rs index 18a593a..837d6eb 100644 --- a/crates/punktfunk-host/src/encode/vaapi.rs +++ b/crates/punktfunk-host/src/encode/vaapi.rs @@ -134,11 +134,19 @@ pub fn probe_can_encode(codec: Codec) -> bool { return false; } unsafe { - let hw = match VaapiHw::new(ffi::AVPixelFormat::AV_PIX_FMT_NV12, 640, 480, 2) { - Ok(hw) => hw, - Err(_) => return false, + // A missing VA device (non-VAAPI host, GPU-less CI) is an expected probe outcome — quiet + // ffmpeg's "No VA display found" error for the probe, then restore the level. + let prev = ffi::av_log_get_level(); + ffi::av_log_set_level(ffi::AV_LOG_FATAL); + let ok = match VaapiHw::new(ffi::AVPixelFormat::AV_PIX_FMT_NV12, 640, 480, 2) { + Ok(hw) => { + open_vaapi_encoder(codec, 640, 480, 30, 2_000_000, hw.device_ref, hw.frames_ref) + .is_ok() + } + Err(_) => false, }; - open_vaapi_encoder(codec, 640, 480, 30, 2_000_000, hw.device_ref, hw.frames_ref).is_ok() + ffi::av_log_set_level(prev); + ok } } diff --git a/crates/punktfunk-host/src/gamestream/serverinfo.rs b/crates/punktfunk-host/src/gamestream/serverinfo.rs index f90d4f4..b75f4f9 100644 --- a/crates/punktfunk-host/src/gamestream/serverinfo.rs +++ b/crates/punktfunk-host/src/gamestream/serverinfo.rs @@ -61,7 +61,13 @@ fn codec_mode_support() -> u32 { if caps.av1 { m |= SCM_AV1_MAIN8; } - return m; + // Only trust a probe that actually found an encoder. An empty result means VAAPI wasn't + // usable at probe time (no VA display — a GPU-less CI box, or a misconfigured host), NOT + // that the GPU encodes nothing; advertise the static superset (pre-probe behaviour) rather + // than claiming zero codecs. + if m != 0 { + return m; + } } SERVER_CODEC_MODE_SUPPORT } @@ -99,6 +105,13 @@ mod tests { https_port: 47984, }; let xml = serverinfo_xml(&host, false); - assert!(xml.contains("65793")); + // The mask is the GPU-aware value (NVENC/no-GPU → the static 65793; a VAAPI host → + // whatever it probes). Assert the XML embeds exactly what `codec_mode_support()` returns, + // so the test is deterministic regardless of the build host's GPU. + let mask = codec_mode_support(); + assert!(mask != 0, "must advertise at least one codec"); + assert!(xml.contains(&format!( + "{mask}" + ))); } }