An open source C library implementing the NotchLC video codec, with an FFmpeg plugin.
Status: Active development. The core library, GPU decode path, encoder, and FFmpeg wrappers are implemented and tested on macOS/Linux. Windows builds are expected to work (C99, no POSIX dependencies, MSVC support in CMake) but have not yet been tested. See ROADMAP.md.
NotchLC (nclc) is a GPU-friendly intra-frame video codec used in the live visual and
VJ community, primarily via Notch. It stores each frame as a
YUV+Alpha image using spatial-domain block compression with LZ4 or LZF entropy coding,
inside a QuickTime MOV container.
The codec is designed so that compressed frames can be uploaded directly to the GPU and
decompressed via compute shaders, minimizing PCI-e bandwidth and avoiding CPU-side
decode overhead. FFmpeg has an existing CPU-side decoder; libnclc aims to provide
both CPU and GPU-friendly decode paths, plus an encoder (which no open-source
implementation currently provides).
| Property | Value |
|---|---|
| FourCC | nclc |
| Container | QuickTime MOV |
| Color model | YCbCr + Alpha |
| Luma depth | 12 bits |
| Chroma depth | 8 bits (expanded to 12 on decode) |
| Alpha depth | 8 bits (expanded to 12 on decode) |
| Decoded pixel format | YUVA 4:4:4 12-bit |
| Compression | LZF or LZ4 (custom variant) |
| Block sizes | 4x4 (luma), 16x16 hierarchical (chroma, alpha) |
| Typical compression | 5:1 to 8:1 vs raw |
See format.md for the complete bitstream specification.
cmake -B build
cmake --build buildctest --test-dir build --output-on-failurecmake --install build --prefix /usr/localFFmpeg AVCodec wrappers are provided in ffmpeg/ for both decoding and encoding.
These must be integrated into an FFmpeg source tree — see ffmpeg/README.md.
#include <nclc/nclc.h>
nclc_decoder_t *dec = nclc_decoder_create();
nclc_frame_t frame;
nclc_error_t err = nclc_decode_frame(dec, sample_data, sample_size,
NCLC_PIXFMT_RGBA8, &frame);
if (err == NCLC_OK) {
/* frame.planes[0] is RGBA8, frame.width x frame.height */
nclc_frame_free(&frame);
}
nclc_decoder_destroy(dec);nclc_encoder_params_t params = {
.width = 1920, .height = 1080,
.quality = NCLC_QUALITY_HIGH,
.compress = NCLC_COMPRESS_LZ4,
};
nclc_encoder_t *enc = nclc_encoder_create(¶ms);
uint8_t *out_data; size_t out_size;
nclc_encode_frame(enc, &input_frame, &out_data, &out_size);
/* out_data is a complete NotchLC frame, decodable by FFmpeg/libnclc */
nclc_encoder_destroy(enc);nclc_gpu_frame_t gpu;
nclc_decode_gpu(dec, sample_data, sample_size, &gpu);
/* Option A: Upload individual sections */
/* gpu.y_control, gpu.y_data, gpu.y_block_offsets, gpu.uv_data, etc. */
/* Option B: Single packed buffer upload */
const uint8_t *pack; size_t pack_size;
nclc_gpu_pack(dec, &gpu, &pack, &pack_size);
/* Upload pack buffer, dispatch shaders using nclc_gpu_header_t offsets */Reference compute shaders are provided in shaders/ (GLSL 450, HLSL SM 5.0, Metal).
libnclc/
├── include/
│ └── nclc/
│ └── nclc.h # Public C API
├── src/
│ ├── internal.h # Shared internal definitions
│ ├── bitstream.h/.c # Bit reader/writer
│ ├── lz4.c # Custom LZ4 decompressor
│ ├── lzf.c # LZF decompressor
│ ├── decode.c # Frame-level decode dispatch
│ ├── decode_y.c # Y channel block decoder
│ ├── decode_uv.c # UV channel hierarchical decoder
│ ├── decode_alpha.c # Alpha channel decoder
│ ├── decode_gpu_ref.c # CPU reference decode from GPU data
│ ├── gpu_pack.c # Single-buffer GPU upload packing
│ ├── colorspace.c # YUVA ↔ RGBA conversion
│ ├── encode.c # Frame-level encoder
│ ├── encode_y.c # Y channel block encoder
│ ├── encode_uv.c # UV hierarchical encoder
│ └── encode_alpha.c # Alpha channel encoder
├── shaders/
│ ├── nclc_common.glsl # Shared GLSL definitions
│ ├── nclc_decode_y.comp # Y luma decode (GLSL 450)
│ ├── nclc_decode_uv.comp # UV chroma decode (GLSL 450)
│ ├── nclc_decode_alpha.comp # Alpha decode (GLSL 450)
│ ├── nclc_yuva_to_rgba.comp # Colorspace conversion (GLSL 450)
│ ├── hlsl/ # HLSL SM 5.0 translations
│ └── metal/ # Metal Shading Language translations
├── ffmpeg/
│ ├── nclcdec.c # FFmpeg AVCodec decoder wrapper
│ ├── nclcenc.c # FFmpeg AVCodec encoder wrapper
│ └── README.md # FFmpeg integration instructions
├── tools/
│ ├── nclcinfo.c # CLI inspection tool
│ ├── nclcenc.c # Raw RGBA8-to-frame encoder CLI
│ └── nclcdec.c # Frame-to-raw RGBA8 decoder CLI
├── tests/
│ ├── test_decode.c # Decoder and malformed-input tests
│ ├── test_gpu_ref.c # CPU vs GPU-reference validation
│ ├── test_encode.c # Encoder round-trip tests
│ └── test_lz4_roundtrip.c # Custom LZ4 tests
├── cmake/
│ └── libnclcConfig.cmake.in # CMake package config template
├── format.md # Bitstream specification
├── ROADMAP.md # Phased development plan
├── CONTRIBUTING.md # Contribution guidelines
├── CMakeLists.txt
└── LICENSE
- FFmpeg decoder:
libavcodec/notchlc.cby Paul B Mahol (2020) — CPU-side decoder outputting YUVA444P12 - Notch official: notchlc.notch.one
NotchLC's bitstream format was determined through reverse engineering of files produced by Notch, with reference to FFmpeg's LGPL-licensed decoder implementation. Reverse engineering for interoperability is protected under EU Software Directive Article 6 and has defensible basis under DMCA §1201(f).
This project is not affiliated with or endorsed by Notch.
GNU Lesser General Public License v2.1 or later. See LICENSE.
Contributions require assignment of rights compatible with LGPL-2.1+.
See CONTRIBUTING.md.