Skip to main content

lvqr_transcode/
lib.rs

1//! Server-side transcoding for LVQR (Tier 4 item 4.6).
2//!
3//! Generates an ABR ladder (720p / 480p / 240p by default) from a
4//! single high-resolution source broadcast, with the output
5//! renditions re-injected into the caller-supplied
6//! [`lvqr_fragment::FragmentBroadcasterRegistry`] under
7//! `<source>/<rendition>` broadcast names. Every egress surface
8//! (LL-HLS, DASH, MoQ relay, archive) picks them up without
9//! per-protocol wiring; the LL-HLS master playlist composer emits
10//! one `#EXT-X-STREAM-INF` per rendition automatically.
11//!
12//! ## What this crate ships
13//!
14//! Always available (default features):
15//!
16//! * [`Transcoder`] trait + [`TranscoderFactory`] +
17//!   [`TranscoderContext`] -- the "subscribe / drain / panic-isolate"
18//!   shape generalised from `lvqr_agent::Agent`. Each factory
19//!   carries its own [`RenditionSpec`].
20//! * [`TranscodeRunner`] + [`TranscodeRunnerHandle`] -- registry-side
21//!   installer + cheaply-cloneable handle, mirroring
22//!   `lvqr_agent::AgentRunner`.
23//! * [`RenditionSpec`] with width / height / bitrate fields,
24//!   [`RenditionSpec::preset_720p`] / `preset_480p` / `preset_240p`
25//!   constructors, and [`RenditionSpec::default_ladder`].
26//! * [`PassthroughTranscoder`] -- in-memory observer that proves
27//!   the registry-callback / drain / panic-isolation wiring; useful
28//!   for tests and as a metrics tap.
29//! * [`AudioPassthroughTranscoder`] -- copies `<source>/1.mp4` audio
30//!   fragments verbatim into every rendition's audio track so each
31//!   rendition broadcaster is a self-contained mp4 the LL-HLS
32//!   bridge drains without special-casing the missing audio.
33//!
34//! Behind the `transcode` feature (pulls gstreamer-rs 0.23 +
35//! base/good/bad/ugly + gst-libav from the host):
36//!
37//! * [`SoftwareTranscoder`] / [`SoftwareTranscoderFactory`] -- the
38//!   `appsrc -> qtdemux -> h264parse -> avdec_h264 -> videoscale ->
39//!   x264enc -> ... -> mp4mux -> appsink` ladder, one worker thread
40//!   per `(source, rendition)` pair, bounded mpsc.
41//! * [`AacToOpusEncoder`] / [`AacToOpusEncoderFactory`] -- AAC -> Opus
42//!   transcoder used by `lvqr-whep` (under its `aac-opus` feature)
43//!   so AAC publishers reach Opus-negotiated WHEP subscribers.
44//!
45//! Behind the `hw-videotoolbox` feature (implies `transcode`;
46//! requires the `applemedia` plugin from gst-plugins-bad):
47//!
48//! * [`VideoToolboxTranscoder`] / [`VideoToolboxTranscoderFactory`]
49//!   -- mirrors `SoftwareTranscoderFactory` but swaps the
50//!   `x264enc bitrate=... tune=zerolatency speed-preset=superfast`
51//!   pipeline element for Apple's HW-only `vtenc_h264_hw bitrate=...
52//!   realtime=true allow-frame-reordering=false
53//!   max-keyframe-interval=60`. HW-only path is intentional: a
54//!   factory that silently falls back to CPU encoding under load
55//!   defeats the point of an operator-pickable hardware tier.
56//!   `is_available()` probes for the encoder element at construction
57//!   and `build()` opts out cleanly with a warn log when missing.
58//!
59//! NVENC, VAAPI, and QSV stay deferred to v1.2 per the README's
60//! existing language. When a third HW backend lands, that session
61//! is also the right moment to extract a shared `pipeline.rs`
62//! scaffolding module from `software.rs` + `videotoolbox.rs`.
63//!
64//! ## Where this crate fits in the consumer family
65//!
66//! Pattern-matches the existing
67//! [`lvqr_fragment::FragmentBroadcasterRegistry`] consumers:
68//!
69//! | Crate | Wires | Purpose |
70//! |-------|-------|---------|
71//! | `lvqr_cli::hls::BroadcasterHlsBridge` | `on_entry_created` | LL-HLS playlist composition |
72//! | `lvqr_cli::archive::BroadcasterArchiveIndexer` | `on_entry_created` | DVR archive index + on-disk segments |
73//! | `lvqr_wasm::install_wasm_filter_bridge` | `on_entry_created` | Per-fragment WASM filter tap |
74//! | `lvqr_cli::cluster_claim::install_cluster_claim_bridge` | `on_entry_created` | Renew cluster broadcast claim |
75//! | `lvqr_agent::AgentRunner` | `on_entry_created` | Per-broadcast user-defined agents |
76//! | `lvqr_transcode::TranscodeRunner` | `on_entry_created` | Per-broadcast ABR-ladder transcoders |
77//!
78//! ## Operator wiring
79//!
80//! `lvqr-cli` exposes `--transcode-rendition 720p,480p,240p` (or a
81//! `.toml` `RenditionSpec` path) and, on `hw-videotoolbox` builds,
82//! `--transcode-encoder software|videotoolbox`. End-to-end shape:
83//! ingest one source RTMP stream, the LL-HLS master playlist
84//! advertises one variant per rendition + the source.
85
86mod audio_passthrough;
87mod passthrough;
88mod rendition;
89mod runner;
90mod transcoder;
91
92#[cfg(feature = "transcode")]
93mod aac_opus;
94#[cfg(feature = "transcode")]
95mod software;
96#[cfg(feature = "transcode")]
97pub mod test_support;
98
99#[cfg(feature = "hw-videotoolbox")]
100mod videotoolbox;
101
102pub use audio_passthrough::{AudioPassthroughTranscoder, AudioPassthroughTranscoderFactory};
103pub use passthrough::{PassthroughTranscoder, PassthroughTranscoderFactory};
104pub use rendition::RenditionSpec;
105pub use runner::{TranscodeRunner, TranscodeRunnerHandle, TranscoderStats};
106pub use transcoder::{Transcoder, TranscoderContext, TranscoderFactory};
107
108#[cfg(feature = "transcode")]
109pub use aac_opus::{AacAudioConfig, AacToOpusEncoder, AacToOpusEncoderFactory, OpusFrame};
110#[cfg(feature = "transcode")]
111pub use software::{SoftwareTranscoder, SoftwareTranscoderFactory};
112
113#[cfg(feature = "hw-videotoolbox")]
114pub use videotoolbox::{VideoToolboxTranscoder, VideoToolboxTranscoderFactory};