Server-side transcoding for LVQR (Tier 4 item 4.6).
Generates an ABR ladder (720p / 480p / 240p by default) from a
single high-resolution source broadcast, with the output
renditions re-injected into the caller-supplied
[lvqr_fragment::FragmentBroadcasterRegistry] under
<source>/<rendition> broadcast names. Every egress surface
(LL-HLS, DASH, MoQ relay, archive) picks them up without
per-protocol wiring; the LL-HLS master playlist composer emits
one #EXT-X-STREAM-INF per rendition automatically.
What this crate ships
Always available (default features):
- [
Transcoder] trait + [TranscoderFactory] + [TranscoderContext] -- the "subscribe / drain / panic-isolate" shape generalised fromlvqr_agent::Agent. Each factory carries its own [RenditionSpec]. - [
TranscodeRunner] + [TranscodeRunnerHandle] -- registry-side installer + cheaply-cloneable handle, mirroringlvqr_agent::AgentRunner. - [
RenditionSpec] with width / height / bitrate fields, [RenditionSpec::preset_720p] /preset_480p/preset_240pconstructors, and [RenditionSpec::default_ladder]. - [
PassthroughTranscoder] -- in-memory observer that proves the registry-callback / drain / panic-isolation wiring; useful for tests and as a metrics tap. - [
AudioPassthroughTranscoder] -- copies<source>/1.mp4audio fragments verbatim into every rendition's audio track so each rendition broadcaster is a self-contained mp4 the LL-HLS bridge drains without special-casing the missing audio.
Behind the transcode feature (pulls gstreamer-rs 0.23 +
base/good/bad/ugly + gst-libav from the host):
- [
SoftwareTranscoder] / [SoftwareTranscoderFactory] -- theappsrc -> qtdemux -> h264parse -> avdec_h264 -> videoscale -> x264enc -> ... -> mp4mux -> appsinkladder, one worker thread per(source, rendition)pair, bounded mpsc. - [
AacToOpusEncoder] / [AacToOpusEncoderFactory] -- AAC -> Opus transcoder used bylvqr-whep(under itsaac-opusfeature) so AAC publishers reach Opus-negotiated WHEP subscribers.
Behind one of the hw-* features (each implies transcode):
hw-videotoolbox-- [VideoToolboxTranscoder] / [VideoToolboxTranscoderFactory] for macOS via Apple'svtenc_h264_hw(theapplemediaplugin from gst-plugins-bad).hw-nvenc-- [NvencTranscoder] / [NvencTranscoderFactory] for Linux + Nvidia GPUs vianvh264enc(thenvcodecplugin from gst-plugins-bad, driven by the CUDA runtime).hw-vaapi-- [VaapiTranscoder] / [VaapiTranscoderFactory] for Linux + Intel iGPU / AMD viavah264enc(the modernvaplugin from gst-plugins-bad, superseding the deprecatedvaapih264encfromgstreamer-vaapi).hw-qsv-- [QsvTranscoder] / [QsvTranscoderFactory] for Linux + Intel Quick Sync viaqsvh264enc(theqsvplugin from gst-plugins-bad, driving Intel Media SDK / oneVPL).
All four HW backends mirror SoftwareTranscoderFactory shape
verbatim -- same Transcoder trait, same lifecycle, same
<source>/<rendition> output broadcast naming, same bounded
mpsc + dedicated worker thread per (source, rendition) pair --
and only swap the GStreamer encoder element + property mapping.
HW-only path is intentional across all four: a factory that
silently falls back to CPU encoding under load defeats the point
of an operator-pickable hardware tier. Each factory's
is_available() probes the required encoder element at
construction and build() opts out cleanly with a warn log when
missing.
Future sessions may extract the shared scaffolding into a
dedicated pipeline.rs module (per the "three is the threshold
for an abstraction" rule). The current shape is intentional code
duplication: each backend stays readable on its own and the cost
of cross-backend changes is small enough that the mechanical-
sharing tradeoff is not yet a win.
Where this crate fits in the consumer family
Pattern-matches the existing
[lvqr_fragment::FragmentBroadcasterRegistry] consumers:
| Crate | Wires | Purpose |
|---|---|---|
lvqr_cli::hls::BroadcasterHlsBridge |
on_entry_created |
LL-HLS playlist composition |
lvqr_cli::archive::BroadcasterArchiveIndexer |
on_entry_created |
DVR archive index + on-disk segments |
lvqr_wasm::install_wasm_filter_bridge |
on_entry_created |
Per-fragment WASM filter tap |
lvqr_cli::cluster_claim::install_cluster_claim_bridge |
on_entry_created |
Renew cluster broadcast claim |
lvqr_agent::AgentRunner |
on_entry_created |
Per-broadcast user-defined agents |
lvqr_transcode::TranscodeRunner |
on_entry_created |
Per-broadcast ABR-ladder transcoders |
Operator wiring
lvqr-cli exposes --transcode-rendition 720p,480p,240p (or a
.toml RenditionSpec path) and, on hw-videotoolbox builds,
--transcode-encoder software|videotoolbox. End-to-end shape:
ingest one source RTMP stream, the LL-HLS master playlist
advertises one variant per rendition + the source.