12708618d4
- docs/integrations/frigate.md — полный production-tested guide: Dockerfile, docker-compose, config.yml, troubleshooting (s6+pid, scale_cuda, hwaccel issues), build steps - docs/integrations/cctv-cpp.md — C++ pattern: IFrameSource interface + CuframesSource skeleton + CMake setup + runtime requirements - examples/frigate-compose/ — reference compose stack (cuframes-pub + Frigate) с config.yml stub, .env.example, README - examples/python-consumer/ — ctypes-based skeleton для AI/ML pipeline'ов (до v0.3 native pybind11 bindings) - docs/integration.md — превратился в index-страницу, ссылается на specific guides Reorganization упрощает onboarding: пользователь выбирает guide по типу integration'а (Frigate/C++/Python/FFmpeg) и сразу видит реальный code. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
306 lines
14 KiB
Markdown
306 lines
14 KiB
Markdown
# 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 — оно работает.
|
||
|
||
## См. также
|
||
|
||
- [filter/README.md](../../filter/README.md) — детали FFmpeg demuxer + patch
|
||
- [docs/integration.md](../integration.md) — общий integration guide
|
||
- [BENCHMARKS.md](../../BENCHMARKS.md) — production-measured результаты
|
||
- [ROADMAP.md](../../ROADMAP.md) — v0.2 что улучшит для Frigate
|