Command line

nanocodec encodes raw 8-bit 4:2:0 video, decodes our streams, and extracts temporal or spatial sub-streams. The examples below use the 640x360 test clip from Getting started; the full option list is at the end of this page, the same list nanocodec help prints.

Fixed QP

Without --bitrate, every frame is coded at --qp in the codec's own scale (QP for H.264, HEVC and VVC; base_q_idx 0-255 for AV1, VP9 and AV2):

nanocodec encode --codec h264 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --qp 30 --output out.264

Real-time rate control (CBR) and buffer

--bitrate turns on the single-pass real-time rate control: no lookahead, a virtual decoder buffer of --buffer-ms (1000 ms by default) and a peak of twice the target unless --peak-bitrate says otherwise. The target is a ceiling: easy content may come in under it. --rate-change changes the target mid-stream, as a transport's bandwidth estimate would; --rate-log writes each frame's quantiser, size and buffer state:

nanocodec encode --codec hevc --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 400 --buffer-ms 500 --rate-change 75:200 --rate-log rate.csv --output out.hevc

With --timestamps (one capture time per frame), rate control budgets each frame for its real interval, so a camera that skips frames keeps its bitrate in time. --frame-drop lets it skip an inter frame that would overflow the buffer even at the highest quantiser.

Resilience: temporal layers, long-term references, key frames

Three temporal layers (hierarchical P; the top layer can be dropped), a long-term reference every 30 frames for loss recovery, and a key frame on request at frame 90, as a receiver's request would cause. By default the encoder picks flat or layered coding per group of frames from the motion it sees (layers.adaptive); --param layers.adaptive=0 keeps the layers throughout:

nanocodec encode --codec h264 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 300 --temporal-layers 3 --param layers.adaptive=0 --ltr-interval 30 --keyframe 90 \
  --output layered.264

Keep only temporal layers 0 and 1 (half the frame rate), without re-encoding:

nanocodec extract --codec h264 --temporal-layers 3 --max-layer 1 --input layered.264 --output half-rate.264

Intra refresh replaces periodic key frames with an intra column that sweeps the picture every --intra-refresh frames, so a receiver that lost a frame recovers without a key-frame burst:

nanocodec encode --codec av1 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 300 --intra-refresh 30 --output refresh.ivf

The C API takes the same settings and adds the live calls: key-frame requests, bitrate changes, and the receiver's acknowledgements and loss reports.

Spatial scalability (SVC)

AV1 and VP9 code several spatial layers in one stream with --scalability (WebRTC mode names: L2T1 is two spatial layers at 2:1 and one temporal layer; _KEY modes are K-SVC). A receiver can decode the base layer alone:

nanocodec encode --codec av1 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 500 --scalability L2T1 --output svc.ivf
nanocodec extract --codec av1 --base-only --input svc.ivf --output base.ivf
nanocodec decode --codec av1 --input base.ivf --output base.yuv

Still camera

--still-camera adds noise handling for a fixed camera over the preset. It lowers the bitrate on still, noisy scenes and is off in every preset:

nanocodec encode --codec av1 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 300 --still-camera --output still.ivf

Presets, parameter files and --param

The encoder's heuristics are named parameters. They are applied in order, later settings winning: the preset, then --params FILE, then each --param NAME=VALUE. nanocodec params --codec C lists every parameter with the codec's default, its range and what raising it trades. A parameter file has one name = value per line:

# my-params.toml
planner.lambda_scale = 1.1
nanocodec encode --codec h264 --input in.yuv --width 640 --height 360 --fps 30 --frames 150 \
  --bitrate 300 --preset fast --params my-params.toml --param scene.detect=0 --output tuned.264

Decoding

What our decoders read, per format: H.264 (Constrained High), HEVC (Main), AV1 (Main, 8-bit 4:2:0) and VP9 (profile 0) pass the conformance streams we test in those profiles; VVC passes the 9 official 8-bit streams and 121 of 133 8-bit VTM and VVenC streams, so it is not a full Main-profile decoder; AV2 decodes our own streams and 9 of 30 foreign test streams (the rest use tools outside our subset). All are 8-bit 4:2:0 only. Output is raw I420 (- writes stdout); --frame-md5 writes one MD5 per frame, and --discard 1 decodes without writing, for timing:

nanocodec decode --codec hevc --input out.hevc --output decoded.yuv
nanocodec decode --codec h264 --input layered.264 --frame-md5 frames.md5

All options

Generated from crates/nc-cli/src/help.rs, which a test keeps in step with the options the parsers read.