Files
cuframes/docs/integrations/frigate.md
T
gx 12708618d4 docs: reference integrations + examples
- 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>
2026-05-18 21:37:35 +01:00

14 KiB
Raw Blame History

Frigate integration

Полный production-tested guide для интеграции cuframes с Frigate NVR. На основе реального 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).
  • 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)

# 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:

docker build -t local/frigate-cuframes:latest -f Dockerfile.frigate .

Размер ~10 GB (наследует Frigate stable-tensorrt ~9 GB).

Шаг 2 — docker-compose: publisher + Frigate

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:

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

docker compose up -d
docker logs -f frigate

Что искать в logs:

  • [INFO] Camera processor started for parking_overview — normal startup
  • НЕТ [ERROR] Ffmpeg process crashed — если есть, посмотри Troubleshooting
  • В nvidia-smi dmon -s u колонка %dec должна показывать ~1-2% на одну камеру (это publisher), Frigate сам не decode'ит cuframes input
# Проверить что 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 — оно работает.

См. также