Expand description
Server-side transcoding for LVQR.
Tier 4 item 4.6, session 104 A scaffold. This is the crate
referenced by tracking/TIER_4_PLAN.md section 4.6. The goal is
to let LVQR generate an ABR ladder (720p / 480p / 240p by
default) from a single high-resolution source broadcast, with
the output renditions re-injected into the local
lvqr_fragment::FragmentBroadcasterRegistry so every egress
surface (LL-HLS, DASH, MoQ relay, archive) serves them as if
they had been ingested directly.
§Session 104 A scope
Scaffold + one pass-through transcoder:
Transcodertrait +TranscoderFactory+TranscoderContextmodeled on thelvqr-agentcrate’sAgentshape so operators see one consistent “subscriber-with-lifecycle” idiom across WASM filters, AI agents, and transcoders.TranscodeRunner+TranscodeRunnerHandle: registry-side installer + cheaply-cloneable handle, exactly mirroringAgentRunnerinlvqr-agent.RenditionSpecwith width / height / bitrate fields and three preset constructors (RenditionSpec::preset_720p,RenditionSpec::preset_480p,RenditionSpec::preset_240p) plusRenditionSpec::default_ladderfor the LVQR default 3-rung ladder.PassthroughTranscoder+PassthroughTranscoderFactory: the 104 A concrete implementation. Logs + counts per-fragment but does NOT actually encode or republish output. Exists to prove the end-to-end wiring (FragmentBroadcasterRegistrycallback -> drain task -> per-rendition transcoder instance) before thegstreamer-rspipelines land in session 105 B.
§What session 105 B adds
- Real
gstreamer-rspipelines gated behind atranscodeCargo feature (default OFF so CI runners without gstreamer plugins continue to build). - A
SoftwareTranscoderusingappsrc -> qtdemux -> h264parse -> avdec_h264 -> videoscale -> x264enc -> ... -> mp4mux -> appsink(plus passthrough audio) and re-injecting the output into the caller-suppliedlvqr_fragment::FragmentBroadcasterRegistryas a new broadcast named<source>/<rendition>(e.g.live/foo/720p). - Optional hardware-encoder backends behind per-encoder feature
flags (
hw-nvenc,hw-vaapi,hw-qsv,hw-videotoolbox).
§What session 106 C adds
lvqr-cliwiring (--transcode-rendition 720p,480p,240pflag +ServeConfig::transcode_renditions).- LL-HLS master playlist composition: the HLS bridge learns
about source -> rendition relationships so one master
playlist references every rendition as a variant with
BANDWIDTH/RESOLUTIONmatchingRenditionSpec. AudioPassthroughTranscoderFactory: always-available sibling of [SoftwareTranscoderFactory] that copies<source>/1.mp4fragments verbatim into<source>/<rendition>/1.mp4so each rendition broadcaster is a self-contained mp4 the LL-HLS bridge drains without special-casing the missing audio.- End-to-end demo: ingest one 1080p RTMP stream, watch the LL-HLS master playlist advertise four variants (source + three ladder rungs).
§Anti-scope (session 104 A)
- No
lvqr-cliwiring. 106 C owns the composition root. - No gstreamer dependency. 105 B owns the real pipeline.
Session 104 A ships a pass-through that exists only to
prove the
FragmentBroadcasterRegistrysubscribe / drain / panic-isolation wiring without pulling a heavy C dep into the workspace build. - No output re-publish. 104 A transcoders are observers only. Session 105 B adds the output side.
- No config-file / admin-API ladder override. 105 B + 106 C own operator-facing configuration.
- No HLS master-playlist integration. 106 C owns the egress wiring.
§Where this crate fits in the consumer family
Pattern-matches the five 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 (new) | on_entry_created | Per-broadcast ABR-ladder transcoders |
No new abstractions invented: the trait surface is a
one-method generalisation of [lvqr_agent]’s Agent /
AgentFactory / AgentRunner, re-shaped so each factory
carries its own RenditionSpec. Every existing consumer
already encodes the same subscribe / drain / panic-isolate
pattern by hand.
Structs§
- Audio
Passthrough Transcoder - Per-
(source, rendition)audio passthrough. Forwards every sourceFragmentverbatim to the rendition broadcaster. - Audio
Passthrough Transcoder Factory - Factory that builds one
AudioPassthroughTranscoderper source audio track, republishing fragments onto<source>/<rendition>/1.mp4. - Passthrough
Transcoder - Pass-through transcoder: logs each fragment and counts calls but does NOT encode or republish. The real encoder lives in session 105 B.
- Passthrough
Transcoder Factory - Factory that builds a
PassthroughTranscoderfor each video-track source stream acrate::TranscodeRunnersees. - Rendition
Spec - One rendition in an ABR ladder. Carries the target geometry + bitrates a downstream encoder uses to produce output fragments.
- Transcode
Runner - Builder that collects
TranscoderFactoryregistrations and installs them onto aFragmentBroadcasterRegistry. Typical usage – three rungs of the default ladder: - Transcode
Runner Handle - Cheaply-cloneable handle returned by
TranscodeRunner::install. - Transcoder
Context - Snapshot of the
(broadcast, track, FragmentMeta, rendition)tuple a freshTranscodersees at construction time. - Transcoder
Stats - Per-
(transcoder, rendition, broadcast, track)outcome counters.
Traits§
- Transcoder
- In-process consumer of source
Fragmentvalues for one(broadcast, track, rendition)tuple. The 104 A trait is observe-only; 105 B extends the concrete implementations with an output-publish side without changing the trait surface. - Transcoder
Factory - Factory that builds a
Transcoderfor one specific rendition of one specific(broadcast, track)stream.