Files
gx fca07bf669
build / cmake build (CUDA 12.4, Ubuntu 22.04) (pull_request) Failing after 3m43s
build / ffmpeg filter patch (out-of-tree) (pull_request) Has been skipped
test+docs: packet ring stress test + Frigate dual-input guide (v0.2 Step 6)
Тесты:
- libcuframes/tests/test_packet_ring.c — 2 scenarios:
  1) normal flow: 1 pub × 1 sub × 2000 packets, varied sizes, GOP=30,
     payload integrity check (seq в первых 8 байтах + pattern). PTS
     monotonicity, first KEY seq, нет data errors.
  2) slow consumer (10ms delay): publisher 200 fps, subscriber должен
     detect OVERRUN, library resync на keyframe — verify received >10
     даже на сильно медленном консьюмере.
- libcuframes/tests/CMakeLists.txt: add_test packet_ring_basic.

Docs:
- CHANGELOG.md: новая [Unreleased] секция с full v0.2 highlights и
  явно declared limitations (sub-stream, audio, codec change → v0.3).
- docs/integrations/frigate.md: новая секция "v0.2: dual-input (detect +
  record через один RTSP)" с config example, requirements, trade-offs.

Связано: #2, PR #4. Step 6 (final) перед снятием draft.
2026-05-19 17:08:17 +01:00

