This is the start-here map of the codebase: what the system is, how the code is organized, and where to read next. For the per-frame data flow see pipeline.md; for the rationale behind the big choices see decisions.md; for the deep per-crate references see the documentation map at the bottom.
rivet takes an arbitrary input video file and transcodes it to AV1 — as a single MP4, a multi-rendition ABR ladder, or a segmented CMAF/HLS package — on the GPU when one is present, falling back to software. It ships three ways to drive it from one engine:
- a library (
rivet::transcode_file,rivet::run_job), - a CLI (
rivet transcode | probe | devices | capabilities | pipe | ipc | serve), - an HTTP API and a Unix-socket IPC server.
The design goals that explain almost every decision in the tree (the full list is in decisions.md):
- AV1 + Opus + MP4 out by default, royalty-clean. AV1 is the default output
video codec (royalty-clean); H.264 / H.265 are also selectable
(
with_video_codec/--codec) for legacy-player compatibility, accepting their patent-licensing tradeoff. Audio is AAC/Opus passthrough or transcoded to Opus. AV1-default is the load-bearing recommendation — H.264/H.265 are opt-in. - No FFmpeg, in any capacity. Demuxers, muxers, and the GPU codec dispatch
are hand-written / hand-rolled
dlopenFFI in-tree, and the software AV1 paths are pure Rust (rav1e / rav1d). There is noffmpegfeature and no libav* linkage in any build; see No FFmpeg. - Decode once, lease GPUs fairly. A multi-rendition ladder decodes the source a single time and spreads encode work across every GPU.
- Stream, don't buffer. Demux yields one sample at a time so a 15-minute source doesn't materialize in RAM.
flowchart TD
subgraph rivet["rivet — orchestration + front-ends"]
FE["CLI · HTTP API · IPC · library facade"]
ENG["job engine · multi-GPU reactive scheduler<br/>decode pump · gpu pool · scalers · encoder workers"]
FE --> ENG
end
rivet --> codec
rivet --> container
subgraph codec["codec — pixels & bitstreams"]
DEC["decode dispatch (NVDEC/AMF/QSV + optional rav1d)"]
ENC["encode dispatch (NVENC/AMF/QSV + optional rav1e)"]
CLR["colorspace · tonemap · audio · probe · gpu detect"]
end
subgraph container["container — bytes on disk"]
DMX["demux (MP4/MKV/TS/AVI, streaming)"]
MUX["mux (AV1 MP4 · CMAF · HLS)"]
end
| Crate | Responsibility | Reads bytes? | Touches pixels? | Deep-dive |
|---|---|---|---|---|
container |
Demux input containers → samples; mux AV1/audio → MP4 / CMAF / HLS. Clean-room, no FFmpeg. | ✅ | ❌ | container.md |
codec |
Decode samples → frames; encode frames → AV1; colorspace, tonemap, audio, GPU detection, probe. Hand-rolled GPU FFI. | ❌ | ✅ | codec-decode.md · codec-encode.md |
rivet |
The configurable job engine, the reactive multi-GPU scheduler, and the CLI / HTTP / IPC front-ends. | — | — | engine.md |
container and codec are deliberately generic and depend on nothing rivet-specific — they were extracted so the transcoding core is reusable. rivet is the application that wires them into jobs, schedules them across GPUs, and exposes them over three interfaces.
Every job, whatever the front-end, follows the same shape (the detailed diagram
- code map is in pipeline.md):
flowchart LR
IN([input]) --> D["demux<br/>(container)"]
D --> DEC["decode ONCE<br/>(codec, GPU)"]
DEC --> N["normalize<br/>4:4:4→4:2:0 · HDR→SDR tonemap"]
N --> S["scale per rung"]
S --> E["encode AV1<br/>(codec, GPU lease)"]
E --> M["mux<br/>(container)"]
M --> OUT([MP4 / CMAF-HLS])
D -. audio .-> M
The two things that make this fast are decode-once fan-out (one decode — split across the cards at segment-aligned keyframes — feeds all renditions) and ladder workers on a GPU lease pool (every card serves every rung, taking the next chunk of whichever is furthest behind, so no card idles while work exists). Both live in the rivet engine — see engine.md.
There are two orchestrations, picked by GPU count and output mode:
| Path | When | Code | Notes |
|---|---|---|---|
| Single-shot | one file → one MP4, single GPU / --single-gpu |
transcode.rs |
Straight demux→decode→encode→mux loop; bytes returned in memory. The pipe/ipc streaming paths use this. |
| Multi-GPU | ABR ladders, HLS, or multiple GPUs (default) | multigpu/ + the pump/pool/scaler/worker modules |
Decode-once pump (one per range when the source splits) → per-rung scalers → bounded chunk queues → one ladder worker per GPU serving every rung deepest-first, with a cross-vendor codec invariant. |
Single-file output on multiple GPUs uses the reactive engine too: it chunks the
one rendition at GOP boundaries, encodes the chunks across the GPUs, and stitches
them back losslessly (ChunkSeamMode controls seam quality).
The CLI flags, the HTTP JSON/query spec, and the IPC #rivet header are all thin
adapters over a single canonical knob set,
TranscodeSettings, with one
into_spec() builder. Add an option once there and every front-end gets it — see
engine.md and output-spec.md.
flowchart TD
CLI["CLI flags"] --> TS[TranscodeSettings]
JSON["HTTP JSON / query"] --> TS
KV["IPC #rivet k=v header"] --> TS
TS --> SPEC["OutputSpec.into_spec()"] --> ENG["job engine"]
| Doc | What it covers |
|---|---|
| architecture.md (this) | The system map, the crates, the lifecycle, where to read next. |
| pipeline.md | The end-to-end data flow with diagrams + a code map. |
| decisions.md | The cross-cutting why — the load-bearing design decisions and their rationale. |
| codec-decode.md | The codec crate's decode side: the dispatch tiers, each GPU decoder, GPU detection, bitstream parsers, probe, HDR/SEI. |
| codec-encode.md | The codec crate's encode side: the encoder dispatch, each HW backend, quality tuning, colorspace, tonemapping, audio. |
| container.md | The container crate: demuxers (streaming + per-format), Annex-B conversion, the AV1 MP4 muxer, CMAF/HLS, audio glue. |
| engine.md | The rivet crate internals: the job engine, the reactive multi-GPU scheduler, progress, and the CLI/HTTP/IPC front-ends. |
| output-spec.md | The complete OutputSpec configuration guide (every knob, with examples). |
| cli.md | The CLI reference — every subcommand, flag, and env var. |
| api.md | The HTTP API reference — endpoints, request bodies, job lifecycle, OpenAPI. |
Source-tree conventions to know while reading: GPU backends are hand-rolled
dlopen FFI (no wrapper crates) and ship with *_stub.rs fallbacks so a build
without that vendor's feature still compiles; a vendored scaffold that a real
library later replaced is deleted, not kept "for reference."