From 99a1d1bed62bab0c135ef6e2ddc1fcab299073a4 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 19 Jul 2026 11:17:15 +0200 Subject: [PATCH] fix(pf-capture): don't require a libspa that exports SPA_VIDEO_TRANSFER_SMPTE2084 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GNOME 50 HDR format offer took the PQ transfer id straight from pw::spa::sys, which only exists on libspa new enough to carry the BT2020_10/SMPTE2084/ARIB_STD_B67 block. Ubuntu 24.04 (noble) — the .deb host builder — ships older headers, so bindgen emitted no such constant and the host failed to compile there: error[E0425]: cannot find value `SPA_VIDEO_TRANSFER_SMPTE2084` in crate `pw::spa::sys` This never showed up locally or on the Linux CI: both run a current PipeWire, where the binding is present. It broke deb.yml's build-publish-host job, so v0.14.0 published its client .debs but no host .deb. Spell the id out (14) instead. It's wire ABI, not a private detail — SPA mirrors GStreamer's GstVideoTransferFunction and that block was added as a unit, so the value is the same on every libspa that has the symbol. On one that doesn't, PipeWire fails to intersect the offer and the session negotiates SDR, which is what an HDR-incapable host should do anyway (the path needs GNOME 50+ regardless). A test pins our value against pw::spa::sys wherever the symbol exists, so a renumbered enum fails loudly instead of silently mis-tagging the transfer function. It only builds where tests are compiled — the .deb/.rpm builders run plain `cargo build`, so it can't reintroduce the failure it guards. Co-Authored-By: Claude Opus 4.8 --- crates/pf-capture/src/linux/mod.rs | 37 +++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/crates/pf-capture/src/linux/mod.rs b/crates/pf-capture/src/linux/mod.rs index 98a7af27..e4c72288 100644 --- a/crates/pf-capture/src/linux/mod.rs +++ b/crates/pf-capture/src/linux/mod.rs @@ -1058,6 +1058,19 @@ mod pipewire { /// depth — so tiled modifiers are deliberately NOT advertised (a zero-copy 10-bit de-tile is /// the follow-up). SHM is excluded entirely: Mutter's SHM record path paints 8-bit ARGB32 /// regardless of the negotiated format. + /// `SPA_VIDEO_TRANSFER_SMPTE2084` (PQ) — spelled out rather than taken from `pw::spa::sys` + /// because libspa only grew the constant with the BT2020_10/SMPTE2084/ARIB_STD_B67 block, and + /// the distro builders (Ubuntu 24.04 noble for the .deb) ship headers predating it — bindgen + /// then emits no such constant and the host fails to compile there, even though the code never + /// runs on those systems (the HDR path needs GNOME 50+). + /// + /// 14 is the enum's position in `spa/param/video/color.h` and is wire ABI, not a private + /// detail: SPA mirrors GStreamer's `GstVideoTransferFunction`, where that block was added + /// together, so the value is identical on every libspa that has the symbol at all. On one that + /// doesn't, PipeWire simply fails to intersect this format offer and the session negotiates + /// SDR — the same outcome as not offering HDR. + const SPA_VIDEO_TRANSFER_SMPTE2084: u32 = 14; + fn build_hdr_dmabuf_format( format: VideoFormat, preferred: Option<(u32, u32, u32)>, @@ -1106,9 +1119,7 @@ mod pipewire { obj.properties.push(pw::spa::pod::Property { key: pw::spa::sys::SPA_FORMAT_VIDEO_transferFunction, flags: pw::spa::pod::PropertyFlags::MANDATORY, - value: pw::spa::pod::Value::Id(pw::spa::utils::Id( - pw::spa::sys::SPA_VIDEO_TRANSFER_SMPTE2084, - )), + value: pw::spa::pod::Value::Id(pw::spa::utils::Id(SPA_VIDEO_TRANSFER_SMPTE2084)), }); obj.properties.push(pw::spa::pod::Property { key: pw::spa::sys::SPA_FORMAT_VIDEO_colorPrimaries, @@ -2398,4 +2409,24 @@ mod pipewire { mainloop.run(); Ok(()) } + + #[cfg(test)] + mod tests { + /// Pin our hand-written PQ transfer id against the real libspa binding. We can't take the + /// constant from `pw::spa::sys` directly (older distro headers don't export it — see + /// [`super::SPA_VIDEO_TRANSFER_SMPTE2084`]), so assert the two agree wherever the symbol + /// DOES exist. Any libspa that renumbers the enum fails this instead of silently tagging + /// the HDR offer with the wrong transfer function. + /// + /// Only builds where tests are compiled — the .deb/.rpm builders run plain `cargo build`, + /// so this never reintroduces the compile failure it exists to prevent. + #[test] + fn pq_transfer_id_matches_libspa() { + assert_eq!( + super::SPA_VIDEO_TRANSFER_SMPTE2084, + super::pw::spa::sys::SPA_VIDEO_TRANSFER_SMPTE2084, + "libspa renumbered spa_video_transfer_function — update the hardcoded PQ id" + ); + } + } }