feat(protocol,host): negotiate video codec + add a GPU-less software (openh264) encode path
Phase 1 of codec negotiation, and the Linux software H.264 encode path it unblocks. **Codec negotiation (core `quic`):** - `Hello.video_codecs` (bitfield: CODEC_H264/HEVC/AV1) — the client advertises what it can decode; appended as a trailing byte (older client → 0 = HEVC-only, back-compat). - `Welcome.codec` — the single codec the host resolved and will emit; trailing byte (older host → HEVC). - `resolve_codec(client, host_capable)` picks the shared codec (precedence HEVC > AV1 > H.264) or `None` → the host refuses honestly rather than sending an undecodable stream. - Roundtrip + back-compat tests; cbindgen exports the CODEC_* constants. **Software encoder (host):** - The openh264 `OpenH264Encoder` (was Windows-only) is now built on Linux too — it's platform-agnostic (consumes CPU RGB `CapturedFrame`s, statically-bundled openh264). `openh264` moved to the shared linux+windows Cargo target. - `PUNKTFUNK_ENCODER=software` selects it: `open_video` gains a `software` branch (H.264 only), and `session_plan::resolve_encoder` / `capture::gpu_encode` resolve `EncoderBackend::Software` → `output_format().gpu = false`, so the portal capturer delivers CPU RGB. Explicit-only (auto never picks it — a box with a dead driver still has /dev/nvidiactl and would mis-resolve NVENC). **Host codec resolution (`punktfunk1`):** - The native path no longer hardcodes HEVC: it resolves the codec from the client's advertised set ∩ the host's capability (`Codec::host_wire_caps`: software→H.264, else HEVC), threads it through `SessionPlan.codec`, and opens the encoder + validates reconfigures at that codec. A software host + HEVC-only client is refused with a clear error. - 4:4:4 is gated on HEVC (it's HEVC-only). **Probe:** advertises H264|HEVC|AV1 and logs the resolved codec. Validated on the GPU-less dev box: negotiation is live end-to-end (probe advertises 0x07 → host resolves H.264 → Welcome reports it → plan = Software/H264), and the openh264 unit test (CPU RGB → AnnexB IDR) now runs on Linux. Full capture→encode still needs a GPU on this box — every compositor screencast path (KWin GL, gamescope VK_EXT_physical_device_drm, wlroots EGL) requires one; software render (llvmpipe/pixman) can't be captured — so this box exercises negotiation + encoder, not live capture. The software path unblocks GPU-less-*encode* boxes that still have a display GPU. Phase 2 (clients advertising real codecs + decoding per Welcome.codec) is a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -231,6 +231,16 @@ fn now_ns() -> u64 {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Human name for the negotiated `Welcome::codec` (also the natural `--out` file extension). The
|
||||
/// bitstream is dumped verbatim, so an H.264 software-host session should be saved as `.h264`.
|
||||
fn codec_ext(codec: u8) -> &'static str {
|
||||
match codec {
|
||||
punktfunk_core::quic::CODEC_H264 => "h264",
|
||||
punktfunk_core::quic::CODEC_AV1 => "av1",
|
||||
_ => "h265",
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
@@ -411,6 +421,13 @@ async fn session(args: Args) -> Result<()> {
|
||||
// `--audio-channels` (default stereo); the probe multistream-decodes + validates the
|
||||
// host's frames to exercise the surround encode path headlessly.
|
||||
audio_channels: args.audio_channels,
|
||||
// The probe just dumps the bitstream (no decode), so it advertises every codec — HEVC
|
||||
// (the host default) AND H.264 (so it can drive a GPU-less software host,
|
||||
// `PUNKTFUNK_ENCODER=software`) AND AV1. The host picks one and reports it in
|
||||
// `Welcome::codec`; the dump extension follows that.
|
||||
video_codecs: punktfunk_core::quic::CODEC_H264
|
||||
| punktfunk_core::quic::CODEC_HEVC
|
||||
| punktfunk_core::quic::CODEC_AV1,
|
||||
}
|
||||
.encode(),
|
||||
)
|
||||
@@ -429,6 +446,7 @@ async fn session(args: Args) -> Result<()> {
|
||||
hdr = welcome.color.is_hdr(),
|
||||
chroma_444 = welcome.chroma_format == punktfunk_core::quic::CHROMA_IDC_444,
|
||||
chroma_format_idc = welcome.chroma_format,
|
||||
codec = codec_ext(welcome.codec),
|
||||
"session offer"
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user