365 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Frigate integration
Полный production-tested guide для интеграции cuframes с
[Frigate NVR](https://github.com/blakeblackshear/frigate). На основе реального
deployment (Frigate 0.17.1-tensorrt + RTX 5090 + Dahua HEVC камеры).
## Что вы получаете
- **Один NVDEC decode на камеру** вместо одного у Frigate + одного у каждого
другого consumer'а (cctv-processor, AI-скрипт, mosaic-сервер).
- Frigate видит decoded frames через **обычный FFmpeg URL** — никакого fork'а
Frigate-кода. Frigate сам не подозревает что под капотом cuframes.
## Что вы НЕ получаете в v0.1
- **Record path** (`-c:v copy` для архива) — этот path в Frigate всё ещё через
свой отдельный RTSP. v0.2 cuframes решит это через encoded packet sharing
(см. [issue #2](https://git.goldix.org/gx/cuframes/issues/2)).
- Hwaccel CUDA filters для detect resize (`scale_cuda`) — наш minimal FFmpeg
собран без `--enable-cuda-llvm` (не работает на glibc < 2.38 что у Debian 12,
на котором Frigate base). Workaround: `hwaccel_args: []` в config → CPU
scale (cost ~5-10% CPU на FHD25).
## Архитектура
```
Camera RTSP ──► cuframes-rtsp-source ──► [NVDEC ─► NV12 in CUDA IPC]
├──► Frigate (ffmpeg -f cuframes) → detect
├──► cctv-processor (CuframesSource) → motion+mosaic
└──► AI-script (Python ctypes) → inference
```
## Требования
| | Минимум | Note |
|---|---|---|
| NVIDIA driver | 555+ | для CUDA 12 runtime |
| CUDA Toolkit (для build patched FFmpeg) | 12.4+ | host или builder container |
| GPU compute capability | ≥ 7.5 | требование CUDA IPC |
| OS на target (Frigate runtime) | Debian 12 bookworm | glibc 2.36 — это база Frigate `stable-tensorrt` |
| OS на builder | Ubuntu 22.04 (glibc 2.35) | forward-compat с Debian 12 |
| docker buildx | latest | для multi-stage build |
## Шаг 1 — Build patched Frigate image
Cuframes integration требует patched FFmpeg внутри Frigate с `cuframes://`
demuxer. Самый простой путь — собрать overlay image поверх existing Frigate.
### 1.1. Минимальный Dockerfile (Debian 12 builder + custom FFmpeg)
```dockerfile
# Build patched FFmpeg на Debian 12 (glibc-совместимо с Frigate runtime)
FROM debian:bookworm AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake git nasm pkg-config ca-certificates wget patch ninja-build \
libssl-dev libx264-dev libx265-dev libnuma-dev zlib1g-dev \
libfreetype-dev libfribidi-dev libharfbuzz-dev libfontconfig-dev \
libvpx-dev libopus-dev libmp3lame-dev libvorbis-dev libtheora-dev libwebp-dev \
libaom-dev libdav1d-dev libsvtav1enc-dev \
libssh-dev librist-dev libsrt-openssl-dev \
libdrm-dev libva-dev libxcb1-dev \
&& rm -rf /var/lib/apt/lists/*
# CUDA toolkit 12.x
RUN wget -q https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb \
&& dpkg -i cuda-keyring_1.1-1_all.deb && rm cuda-keyring_1.1-1_all.deb \
&& apt-get update && apt-get install -y --no-install-recommends cuda-toolkit-12-6 \
&& rm -rf /var/lib/apt/lists/*
ENV PATH=/usr/local/cuda/bin:$PATH
# nv-codec-headers (для FFmpeg ffnvcodec/nvenc/nvdec)
RUN git clone --depth 1 --branch n12.2.72.0 https://github.com/FFmpeg/nv-codec-headers.git /tmp/nvc \
&& make -C /tmp/nvc install && rm -rf /tmp/nvc
# Build libcuframes (static install в /opt/cuframes)
RUN git clone --depth 1 https://git.goldix.org/gx/cuframes.git /src/cuframes \
&& cmake -B /src/cuframes/build -S /src/cuframes -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF \
-DBUILD_EXAMPLES=OFF -DBUILD_TOOLS=OFF \
&& cmake --build /src/cuframes/build -j"$(nproc)" \
&& cmake --install /src/cuframes/build --prefix /opt/cuframes
# Clone patched FFmpeg fork (либо upstream + apply patch — см. filter/README.md)
RUN git clone --depth 1 --branch n7.1-cuframes \
https://git.goldix.org/gx/ffmpeg-patched.git /src/ffmpeg
# Configure (minimal-but-functional для Frigate)
RUN cd /src/ffmpeg && ./configure \
--prefix=/opt/ffmpeg \
--enable-gpl --enable-version3 --enable-nonfree \
--enable-libcuframes \
--enable-libx264 --enable-libx265 \
--enable-libvpx --enable-libopus --enable-libmp3lame \
--enable-libvorbis --enable-libtheora --enable-libwebp \
--enable-libaom --enable-libdav1d --enable-libsvtav1 \
--enable-libfreetype --enable-libfribidi --enable-libharfbuzz \
--enable-libssh --enable-librist --enable-libsrt \
--enable-openssl \
--enable-ffnvcodec --enable-cuvid --enable-nvenc --enable-nvdec \
--extra-cflags="-I/opt/cuframes/include -I/usr/local/cuda/include" \
--extra-ldflags="-L/opt/cuframes/lib -L/usr/local/cuda/lib64" \
--extra-libs="-lcudart -lpthread -lrt -lm" \
--disable-doc --disable-htmlpages --disable-manpages
RUN cd /src/ffmpeg && make -j"$(nproc)" && make install
# ─── Runtime: Frigate + наши binaries поверх ──────────────────────────
FROM ghcr.io/blakeblackshear/frigate:stable-tensorrt
# Missing dynamic .so которые требует наш patched ffmpeg (Frigate image их не имеет —
# bundled статически собран без них в DT_NEEDED)
RUN apt-get update && apt-get install -y --no-install-recommends \
libharfbuzz0b libfribidi0 librist4 libsrt1.5-openssl libssh-4 \
libvpx7 libwebpmux3 libwebp7 libdav1d6 libaom3 libmp3lame0 \
libsvtav1enc1 libtheora0 libvorbis0a libvorbisenc2 \
libx264-164 libx265-199 libopus0 \
&& rm -rf /var/lib/apt/lists/*
# Replace bundled ffmpeg (оригинал backup'нем под .orig)
RUN cp /usr/lib/ffmpeg/7.0/bin/ffmpeg /usr/lib/ffmpeg/7.0/bin/ffmpeg.orig \
&& cp /usr/lib/ffmpeg/7.0/bin/ffprobe /usr/lib/ffmpeg/7.0/bin/ffprobe.orig
COPY --from=builder /opt/ffmpeg/bin/ffmpeg /usr/lib/ffmpeg/7.0/bin/ffmpeg
COPY --from=builder /opt/ffmpeg/bin/ffprobe /usr/lib/ffmpeg/7.0/bin/ffprobe
COPY --from=builder /opt/cuframes/lib/libcuframes.so.0.1.0 /usr/local/lib/
RUN cd /usr/local/lib && ln -sf libcuframes.so.0.1.0 libcuframes.so.0 \
&& ln -sf libcuframes.so.0 libcuframes.so && ldconfig
# Build-time smoke: ldd resolved + cuframes demuxer registered
RUN ldd /usr/lib/ffmpeg/7.0/bin/ffmpeg | grep -q "not found" && exit 1 || true
RUN /usr/lib/ffmpeg/7.0/bin/ffmpeg -hide_banner -formats | grep -q cuframes \
&& echo "OK: cuframes demuxer registered in Frigate image"
```
Build:
```bash
docker build -t local/frigate-cuframes:latest -f Dockerfile.frigate .
```
Размер ~10 GB (наследует Frigate `stable-tensorrt` ~9 GB).
## Шаг 2 — docker-compose: publisher + Frigate
```yaml
services:
# Один publisher на камеру — единственный source RTSP, делает 1× NVDEC.
cuframes-pub-parking:
image: git.goldix.org/gx/cuframes:0.1 # либо local build из filter/Dockerfile.runtime
container_name: cuframes-pub-parking
restart: unless-stopped
runtime: nvidia
# CRITICAL: ipc=shareable — Frigate и другие consumers подсоединяются через
# ipc: container:cuframes-pub-parking
ipc: shareable
shm_size: 256m
environment:
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
volumes:
- cuframes_sock:/run/cuframes
command:
- /usr/local/bin/cuframes-rtsp-source
- --rtsp
- "rtsp://admin:${CAM_PASS}@cam-parking-ip:554/cam/realmonitor?channel=1&subtype=1"
- --key
- cam-parking
- --ring
- "6"
- --verbose
frigate:
image: local/frigate-cuframes:latest
container_name: frigate
restart: unless-stopped
depends_on:
cuframes-pub-parking:
condition: service_started
runtime: nvidia
privileged: true
shm_size: 512m
# CUDA IPC c publisher'ом: shared /dev/shm
# WARN: pid намерено НЕ share'ится — Frigate использует s6-overlay,
# которое требует PID 1 в своём namespace.
ipc: "container:cuframes-pub-parking"
environment:
FRIGATE_RTSP_PASSWORD: "${FRIGATE_RTSP_PASSWORD}"
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
ports:
- "5000:5000"
- "8971:8971"
volumes:
- cuframes_sock:/run/cuframes:ro
- ./config/config.yml:/config/config.yml:ro
- /home/user/frigate-media:/media/frigate
# ... остальные volumes как обычно
volumes:
cuframes_sock:
```
## Шаг 3 — Frigate config.yml
Ключевые отличия от стандартного config:
```yaml
ffmpeg:
# ВАЖНО: hwaccel cuda отключаем (наш ffmpeg без cuda-llvm → нет scale_cuda).
# Detect-path использует CPU scale, но decode уже done у publisher'а.
hwaccel_args: []
output_args:
record: preset-record-generic-audio-aac
cameras:
parking_overview:
enabled: true
ffmpeg:
inputs:
# main (full-res) — только запись в архив через прямой RTSP
# (decode у Frigate НЕ происходит — это `-c:v copy` мux)
- path: rtsp://admin:${FRIGATE_RTSP_PASSWORD}@cam-parking-ip:554/cam/realmonitor?channel=1&subtype=0
roles: [record]
# sub-stream → через cuframes (decoded у publisher'а, без второго NVDEC у Frigate)
- path: cuframes://cam-parking
input_args: -f cuframes
roles: [detect]
detect:
width: 640
height: 480
fps: 5
```
После v0.2 cuframes (encoded packet sharing) record-path тоже мoжет
переключиться на `cuframes_packets://cam-parking` — тогда **никакого RTSP в
Frigate config'е вообще**.
## Шаг 4 — Run + verify
```bash
docker compose up -d
docker logs -f frigate
```
Что искать в logs:
- `[INFO] Camera processor started for parking_overview` — normal startup
- НЕТ `[ERROR] Ffmpeg process crashed` — если есть, посмотри
[Troubleshooting](#troubleshooting)
- В `nvidia-smi dmon -s u` колонка `%dec` должна показывать ~1-2% на одну
камеру (это publisher), Frigate сам не decode'ит cuframes input
```bash
# Проверить что Frigate реально читает cuframes:
docker exec frigate ps -ef | grep ffmpeg | grep cuframes
# Должна быть линия вида:
# ffmpeg ... -f cuframes -i cuframes://cam-parking -r 5 -vf fps=5,scale=640:480 ...
```
## Troubleshooting
### `s6-overlay-suexec: fatal: can only run as pid 1`
Появляется если попытались добавить `pid: container:cuframes-pub-parking` в
Frigate service. Frigate's s6-overlay strict требует PID 1.
**Fix**: убрать `pid:` из compose. Если только `ipc:` shared — большинство
случаев работают (Frigate подсоединяется первым и его CUDA context служит
для последующих).
**Альтернатива**: запустить Frigate с собственным namespace но дублировать
publisher socket через bind-mount. Frigate сам управляется first CUDA context.
### `[AVFilterGraph] No such filter: 'scale_cuda'`
Frigate config имеет `hwaccel_args: preset-nvidia` (default). Наш patched
ffmpeg собран без `--enable-cuda-llvm` (не работает на glibc < 2.38). Эта
опция компилирует CUDA filters, включая `scale_cuda`.
**Fix**: `hwaccel_args: []` в config.yml. CPU scale (5-10% CPU per FHD25 камера).
**Real fix** (planned): cuframes v0.2 — publisher сам делает resize до detect-size
и публикует pre-scaled frames. Тогда Frigate не нуждается в scale_cuda.
### `cudaIpcOpenEventHandle: invalid device context`
Consumer container не имеет shared pid namespace с publisher'ом → CUDA driver
не валидирует IPC peer.
**Fix для cross-container CUDA IPC**: `pid: container:<publisher>` + `ipc:
container:<publisher>`. Для Frigate этот fix недоступен (см. предыдущий пункт).
Workaround — поднять Frigate первым после publisher (race window) или использовать
encoded packet path (v0.2).
### `Nonmatching transport in server reply` от RTSP-output Frigate
Не относится к cuframes — это нормальное поведение Frigate's go2rtc для
TCP transport. TV/VLC обычно использует UDP — оно работает.
## v0.2: dual-input (detect + record через один RTSP)
После cuframes v0.2 publisher активирует **encoded packet ring** параллельно
с decoded frames ring. Это даёт Frigate одновременно:
- `cuframes://<key>`**decoded NV12** для `detect` role (как в v0.1)
- `cuframes_packets://<key>`**encoded H.264/H.265** для `record` role
(passthrough, без decode)
**1 RTSP connection** к камере вместо 2-3 (Frigate сейчас открывает
отдельный stream для record).
### Setup
```bash
cuframes-rtsp-source \
--rtsp rtsp://admin:pw@192.168.88.98/cam/realmonitor?channel=1 \
--key cam-parking \
--enable-packet-ring
```
Publisher держит **два** SHM:
- `/dev/shm/cuframes-cam-parking` (decoded NV12, v0.1)
- `/dev/shm/cuframes-cam-parking-packets` (encoded packets, v0.2)
### Frigate config
```yaml
cameras:
cam_parking:
ffmpeg:
inputs:
- path: cuframes://cam-parking
input_args: -f cuframes
roles: [detect]
- path: cuframes_packets://cam-parking
input_args: -f cuframes_packets
roles: [record]
```
### Requirements
- Patched FFmpeg с обоими demuxer'ами:
[gx/ffmpeg-patched PR #1](https://git.goldix.org/gx/ffmpeg-patched/pulls/1).
- Frigate Dockerfile перекомпилирован с этим ffmpeg (см. секцию выше про
`cuframes-frigate:0.17` build).
### Trade-offs
| Метрика | v0.1 (frames only) | v0.2 (frames + packets) |
|---|---|---|
| RTSP к камере | 1 (publisher) | 1 (publisher) |
| Frigate-side RTSP | 1+ (record отдельно) | **0** — всё через cuframes |
| Camera RTSP streams | 2+ | **1** |
| Доп. VRAM | ring (~10 MB) | без изменений |
| Доп. host RAM | минимум | + 8 MB на packet ring |
| Доп. CPU | nominal | nominal (memcpy в shared ring) |
## См. также
- [filter/README.md](../../filter/README.md) — детали FFmpeg demuxer + patch
- [docs/integration.md](../integration.md) — общий integration guide
- [docs/protocol.md §10](../protocol.md#10-v02-extension-encoded-packet-ring-proto_version2) — wire-protocol spec для packet ring
- [BENCHMARKS.md](../../BENCHMARKS.md) — production-measured результаты
- [ROADMAP.md](../../ROADMAP.md) — v0.3+ planned features