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.