Files
punktfunk/crates/pf-client-core/Cargo.toml
T
enricobuehler 5c05246098 feat: M10 — FFmpeg is gone from the client
cargo tree -p punktfunk-client-session finds no ffmpeg. The host still does,
which is the whole point: pf-encode keeps libavcodec unconditionally and no
host workflow, packaging script or licence file was touched.

Deleted: crates/pf-ffvk, video_vulkan.rs, video_vaapi.rs, video_libav.rs, the
libavcodec half of video_d3d11.rs, the av_log machinery, ffmpeg::codec::Id as
the decoder's vocabulary (the quic CODEC_* wire constants now serve, which is
why the evidence table was keyed on them), DecodedImage::VkFrame and ::Dmabuf,
the presenter's AVVkFrame lane, and the ffmpeg-fallback feature with
everything behind it. DrmFrameGuard collapses from an enum to a newtype, which
removes an unsafe impl Send. Roughly 25,000 lines.

Then the CI, packaging, licensing and docs work the plan's §6 lists: the
Windows workflows lose FFMPEG_DIR, PF_FFVK_VULKAN_INCLUDE and their PATH
prepend; the MSIX loses its DLL wildcard; the client .deb stops emitting libav
sonames on its own because depends come from dpkg-shlibdeps; arch, flatpak and
nix drop the dependency; and the README's "FFmpeg 7 or 8" contract narrows to
the host.

Three defects reached users' machines in the first cut, and none was in the
deletion itself.

All three desktop Settings UIs offer vulkan, vaapi and d3d11va as stored
decoder values, so those strings sit in shipped settings files today. Refusing
them by name — which is the correct rule for a stale pin — would have bricked
every upgraded client whose owner ever touched that dropdown. They now migrate
onto the native rung for the same hardware family, at decoder construction AND
at each dialog's lookup, because a legacy value that matches no preset
displays as "Automatic" and silently rewrites the user's preference on the
next save.

M9's evidence filter was deleted on the argument that with no libavcodec twin
below, barring an unproven rung removes hardware decode rather than moving
down one rung. That is true on Windows and false on Linux for Intel and every
unknown vendor id, where prefer_vulkan_first is false and the order is
native-vaapi → native-vk: a rung that has decoded nothing anywhere sitting
above one that is 250/250 on three drivers. Every Intel Linux desktop would
have moved from libavcodec VAAPI, shipping for years, onto pf-vaadec by
default — and a rung that constructs and then produces wrong pixels leaves
only by the error-streak demotion, which this codebase already documents as
not tripping on the B580's strobing. The filter is restored as a narrow, pure,
testable rule: an unproven rung yields to a proven one, and to nothing else.
Windows deliberately passes no rung below, because that vendor family is the
one with a measured wrong-pixel report against Vulkan decode, and trading no
evidence for evidence of corruption is the wrong direction.

And the notices still said FFmpeg was bundled. The root file is what both
desktop clients include_str! and what the MSIX ships, three lines under the
new card saying no FFmpeg is bundled; Apple's Acknowledgements said it too, on
iOS, tvOS and macOS. The generator now emits four per-client files scoped by
transitive closure — 0 FFmpeg mentions in each, verified — while the root file
keeps it for the host. That also ends the standing false attribution of
ffmpeg-next, GTK4, windows-rs and the NVENC SDK to an iPhone.

Windows has no reachable box, so it was compiled instead: a cross clippy at
-D warnings on x86_64 and aarch64-pc-windows-msvc with the C toolchain stubbed
so build scripts run without linking. That gate immediately caught an
include_str! path one directory too deep, which nothing else could have.

Gates: container clippy -D warnings, 160 tests, workspace check, both Windows
targets clean, client ffmpeg count 0 and host 2. The four decode crates are
untouched, so the hardware rungs' 250/250 stands.

⚠ Owed and unrun: no GPU has executed any of this milestone. M8's on-glass
software check, M7's D3D11 and VAAPI AV1 hardware legs, and M9's field bake
all still want hardware, and the bake window and criteria remain the user's.
2026-08-07 08:58:47 +02:00

184 lines
11 KiB
TOML

