Skip to content

feat(moq-video)!: make hardware encoders always-on (openh264 stays the software fallback)#1819

Merged
kixelated merged 27 commits into
devfrom
claude/loving-dubinsky-32ccb0
Jun 21, 2026
Merged

feat(moq-video)!: make hardware encoders always-on (openh264 stays the software fallback)#1819
kixelated merged 27 commits into
devfrom
claude/loving-dubinsky-32ccb0

Conversation

@kixelated

@kixelated kixelated commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Hardware encoders become always-on across all platforms, while openh264 remains the always-compiled software fallback so a GPU-less box still encodes.

  • NVENC + VAAPI are now always-on for Linux (cfg-gated, no longer behind opt-in nvenc/vaapi features), matching how VideoToolbox (macOS) and Media Foundation (Windows) already worked. Both still dlopen their drivers at runtime, so a binary links on a GPU-less builder and runs on a machine with no GPU.
  • openh264 stays the always-on software fallback. Kind::Auto prefers a hardware encoder and falls back to openh264 when none is usable; Kind::Software / Kind::Named("openh264") always work. (No software feature: I don't want a build that can't encode at all.)
  • NVENC no longer aborts on a driver-less host. cudarc and the NVENC SDK panic (process-abort under release panic = "abort") when their library can't be dlopen'd, so always-on NVENC would crash Kind::Auto on every GPU-less Linux box. Nvenc::open now probes libcuda + libnvidia-encode with libloading first and returns Err, so backend::open falls back to openh264. Verified GPU-less in a Linux container.
  • publish = false removed from moq-video (the remaining functional publish blocker is the nvidia fork, see below).

Consumers

  • moq-boy uses Kind::Software directly (its 160x144 Game Boy frames are small enough that hardware encoders may reject them); openh264 being always-on means no special feature wiring.
  • moq-cli keeps --hardware (force hardware, error if none) and --software (force openh264).

NVENC plumbing

NVENC's always-on build depends on the dynamic-loading feature of nvidia-video-codec-sdk, consumed via the existing [patch.crates-io] fork branch (reviewed/hardened: per-OS library resolution, no default-build cudarc regression, MSRV-safe libloading 0.8). Consumed with default-features = false so cuda-version-from-build-system stays off and the CUDA version is pinned via cudarc's cuda-12020 (no CUDA toolkit needed to build).

Public API changes (breaking)

  • moq-video features nvenc and vaapi are removed; those backends are unconditional on Linux now.
  • moq_video::encode::Kind::Auto now tries the platform hardware encoders before openh264 (on Linux it previously needed the nvenc/vaapi features to try them at all).
  • No behavior change for openh264 / Kind::Software / moq-cli --software vs the pre-PR baseline (openh264 stays always-on).

Per the branch-targeting rules this is a breaking change to a library crate, hence targeting dev.

Test plan

  • macOS: cargo check / clippy / fmt clean for moq-video, moq-cli --features capture, moq-boy; cargo test -p moq-video (10 tests, incl. the openh264 software paths).
  • Linux (podman, GPU-less): cargo clippy -p moq-video --all-targets -- -D warnings clean and cargo test -p moq-video --locked (8 tests) pass — including software_encoder_emits_annexb (openh264 always compiled) and missing_driver_errors_instead_of_panicking (NVENC falls back, no abort).
  • Real hardware NVENC/VAAPI encode still unverified (no GPU box); only graceful-fallback and synthetic-frame software paths are exercised.

Cross-package sync

Docs updated: doc/bin/cli.md, rs/moq-video/DESIGN-native-codecs.md, and in-crate doc comments (lib, frame, captures, encoder).

(Written by Claude)

