Skip to main content

Hardware-accelerated motion decode

Recording itself never re-encodes video, camera streams are copied straight to disk. Only the motion-analysis path needs a decoder, and the default stack runs that on CPU with no action required (MOTION_HWACCEL=auto, which falls back to CPU whenever no supported GPU is present).

Enabling it

Because Docker never lets a running container grant itself new devices, mapping a GPU or iGPU into the recorder is always a host-side compose change. The supported path is the bundled helper script:

scripts/enable-hwaccel.sh # autodetects; or --backend vaapi|nvdec

It detects the host's hardware (render nodes under /dev/dri for VAAPI, a working nvidia-smi plus the container toolkit for NVDEC), writes the matching stanza into a gitignored docker-compose.override.yml (loaded automatically by every plain docker compose up -d), and restarts the recorder. It refuses to touch an existing override file, printing the stanza to merge by hand instead, and refuses cleanly if no supported hardware is present. Pass --print to see what it would write without applying it.

Manual overlays

If you'd rather see the moving parts, the committed overlay files at the repository root do the same thing by hand:

Intel/AMD iGPU (VAAPI):

docker compose -f docker-compose.yml -f docker-compose.vaapi.example.yml up -d recorder

Set RENDER_GID in .env to the host's render-group GID (getent group render | cut -d: -f3), and MOTION_VAAPI_DEVICE if the iGPU's render node isn't the default /dev/dri/renderD128.

NVIDIA (NVDEC):

docker compose -f docker-compose.yml -f docker-compose.gpu.example.yml up -d recorder

Requires the NVIDIA driver and nvidia-container-toolkit on the host.

Verifying what's actually active

A requested backend and an actually-active backend aren't always the same thing, if the matching device isn't mapped into the container, the recorder logs a warning and falls back to CPU rather than failing. Check the truth with:

GET /config/decode-status

or the admin console's motion-decoding panel, which shows the same data: per camera, the requested backend, the active one, and a human-readable reason whenever they differ. capabilities: null means the recorder hasn't reported in yet (an older image, or it just hasn't booted), not that no devices exist.

A wrong pick is always safe: the recorder falls back to CPU automatically rather than failing to decode at all.