Personal Monorepo ❄️
README.md

h265-decoder-rs#

A pure Rust H.265/HEVC decoder library.

Parses H.265 Annex B bytestreams and decodes frames to YUV 4:2:0 planar (or converted to RGB/RGBA/NV12), suitable for downstream consumers such as AV1 encoders (e.g. rav1e) or display pipelines.

Project structure#

h265-decoder-rs/
├── Cargo.toml                          # Workspace manifest
├── crates/
│   └── h265-decode/
│       ├── Cargo.toml                  # Library crate
│       └── src/
│           ├── lib.rs                  # Public API exports
│           ├── decode.rs               # Top-level Decoder struct and pipeline
│           ├── bitstream.rs            # Bit-level reader, exp-Golomb, emulation prevention
│           ├── nal.rs                  # HEVC NAL unit types, VPS/SPS/PPS/slice header parsing
│           ├── dpb.rs                  # Decoded Picture Buffer (HEVC RPS-based management)
│           ├── frame.rs                # DecodedFrame, FramePlane, PictureType
│           ├── pixel.rs                # PixelFormat, ColourMatrix, YUV↔RGB conversion
│           └── error.rs                # Error and warning types
├── default.nix                         # Nix package and devShell
├── justfile                            # Development commands
└── README.md

Quick start#

use h265_decode::{Decoder, DecoderConfig, PixelFormat};

let config = DecoderConfig::new().pixel_format(PixelFormat::Yuv420p);
let mut decoder = Decoder::new(config);

// Feed raw H.265 Annex B bytestream data
let h265_data: &[u8] = &[/* ... */];
let frames = decoder.decode(h265_data).expect("decode failed");

for frame in &frames {
    println!(
        "decoded {}x{} frame, pts={:?}, {} bytes",
        frame.width(),
        frame.height(),
        frame.pts(),
        frame.data().len(),
    );
}

// Flush remaining frames at end of stream
let trailing = decoder.flush().expect("flush failed");

Architecture#

H.265 Annex B bytestream
┌───────────────────────────┐
│  Annex B start-code       │  Split byte stream on 00 00 01 / 00 00 00 01
│  scanner                  │  start codes into individual NAL units
└───────┬───────────────────┘
        │  Vec<NAL unit bytes>
┌───────────────────────────┐
│  NAL unit parser          │  2-byte HEVC NAL header (type, layer, temporal ID)
│  + emulation prevention   │  Remove 0x00 0x00 0x03 escape bytes → RBSP
│  removal                  │
└───────┬───────────────────┘
        │  NAL type + RBSP data
┌───────────────────────────┐
│  Parameter set parsers    │  VPS (§7.3.2.1): layer/sub-layer config
│  VPS / SPS / PPS          │  SPS (§7.3.2.2): resolution, chroma, bit depth,
│                           │      coding block sizes, reference picture sets
│                           │  PPS (§7.3.2.3): QP, tiles, deblocking, etc.
└───────┬───────────────────┘
┌───────────────────────────┐
│  Slice header parser      │  Slice type (I/P/B), POC LSB, RPS selection,
│  (§7.3.6.1)               │  segment address, dependent slice handling
└───────┬───────────────────┘
┌───────────────────────────┐
│  POC derivation           │  Picture Order Count from LSB + MSB accumulator
│  (§8.3.1)                 │  (same algorithm as H.264 POC type 0)
└───────┬───────────────────┘
┌───────────────────────────┐
│  Picture reconstruction   │  Scaffold: grey I-frames, reference-copy P/B
│  (CTU decode — WIP)       │  Future: CABAC, intra/inter pred, DST/DCT,
│                           │  deblocking, SAO
└───────┬───────────────────┘
        │  DecodedFrame (Y, U, V planes)
┌───────────────────────────┐
│  Decoded Picture Buffer   │  HEVC RPS-based reference management
│  (DPB)                    │  Reorder bumping (max_num_reorder_pics)
│                           │  Display-order output (ascending POC)
└───────┬───────────────────┘
        │  Frames in display order
┌───────────────────────────┐
│  Pixel format conversion  │  YUV 4:2:0 → RGB24 / RGBA32 / NV12
│  (optional)               │  BT.601 / BT.709 / BT.2020 matrices
└───────────────────────────┘

HEVC features implemented#

NAL layer#

  • 2-byte HEVC NAL unit header parsing (type, layer ID, temporal ID)
  • All VCL and non-VCL NAL unit type classification
  • IRAP detection (IDR, CRA, BLA)
  • Annex B start-code scanning (3-byte and 4-byte)
  • Emulation prevention byte removal (0x00 0x00 0x03)

Parameter sets#

  • Video Parameter Set (VPS) – profile/tier/level, sub-layer ordering
  • Sequence Parameter Set (SPS) – resolution, chroma format, bit depth, coding block sizes, reference picture sets, long-term refs, PCM, scaling list (skipped)
  • Picture Parameter Set (PPS) – QP, tiles, deblocking, weighted prediction, entropy coding sync
  • Profile/Tier/Level parsing (general + sub-layer skip)
  • Short-term Reference Picture Set parsing (explicit + inter-prediction)
  • Conformance window crop offset computation

Slice layer#

  • Slice segment header: first_slice flag, type (I/P/B), POC LSB, RPS selection
  • Dependent slice segment detection
  • Slice-local short-term RPS parsing

Picture management#

  • POC derivation (MSB/LSB accumulator with wraparound)
  • Decoded Picture Buffer with configurable size
  • RPS-based reference marking (mark unused, short-term, long-term)
  • Reorder bumping (max_num_reorder_pics constraint)
  • Display-order output (ascending POC)
  • IDR DPB flush
  • Reference list 0 and list 1 construction

Pixel output#

  • YUV 4:2:0 planar (native)
  • RGB24 packed conversion
  • RGBA32 packed conversion
  • NV12 semi-planar conversion
  • BT.601, BT.709, BT.2020 colour matrices

Reconstruction (scaffold)#

  • Grey placeholder for I-frames
  • Reference copy for P/B-frames
  • CABAC entropy decoding
  • Intra prediction (planar, DC, angular)
  • Inter prediction (motion compensation)
  • Inverse transform (DST 4×4, DCT 8×8/16×16/32×32)
  • Dequantization
  • Deblocking filter
  • Sample Adaptive Offset (SAO)

Pixel format output#

Format Description Use case
Yuv420p YUV 4:2:0 planar (I420) Video encoders (rav1e, x265)
Rgb24 Packed 24-bit RGB Display, image processing
Rgba32 Packed 32-bit RGBA Display with alpha
Nv12 Semi-planar Y + interleaved UV Hardware APIs (VA-API, DXVA)

Development#

# Build
cargo build

# Run all tests (138 unit tests)
cargo test

# Run clippy
cargo clippy -- -D warnings

# Format code
cargo fmt

Nix#

# Enter the devShell
direnv allow  # or: nix develop .#h265-decoder-rs

# Build the package
nix build .#h265-decoder-rs

Comparison with h264-decoder-rs#

Feature h264-decoder-rs h265-decoder-rs
NAL header 1 byte 2 bytes
Parameter sets SPS + PPS VPS + SPS + PPS
Coding unit Macroblock (16×16) CTU (up to 64×64)
Reference management Sliding window / MMCO Reference Picture Sets
POC derivation Type 0, 1, 2 Single type (LSB/MSB)
Colour matrix default BT.601 BT.709
Colour matrices BT.601, BT.709 BT.601, BT.709, BT.2020
NAL parser h264-reader crate Built-in (pure Rust)
Reconstruction Scaffold Scaffold

License#

MIT