moq-bot Bot and others added 19 commits June 17, 2026 21:15
Co-authored-by: moq-bot[bot] <186640430+moq-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Luke Curley <kixelated@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…7.3 (#1790)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…1792)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: moq-bot[bot] <186640430+moq-bot[bot]@users.noreply.github.com>
… aarch64-linux (#1793)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#1806)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bring main's recent fixes onto dev. Most of main's commits since the last
sync were already present on dev (latency-range playback, relay
credential-expiry close, moq_json command routing, peer_identity), so the
net new content is:

- CI: adopt main's crane-based Rust checks (clippy/doc/test via `nix flake
  check`), replacing dev's per-runner CARGO_TARGET_DIR scheme (#1801).
- moq-native: combine main's session-flap backoff (#1806) with dev's
  reconnect session-state tracking.

Conflicts resolved in favor of dev's newer moq-net API and input/output
signal structure; main's overlapping changes were the same features in the
older shape. Removed a duplicate PeerIdentity block that auto-merge
concatenated in tls.rs. Regenerated Cargo.lock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware encoders are now always-on and the only ones in a default build:
VideoToolbox (macOS), Media Foundation (Windows), and NVENC + VAAPI (Linux,
previously behind opt-in `nvenc`/`vaapi` features). The openh264 software
encoder moves behind a new opt-in `software` feature (off by default), so a
GPU-less box without it gets `NoEncoder` rather than silently falling back to
software.

- moq-video: drop the `nvenc`/`vaapi` features and cfg-gate NVENC/VAAPI on
  Linux; add `software = ["dep:openh264"]`; `Kind::Auto` no longer falls back
  to software unless the feature is on. Remove `publish = false`.
- NVENC: consume nvidia-video-codec-sdk with default-features off so the crate's
  `cuda-version-from-build-system` default stays off; we pin the CUDA version via
  cudarc's `cuda-12020`. Repin the patched fork to the reviewed dynamic-loading
  commit.
- moq-boy: enable the `software` feature (its 160x144 frames are too small for
  some hardware encoders).
- moq-cli: drop the `--software` flag; capture builds are hardware-only.
- Docs/comments updated (lib, frame, captures, DESIGN, cli.md, flake/overlay).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated enabled auto-merge (squash) June 20, 2026 00:27
kixelated and others added 4 commits June 19, 2026 17:59
`cargo sort --check` (just ci) requires alphabetical order within each
dependency table; the new Linux target deps weren't sorted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ting

Making hardware encoders always-on means Kind::Auto (the default) tries NVENC on
every Linux build. cudarc and the NVENC SDK dlopen their driver libraries lazily
and panic (which aborts the process under release's `panic = "abort"`) when a
library is absent, so a GPU-less Linux box would crash in CudaContext::new
instead of falling back to the next encoder, contrary to this PR's own claim.

Probe libcuda and libnvidia-encode with libloading before touching either crate
and return Error::Codec when missing, so backend::open moves on. Adds a Linux
test asserting open() errors rather than panics when the driver is absent.
Verified GPU-less in podman (cargo test -p moq-video --all-features).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Making hardware encoders always-on is the right call, but gating openh264 behind
an opt-in `software` feature meant a GPU-less box got NoEncoder by default, and
Kind::Software / `--software` stopped working without it. Keep hardware always-on
but restore openh264 as the always-compiled fallback.

- Drop the `software` feature; openh264 is a non-optional dependency again.
- backend::open always registers the openh264 SOFTWARE candidate, so Kind::Auto
  falls back to it and Kind::Software always opens.
- Remove the now-unnecessary `feature = "software"` cfgs (the surface-download
  path in frame.rs is live again; the software encoder tests run again).
- moq-cli regains `--software`; moq-boy drops the (now nonexistent) feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated changed the title feat(moq-video)!: make hardware encoders the default, openh264 opt-in feat(moq-video)!: make hardware encoders always-on (openh264 stays the software fallback) Jun 20, 2026
kixelated and others added 3 commits June 19, 2026 21:59
…-32ccb0

Brings the branch up to date with dev (HEVC #1802, native H.264 decode #1796,
async device capture #1807, srt/rtmp/rtc egress) and keeps this PR's deltas:
NVENC/VAAPI always-on for Linux, openh264 always-on (no `software` feature),
publish=false removed, the nvidia-video-codec-sdk fork repinned to the hardened
dynamic-loading commit (default-features off), and the NVIDIA-probe fallback.

Note: restores dev's H.265/HEVC codec-aware encode path (Codec enum, codec-aware
backend selection, hev1 producer) that the previous branch merge had dropped by
taking "ours" wholesale. Verified: clippy -D clean, 19 moq-video tests pass
(incl. H.265 roundtrips), sort/taplo/fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated merged commit e3664b8 into dev Jun 21, 2026
1 check passed
@kixelated kixelated deleted the claude/loving-dubinsky-32ccb0 branch June 21, 2026 03:05
kixelated pushed a commit that referenced this pull request Jun 21, 2026
dev advanced 3 commits while this PR was open (#1845 PTS-exposing TS Export +
PCR-paced SRT egress, #1847 moq-lite-05 wire sync, #1819 always-on hardware
encoders). Re-merged dev and reconciled two conflicts:

- nix/overlay.nix: kept this PR's cargo+sccache CI direction (dev's tip still
  carries the crane `moqChecks`; the cargo switch lives on main, #1821).
- rs/moq-mux/src/container/ts/export.rs: combined dev's #1845 Frame-returning
  `Export::next` (PTS/keyframe-stamped) with this PR's generic `catalog::Catalog`
  trait (main's #1815 mpegts rename). Updated the moq-cli drain helper to read
  `frame.payload` and refreshed two stale `scte35::Ext` comments.

Verified: moq-mux (279), moq-cli, moq-srt tests pass; workspace clippy -D
warnings and fmt clean (excluding the crates that need libva/gstreamer system
libs unavailable in this sandbox: moq-video/libmoq/moq-boy/moq-gst); JS
type-checks and biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BQ9o9paZnRLpYRgbyjUwFV
@kixelated kixelated mentioned this pull request Jun 21, 2026
kixelated added a commit that referenced this pull request Jun 21, 2026
#1819 made the NVENC/VAAPI hardware encoders always-on for Linux, which also
made libva a hard runtime dependency of every Linux moq-video binary
(moq-vaapi 0.0.2 links libva: NEEDED libva.so.2 / libva-drm.so.2). Give
self-compilers a way to drop the CUDA / libva deps without changing the
default.

moq-video: reintroduce `nvenc` and `vaapi` features (the Linux deps become
optional), both in `default`, gating the backend modules + candidates with
`#[cfg(all(target_os = "linux", feature = ...))]`. Default builds are
unchanged; `--no-default-features` (or dropping one feature) builds without
the corresponding dep. openh264 stays the always-compiled software fallback
and V4L2 capture is unaffected.

Consumers: the workspace moq-video dep is now `default-features = false`
(mirroring moq-native), so each binary opts in. libmoq and moq-boy enable
both encoders; moq-cli exposes default-on `nvenc`/`vaapi` passthroughs so a
`capture` build can drop them:
  cargo build -p moq-cli --no-default-features --features "iroh quinn websocket capture"

Verified: macOS builds all affected crates (features are no-ops off Linux);
a Linux container compiles `moq-video --no-default-features` WITHOUT libva-dev
and the default (nvenc+vaapi) WITH it; `cargo tree` confirms the feature
resolution for every consumer scenario.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants