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.