[package]
name = "pf-client-core"
description = "Shared client plumbing (Linux + Windows) — session pump, native video decode, PipeWire/WASAPI audio, SDL3 gamepads, trust store, discovery — extracted from the GTK client so the shells and the Vulkan session binary build on one implementation"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
# Linux + Windows: the Vulkan session client builds on both; `cargo build --workspace`
# stays green on macOS (the Mac client lives in clients/apple) — there this crate is
# `wol` plus stubs-free emptiness. `wol` is pure std and stays cross-platform, matching
# the old main.rs. Audio is the one per-OS swap: PipeWire on Linux, WASAPI on Windows
# (same public surface — see lib.rs).
[target.'cfg(any(target_os = "linux", windows))'.dependencies]
punktfunk-core = { path = "../punktfunk-core", features = ["quic"] }
# Native Vulkan Video decode (WP-C of the native-decode program, HEVC added by M3
# WP-2, AV1 by M7): auto's TOP rung on both desktop OSes since M9 — for every codec it
# speaks, AV1 included — also pinnable via `PUNKTFUNK_DECODER=native-vulkan` —
# video_vk_native.rs, running pf-vkdecode's VkH264Decoder/VkH265Decoder/VkAv1Decoder on
# the presenter's shared device.
pf-vkdecode = { path = "../pf-vkdecode" }
# The one bitstream parser (M1): the SOFTWARE rung reads its per-picture colour
# signalling, IDR flag and recovery-point SEI from the same `AuPlan` every hardware rung
# already submits from (`video_software.rs`). That is what makes the swscale BT.601
# default unrepresentable rather than merely fixed — there is no second colour source
# left to disagree with.
pf-bitstream = { path = "../pf-bitstream" }
async-channel = "2"
# M8's software rung, the ladder's last one — no FFmpeg in either half.
#
# H.264: openh264 (BSD-2), already a workspace dependency (the HOST's GPU-less encoder,
# `pf-encode/src/enc/sw.rs`), so the licence posture and the bundled-source build are
# both already settled and already compiled by every `--workspace` leg.
#
# AV1: rav1d (BSD-2) — dav1d itself, ported to Rust by the ISRG/Prossimo memory-safety
# project. The plan of record names "dav1d"; the `dav1d` crate reaches it through
# `dav1d-sys`, which is `system-deps`-only (no vendored build): it needs `dav1d.pc` +
# headers at build time and `libdav1d.so`/`dav1d.dll` at run time on EVERY client
# package. That is a new system codec dependency added by the milestone family whose
# §6 excision checklist exists to delete exactly those. rav1d is the same decoder with
# none of that: pure Rust, no linker, nothing new in any package.
#
# ⚠ Both of these are NEW COMPILE COST on the client packaging legs, which is easy to
# miss because the workspace already built openh264: every client leg is `-p`-scoped and
# excludes pf-encode (flatpak's `cargo build -p punktfunk-client-linux -p
# punktfunk-client-session -p punktfunk-cli`, windows.yml/windows-msix.yml's
# `-p punktfunk-client-windows …`, deb.yml's client job, packaging/nix's
# `punktfunk-client`), so all of them compile the bundled OpenH264 tree for the FIRST
# time here. Only the `--workspace` CI legs and the host packages built it before.
#
# `default-features = false` drops two things deliberately:
# * `asm` — rav1d's hand-written assembly needs `nasm` at build time, and it is NOT the
# same trade openh264 makes next to it: openh264-sys2's `try_compile_nasm` returns
# quietly when nasm is missing ("Failed to compile NASM files, not using any
# assembly") and the C build still succeeds, whereas rav1d's build.rs PANICS ("NASM
# build failed. Make sure you have nasm installed or disable the \"asm\" feature").
# So turning `asm` on makes nasm a hard build requirement of every client package,
# and `ci/rust-ci.Dockerfile` — the container the client .deb and the workspace CI
# build in — does not have it (arch, rpm, nix and the FFmpeg-building noble image
# all do; the flatpak GNOME SDK and the Windows runner are not provisioned by
# anything in this tree). Making the rung that only ever runs BECAUSE the GPU
# already failed a build-breaker for the legs that ship it is the wrong way round.
# Turn it back on the day every client leg provisions nasm — and expect a large
# speedup when you do; this is dav1d's asm, and the Rust fallbacks are much slower.
# * `bitdepth_16` — the CPU rung is 8-bit by contract (`video_software.rs` refuses
# anything else rather than mis-scaling it), so building the 10/12-bit half would be
# compiling a path the code refuses to take.
#
# One packaging risk this DOESN'T carry: rav1d exports dav1d's C ABI as `#[no_mangle]`
# symbols (`dav1d_open`, `dav1d_send_data`, …), which could in principle interpose on a
# real libdav1d loaded into the same process. It cannot here — these are Rust `staticlib`
# symbols in an executable with no `-rdynamic` and no dynamic export table entry, so the
# loader never offers them to anyone. That changes if pf-client-core ever becomes a
# `cdylib` or a leg adds `-rdynamic`/`--export-dynamic`; re-check it then.
openh264 = "0.9"
rav1d = { version = "1", default-features = false, features = ["bitdepth_8"] }
# errno names for rav1d's negated-`c_int` returns (`video_software.rs`): `ENOPROTOOPT` —
# the code a `bitdepth_8`-only build answers a 10-bit stream with — is 92 on Linux and
# 123 on Windows, and rav1d re-exports only `Dav1dResult`, so the typed enum that would
# otherwise name it is out of reach. Already in the tree (rav1d's own dependency).
libc = "0.2"
# Opus for the audio planes. The VIDEO side has no FFmpeg at all since M10: every decode
# rung is native (pf-vkdecode / pf-dxvadec / pf-vaadec / openh264+rav1d) and the codec
# vocabulary is `punktfunk_core::quic`'s own `CODEC_*` wire bits. The HOST still encodes
# with libavcodec (`pf-encode`); nothing in this crate does.
opus = "0.3"
mdns-sd = "0.20"
# PyroWave decode (the opt-in wired-LAN wavelet codec, design/pyrowave-codec-plan.md
# §4.5) — pure Vulkan compute on the presenter's shared device, so it builds wherever the
# spawned Vulkan session presenter runs: Linux AND Windows (pyrowave-sys covers both; it
# is an empty stub elsewhere). `ash` only wraps the presenter's existing raw handles
# (same pinned version as pf-presenter).
pyrowave-sys = { path = "../pyrowave-sys", optional = true }
ash = { version = "0.38", optional = true }
# Game-library fetch from the host's management API over mTLS + fingerprint pinning.
# `ureq` is small + sync (the host uses it too) and its rustls unifies with the
# workspace's (quinn's) 0.23; the pinning verifier mirrors core's private `PinVerify`.
ureq = "2"
# Signed update-manifest fetch/verify + the install-kind ladder, shared with the host so one
# trust rule serves both (crates/pf-update-check).
pf-update-check = { path = "../pf-update-check" }
rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
anyhow = "1"
tracing = "0.1"
# Stable ids for profiles and host records (profiles.rs) — the OS RNG only, same version the
# workspace already resolves for punktfunk-core. No uuid crate: the v4 layout is four lines.
rand = "0.9"
# Gamepads: capture + feedback (full DualSense fidelity — touchpad/motion/triggers/LEDs
# need the hidapi driver). Linux links the system SDL3; Windows builds it from source
# (no system SDL3 there — same choice as clients/windows).
[target.'cfg(target_os = "linux")'.dependencies]
pipewire = "0.9"
sdl3 = { version = "0.18", features = ["hidapi"] }
# Native VAAPI decode (M6 of the native-decode program): the hand-declared libva buffer
# layouts, the profile/format/surface decisions, the AuPlan → picparams/IQ/slice
# conversion and the DRM-PRIME export descriptor that `video_vaapi_native` marshals.
# Cross-platform on purpose — everything decidable without a device is tested by the
# ordinary macOS and container gates, exactly as pf-dxvadec does for Windows.
pf-vaadec = { path = "../pf-vaadec" }
# libva itself is dlopen'd, never linked (see `video_vaapi_native`'s module docs): the
# container can then compile and clippy the whole rung without `libva-dev`, and a machine
# without a VAAPI runtime gets a clean refusal instead of a packaging dependency.
libloading = "0.8"
[target.'cfg(windows)'.dependencies]
wasapi = "0.23"
# Native D3D11VA decode (M5 of the native-decode program): the hand-declared DXVA buffer
# layouts and the AuPlan → picparams/qmatrix/slice-control conversion that video_d3d11_native
# submits. Windows-only because the rung is; the crate itself is cross-platform CPU code so
# its tests run on every CI leg (which is the point — `cfg(windows)` code cannot be tested by
# the Linux or macOS gates at all).
pf-dxvadec = { path = "../pf-dxvadec" }
# Pad-audio correlation (pad_audio.rs): the HID devnode's ContainerID and a render endpoint's
# stamped PKEY_Device_ContainerId both live in the registry — read-only, which sidesteps COM
# property stores entirely (the same version the host pins).
winreg = "0.56"
sdl3 = { version = "0.18", features = ["hidapi", "build-from-source"] }
# D3D11 decode-device plumbing (video_d3d11.rs): device/adapter selection, DXVA probes, and
# the shared NT-handle hand-off ring `video_d3d11_native` fills. Same pinned rev as
# clients/windows so the workspace builds ONE windows-rs.
windows = { git = "https://github.com/microsoft/windows-rs", rev = "acb5a1a7441033d9312b16842af02eb0c2b403dc", features = [
# Features are header-named since windows-rs generates from the SDK headers directly
# (#4689) — one feature per header, replacing the old `Win32_*` namespace features.
"d3d11",
"d3dcommon",
"dxgi",
"handleapi",
# RECT/HMONITOR for DXGI_OUTPUT_DESC1 (the display-HDR volume query).
"windef",
# IDXGIResource1::CreateSharedHandle takes an optional SECURITY_ATTRIBUTES.
"minwinbase",
# The GlobalAlloc block the clipboard takes ownership of (clipboard.rs).
"winbase",
# The OS-clipboard bridge (clipboard.rs): Open/Get/SetClipboardData + the sequence
# number — all in winuser now.
"winuser",
] }
[target.'cfg(windows)'.dev-dependencies]
# The native D3D11VA rung's frame-hash parity test compares decoded surfaces against the
# libavcodec goldens M5 captured — the same SHA-256 list, and the same crate, pf-vkdecode's
# Vulkan parity legs use (already in the workspace lock). The goldens are checked-in
# hashes; nothing links FFmpeg to read them.
sha2 = "0.10"
[features]
# PyroWave client decode ships in every default build (flatpak included; pyrowave-sys is a
# vendored in-repo tree, offline-safe, and an empty stub off Linux/Windows). The codec is
# still strictly per-session opt-in (Settings codec pick / PUNKTFUNK_PREFER_PYROWAVE=1).
default = ["pyrowave"]
pyrowave = ["dep:pyrowave-sys", "dep:ash"]
[lints]
workspace = true