Pure C H.264 Baseline decoder. 497 KB, zero dependencies, runtime SIMD dispatch, smart-skip on static scenes.
NexusDecode is a lightweight libavcodec replacement for NVR/VMS workloads: H.264 Baseline profile (≈90 % of surveillance cameras), no B-frames, no external libraries, single static binary on Linux x86-64. Designed around the realities of CCTV streams — static cameras, long GOPs, P-frame-heavy content.
Part of the NexusEye stack — a video management server with its own decode / inference / compressed-domain analytics engines.
libnexusdecode.a is 497 KB with zero external dependencies. A full FFmpeg stack (libavcodec + libavutil + libavformat) is around 10 MB plus system libraries.
Benchmarks are reproducible — sample streams ship in samples/ of the release tarball, and nexusdecode-bench accepts any Annex-B file:
$ ./nexusdecode-bench motion_event.h264 3
nexusdecode-bench · file=motion_event.h264 · size=4.02 MB · iterations=3
decoded: 306 frames (2880x1616)
wall-clock: 2.273 s
throughput: 134.6 fps (7.43 ms/frame)
int decode_smart(Decoder* dec, const uint8_t* nal, int nal_size, Frame* out);Returns DECODE_STATIC when a P-frame contains no motion vectors (every macroblock is P-skip with MV=0). The NVR can then reuse the previous frame for downstream consumers without a full decode. On static cameras (warehouse at night, parking lot off-hours) this drops effective decode load by ~10×.
DECODE_OK // SPS/PPS NAL, nothing to do
DECODE_FRAME_READY // full frame ready
DECODE_STATIC // P-frame, MV=0 — frame unchanged
DECODE_MOTION // P-frame with motion, frame decoded
DECODE_CACHED // IDR, used approximate cache
| Layer | What it does |
|---|---|
| Bitstream | NAL parser, SPS/PPS, slice header, exp-Golomb |
| Entropy | CAVLC (Baseline only; CABAC not implemented) |
| Transform | 4×4 / 2×2 inverse, hadamard for luma DC |
| Prediction | 9 intra-modes (4×4) + 4 (16×16), motion compensation for P-slice |
| Deblocking | edge filter (alpha/beta/tc per spec) |
| Color convert | YUV420 → RGB (optional, SSSE3 path) |
| Parallel | pthread pool, slice-level parallelism |
| Runtime SIMD | CPUID dispatch on init: SSE2 → SSSE3 → AVX2 → fallback |
| Profile | NexusDecode | Where you find it |
|---|---|---|
| Baseline (CAVLC) | ✓ full | IP cameras, RTSP (90 % surv.) |
| Main (CABAC) | — not implemented | Blu-ray, Netflix |
| High (8×8 transform) | — not implemented | Premium consumer encoders |
| 10-bit | — | HDR mastering |
| B-frames | parsed | rare in surveillance streams |
wget https://github.com/facex-engine/nexusdecode/releases/latest/download/nexusdecode-linux-x64.tar.gz
tar xzf nexusdecode-linux-x64.tar.gz
cd nexusdecode
./nexusdecode-bench samples/motion_event.h264 3git clone https://github.com/facex-engine/nexusdecode
cd nexusdecode
make # → libnexusdecode.a (497 KB)
make bench # → nexusdecode-benchRequirements: gcc ≥ 9 or clang ≥ 10, make, glibc.
#include "decode.h"
Decoder* dec = decode_init();
while (read_nal(stream, nal_data, &nal_size)) {
Frame frame;
int r = decode_smart(dec, nal_data, nal_size, &frame);
if (r == DECODE_FRAME_READY || r == DECODE_MOTION) {
consume_frame(&frame); // y / u / v planes
} else if (r == DECODE_STATIC) {
reuse_previous_frame(); // 0 CPU — frame unchanged
}
}
decode_free(dec);Linking: gcc your_app.c libnexusdecode.a -lm -lpthread.
Tested against streams from:
- Hikvision DS-2CD23xx series (H.264 Baseline + Smart Codec H.265+)
- Dahua IPC-HFW (H.264 Baseline)
- Axis P-series (Baseline + Main; Main is rejected — not supported)
- Reolink, Vivotek, Wyze (over ONVIF) — Baseline ok
- TP-Link Tapo, Xiaomi (over RTSP) — Baseline ok
If your camera emits Main or High profile — either switch the camera to Baseline in its encoder settings, or use FFmpeg as a fallback (NexusDecode honestly returns DECODE_ERROR for unsupported bitstreams).
MIT — see LICENSE.
Baurzhan Atynov (@bauratynov)
| Component | What it does | Size |
|---|---|---|
| NexusDecode (you are here) | H.264 decode | 497 KB |
| NexusInfer | YOLO inference on CPU, ONNX Runtime replacement | 159 KB |
| NexusSense | Compressed-domain analytics, motion without decode | 56 KB |
| FaceX | Face embedding INT8 on CPU | 180 KB |