Skip to content

Latest commit

 

History

History
149 lines (119 loc) · 7.6 KB

File metadata and controls

149 lines (119 loc) · 7.6 KB

rivet architecture

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.


What rivet is

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 dlopen FFI in-tree, and the software AV1 paths are pure Rust (rav1e / rav1d). There is no ffmpeg feature 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.

The three crates

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
Loading
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.


The transcode lifecycle

Every job, whatever the front-end, follows the same shape (the detailed diagram

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
Loading

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.


The two execution paths

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 front-ends share one definition

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"]
Loading

Documentation map

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."