docs+docker: integration guide и runtime image для Frigate/cctv stack
docs/integration.md — детальный guide для интеграции в существующий CCTV docker-compose: критичные требования (ipc=shareable/container, общий shared volume для socket), пример CuframesSource для cctv-processor, verification checklist, troubleshooting (timeout, ipc namespace mismatch, high latency). Зафиксировано: v0.1 frigate-decode не убирается без patch'а FFmpeg — это v0.2 scope. docker/Dockerfile.runtime — multi-stage build (devel → runtime), копирует libcuframes.so + cuframes-rtsp-source + sub_count в /usr/local. Образ ~700 MB (vs ~7 GB у dev'а). Smoke-test: бинарки запускаются, ldd видит все нужные libs. docker-compose.example.yml — reference docker-compose с правильным ipc mode и volume mounts для копирования в свои проекты. .dockerignore — исключает build/ и build-*/ из COPY context. README обновлён: статус v0.1 done, quickstart с реальным docker run, ссылка на integration guide.
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
# Build artefacts — генерируются заново внутри образа
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
out/
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
CMakeFiles/
|
||||||
|
CMakeCache.txt
|
||||||
|
CTestTestfile.cmake
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# IDE / OS
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Local secrets
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# FFmpeg (если когда-то распакован)
|
||||||
|
third_party/ffmpeg/
|
||||||
|
ffmpeg-*/
|
||||||
|
|
||||||
|
# Sentinel files
|
||||||
|
*.pid
|
||||||
|
*.sock
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
Zero-copy sharing декодированных видеокадров между процессами через CUDA IPC.
|
Zero-copy sharing декодированных видеокадров между процессами через CUDA IPC.
|
||||||
|
|
||||||
**Статус:** ⚠️ Design phase. Дизайн-спецификация готова, реализация в процессе.
|
**Статус:** v0.1 — libcuframes готов, cuframes-rtsp-source готов, e2e-pipeline
|
||||||
|
протестирован (4×subscriber × 2000 frames, 0 torn). FFmpeg filter — v0.2.
|
||||||
**Лицензия:** LGPL-2.1+
|
**Лицензия:** LGPL-2.1+
|
||||||
|
|
||||||
## Минимальные требования
|
## Минимальные требования
|
||||||
@@ -46,37 +47,51 @@ Camera ─► ffmpeg + cuframes filter ─► VRAM ─┬─► consumer 1 (NVR)
|
|||||||
|
|
||||||
## Состав
|
## Состав
|
||||||
|
|
||||||
- **FFmpeg filter `cuda_ipc_export`** — добавляется в любой ffmpeg-pipeline
|
- **`libcuframes`** — C library + C++ RAII wrapper (header-only) для producer/consumer
|
||||||
- **`libcuframes`** — C library + C++/Python bindings для consumers
|
- **`cuframes-rtsp-source`** — standalone bridge RTSP → cuframes IPC (используется
|
||||||
- **Docker images** — drop-in replacement для существующих setups (включая Frigate)
|
как input для AI/mosaic consumer'ов; альтернатива FFmpeg-filter'а до v0.2)
|
||||||
|
- **`sub_count`** (examples/) — reference subscriber + smoke-test tool
|
||||||
|
- **Docker images** — runtime для drop-in deployment (см. docker/Dockerfile.runtime)
|
||||||
|
- **FFmpeg filter `cuda_ipc_export`** — *planned для v0.2*
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
> 🚧 в разработке
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Producer (после v0.1)
|
# Publisher: декодирует RTSP в CUDA, публикует через cuframes IPC
|
||||||
docker run --gpus all -v /run/cuframes:/run/cuframes ghcr.io/<org>/cuframes-ffmpeg:N \
|
docker run -d --name cuframes-cam --runtime=nvidia --ipc=shareable \
|
||||||
ffmpeg -hwaccel cuda -i rtsp://camera/stream \
|
-v /run/cuframes:/run/cuframes \
|
||||||
-vf "scale_cuda=1920:1080,cuda_ipc_export=key=cam1" \
|
gx/cuframes:0.1 \
|
||||||
-c:v copy -f segment recording.mp4
|
/usr/local/bin/cuframes-rtsp-source \
|
||||||
|
--rtsp 'rtsp://user:pass@cam/stream' --key cam1 --ring 6
|
||||||
|
|
||||||
# Consumer (C++)
|
# Subscriber: получает декодированные frames zero-copy
|
||||||
#include <cuframes.hpp>
|
docker run --rm --runtime=nvidia --ipc=container:cuframes-cam \
|
||||||
cuframes::Subscriber sub("cam1");
|
-v /run/cuframes:/run/cuframes:ro \
|
||||||
while (auto frame = sub.next()) {
|
gx/cuframes:0.1 \
|
||||||
// frame->cuda_ptr — device pointer, zero-copy
|
/usr/local/bin/sub_count --key cam1 --max-frames 100
|
||||||
process_on_cuda(frame->cuda_ptr, frame->width, frame->height);
|
|
||||||
|
# Или C++ кодом:
|
||||||
|
#include <cuframes/cuframes.hpp>
|
||||||
|
cuframes::SubscriberOptions opt;
|
||||||
|
opt.key = "cam1";
|
||||||
|
cuframes::Subscriber sub(opt);
|
||||||
|
cudaStream_t s; cudaStreamCreate(&s);
|
||||||
|
while (auto frame = sub.next(s, 1000)) { // 1s timeout
|
||||||
|
cudaStreamSynchronize(s);
|
||||||
|
process_on_cuda(frame->cuda_ptr(), frame->width(), frame->height());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Полный integration guide** (docker-compose, cctv-processor, troubleshooting):
|
||||||
|
[docs/integration.md](docs/integration.md).
|
||||||
|
|
||||||
## Документация
|
## Документация
|
||||||
|
|
||||||
- [docs/architecture.md](docs/architecture.md) — полный design document
|
- [docs/architecture.md](docs/architecture.md) — полный design document
|
||||||
- [docs/protocol.md](docs/protocol.md) — bit-exact wire protocol spec
|
- [docs/protocol.md](docs/protocol.md) — bit-exact wire protocol spec
|
||||||
- [docs/requirements.md](docs/requirements.md) — system requirements (hardware, software, build, Docker, k8s)
|
- [docs/requirements.md](docs/requirements.md) — system requirements (hardware, software, build, Docker, k8s)
|
||||||
|
- [docs/integration.md](docs/integration.md) — **integration guide** для CCTV-стека (cuframes-rtsp-source + cctv-processor + Frigate)
|
||||||
- [docs/benchmarks-phase0.md](docs/benchmarks-phase0.md) — Phase 0 latency/throughput measurements
|
- [docs/benchmarks-phase0.md](docs/benchmarks-phase0.md) — Phase 0 latency/throughput measurements
|
||||||
- [docs/quickstart.md](docs/quickstart.md) — *(в разработке)*
|
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
@@ -88,15 +103,16 @@ NVIDIA DeepStream закрытые / vendor-locked. Open source FFmpeg-plugin д
|
|||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
| Phase | Что | Срок |
|
| Phase | Что | Статус |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 0 | PoC spike, CUDA IPC latency measurements | 3 дня |
|
| 0 | PoC spike, CUDA IPC latency measurements | ✅ done |
|
||||||
| 1 | `libcuframes` (producer/consumer ring buffer + handshake protocol) | 1 неделя |
|
| 1 | `libcuframes` (producer/consumer ring buffer + handshake protocol) | ✅ done |
|
||||||
| 2 | FFmpeg filter `vf_cuda_ipc_export` + patched FFmpeg build | 1-2 недели |
|
| 1.5 | C++ RAII wrapper, cuframes-rtsp-source, integration docs | ✅ done |
|
||||||
| 3 | C++ / Python bindings | 1 неделя |
|
| 2 | FFmpeg filter `vf_cuda_ipc_input` + patched FFmpeg build | planned |
|
||||||
| 4 | Docker packaging + Frigate drop-in image | 3-5 дней |
|
| 3 | Python bindings (pybind11) | planned |
|
||||||
| 5 | Reference consumer: 16-камерный mosaic compositor | 1 неделя |
|
| 4 | Docker runtime-images в реестре, Frigate plugin POC | planned |
|
||||||
| 6 | OSS launch (HN, reddit, FFmpeg upstream PR) | 3-5 дней |
|
| 5 | Reference: 16-камерный mosaic consumer | planned |
|
||||||
|
| 6 | OSS launch (HN, reddit, FFmpeg upstream PR) | planned |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Пример docker-compose для cuframes intergration в CCTV-стек.
|
||||||
|
#
|
||||||
|
# Запуск:
|
||||||
|
# export CAM_PASS=your_camera_password
|
||||||
|
# docker compose -f docker-compose.example.yml up
|
||||||
|
#
|
||||||
|
# Этот файл — REFERENCE для adaptации в boost проектах (cctv, frigate stack).
|
||||||
|
# Не для production без review.
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Источник: декодирует RTSP в CUDA, публикует через cuframes IPC
|
||||||
|
cuframes-cam-test:
|
||||||
|
# Локальный build из этого репо
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/Dockerfile.runtime
|
||||||
|
image: gx/cuframes:0.1
|
||||||
|
container_name: cuframes-cam-test
|
||||||
|
restart: unless-stopped
|
||||||
|
runtime: nvidia
|
||||||
|
environment:
|
||||||
|
NVIDIA_VISIBLE_DEVICES: all
|
||||||
|
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
|
||||||
|
# CRITICAL: ipc=shareable — позволяет другим контейнерам joinиться через
|
||||||
|
# `ipc: container:cuframes-cam-test`
|
||||||
|
ipc: shareable
|
||||||
|
shm_size: 1g
|
||||||
|
volumes:
|
||||||
|
- cuframes_sock:/run/cuframes
|
||||||
|
command:
|
||||||
|
- /usr/local/bin/cuframes-rtsp-source
|
||||||
|
- --rtsp=rtsp://admin:${CAM_PASS}@192.168.88.98:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
- --key=cam-test
|
||||||
|
- --ring=6
|
||||||
|
- --verbose
|
||||||
|
|
||||||
|
# Потребитель: счётчик frames (smoke-test consumer)
|
||||||
|
cuframes-sub-test:
|
||||||
|
image: gx/cuframes:0.1
|
||||||
|
container_name: cuframes-sub-test
|
||||||
|
depends_on:
|
||||||
|
- cuframes-cam-test
|
||||||
|
restart: "no"
|
||||||
|
runtime: nvidia
|
||||||
|
environment:
|
||||||
|
NVIDIA_VISIBLE_DEVICES: all
|
||||||
|
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
|
||||||
|
# CRITICAL: ipc namespace должен совпадать с publisher'ом
|
||||||
|
ipc: "container:cuframes-cam-test"
|
||||||
|
volumes:
|
||||||
|
- cuframes_sock:/run/cuframes:ro
|
||||||
|
command:
|
||||||
|
- /usr/local/bin/sub_count
|
||||||
|
- --key=cam-test
|
||||||
|
- --max-frames=500
|
||||||
|
- --verbose
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
cuframes_sock:
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Runtime-образ для cuframes — содержит:
|
||||||
|
# - libcuframes.so (built из dev-stage)
|
||||||
|
# - cuframes-rtsp-source bin
|
||||||
|
# - sub_count example bin
|
||||||
|
# - минимальный CUDA runtime + ffmpeg libs (без nvcc и headers)
|
||||||
|
#
|
||||||
|
# Не для разработки! Для dev — docker/Dockerfile.dev.
|
||||||
|
#
|
||||||
|
# Build:
|
||||||
|
# docker build -f docker/Dockerfile.runtime -t gx/cuframes:0.1 .
|
||||||
|
#
|
||||||
|
# Run (publisher):
|
||||||
|
# docker run --rm -it --runtime=nvidia --ipc=shareable \
|
||||||
|
# -v cuframes_sock:/run/cuframes \
|
||||||
|
# gx/cuframes:0.1 \
|
||||||
|
# /usr/local/bin/cuframes-rtsp-source --rtsp ... --key ...
|
||||||
|
|
||||||
|
# ─── Build stage ─────────────────────────────────────────────────────────
|
||||||
|
FROM nvidia/cuda:13.0.3-cudnn-devel-ubuntu24.04 AS build
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
build-essential cmake ninja-build pkg-config \
|
||||||
|
libavcodec-dev libavformat-dev libavutil-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY . /src
|
||||||
|
RUN cmake -B build -S . -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_TESTING=OFF \
|
||||||
|
-DBUILD_EXAMPLES=ON \
|
||||||
|
-DBUILD_TOOLS=ON \
|
||||||
|
-DBUILD_PYTHON_BINDINGS=OFF \
|
||||||
|
-DBUILD_FFMPEG_FILTER=OFF \
|
||||||
|
&& cmake --build build --parallel
|
||||||
|
|
||||||
|
# ─── Runtime stage ────────────────────────────────────────────────────────
|
||||||
|
FROM nvidia/cuda:13.0.3-cudnn-runtime-ubuntu24.04 AS runtime
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libavcodec60 libavformat60 libavutil58 \
|
||||||
|
ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# libcuframes.so → /usr/local/lib (стандартный путь для ldconfig)
|
||||||
|
COPY --from=build /src/build/libcuframes/libcuframes.so* /usr/local/lib/
|
||||||
|
COPY --from=build /src/include/cuframes /usr/local/include/cuframes
|
||||||
|
COPY --from=build /src/build/tools/cuframes-rtsp-source/cuframes-rtsp-source \
|
||||||
|
/usr/local/bin/
|
||||||
|
COPY --from=build /src/build/examples/sub_count/sub_count \
|
||||||
|
/usr/local/bin/
|
||||||
|
|
||||||
|
RUN ldconfig
|
||||||
|
|
||||||
|
# Default — print help, чтобы случайный `docker run` показал что это
|
||||||
|
CMD ["/usr/local/bin/cuframes-rtsp-source", "--help"]
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
# Integration guide
|
||||||
|
|
||||||
|
Этот guide описывает, как использовать cuframes для устранения дублирующего
|
||||||
|
GPU-декодирования между несколькими consumer'ами одного RTSP-потока.
|
||||||
|
|
||||||
|
## Целевой сценарий (motivation)
|
||||||
|
|
||||||
|
В типичной CCTV-системе один и тот же RTSP-stream декодируется несколько раз:
|
||||||
|
|
||||||
|
```
|
||||||
|
Камера ──► RTSP ──► Frigate (decode #1: detection + recording)
|
||||||
|
─► mosaic-сервер (decode #2: компоновка сетки)
|
||||||
|
─► AI-скрипт (decode #3: классификация / OCR)
|
||||||
|
```
|
||||||
|
|
||||||
|
На 16 камер × 25 fps × 3 consumer'а = 1200 NVDEC-операций/сек. RTX 5090 имеет
|
||||||
|
~3 NVDEC-движка, но шина PCIe и memory bandwidth становятся узким местом.
|
||||||
|
|
||||||
|
С cuframes:
|
||||||
|
|
||||||
|
```
|
||||||
|
Камера ──► cuframes-rtsp-source ──► CUDA frame в /dev/shm + cudaIpcEvent
|
||||||
|
│
|
||||||
|
├──► Frigate (zero-copy)
|
||||||
|
├──► mosaic-сервер (zero-copy)
|
||||||
|
└──► AI-скрипт (zero-copy)
|
||||||
|
```
|
||||||
|
|
||||||
|
Decode выполняется **один раз** на источник, потребители получают тот же CUDA
|
||||||
|
device pointer без копий.
|
||||||
|
|
||||||
|
## Текущие limitations v0.1
|
||||||
|
|
||||||
|
- **Frigate** (по состоянию на 0.17) **не имеет** plugin-точки для приёма
|
||||||
|
готовых CUDA-frames. Чтобы убрать Frigate decode полностью, нужен:
|
||||||
|
- либо FFmpeg-filter `vf_cuda_ipc_input` (planned для cuframes v0.2 — требует
|
||||||
|
patch FFmpeg upstream и пересборку Frigate's bundled ffmpeg),
|
||||||
|
- либо Frigate-plugin (требует upstream работы с командой Frigate).
|
||||||
|
- В v0.1 практическое улучшение: **исключить decode для всех custom consumer'ов
|
||||||
|
кроме Frigate** (то есть cctv-processor, AI-скрипты — на cuframes; Frigate
|
||||||
|
остаётся как есть, со своим decode).
|
||||||
|
|
||||||
|
Это уже даёт значительную экономию: было 1×Frigate + N×consumer decode'ов,
|
||||||
|
стало 1×Frigate + 1×cuframes-rtsp-source (один на все consumer'ы).
|
||||||
|
|
||||||
|
## Сценарий 1: cuframes-rtsp-source + cctv-processor (FRIGATE остаётся)
|
||||||
|
|
||||||
|
### docker-compose.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
# Один источник на камеру — публикует декодированный поток через cuframes IPC
|
||||||
|
cuframes-cam-parking:
|
||||||
|
image: gx/cuframes-rtsp-source:0.1
|
||||||
|
restart: unless-stopped
|
||||||
|
runtime: nvidia
|
||||||
|
environment:
|
||||||
|
NVIDIA_VISIBLE_DEVICES: all
|
||||||
|
NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
|
||||||
|
# CRITICAL: --ipc=shareable для cross-container CUDA IPC
|
||||||
|
ipc: shareable
|
||||||
|
shm_size: 1g
|
||||||
|
volumes:
|
||||||
|
- cuframes_sock:/run/cuframes
|
||||||
|
command:
|
||||||
|
- --rtsp=rtsp://admin:${CAM_PASS}@192.168.88.98:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
- --key=cam-parking
|
||||||
|
- --ring=6
|
||||||
|
- --realtime # не нужен для RTSP (real-time источник), оставлен для file://
|
||||||
|
|
||||||
|
# Frigate (как и был — со своим decode на main+sub streams)
|
||||||
|
frigate:
|
||||||
|
image: ghcr.io/blakeblackshear/frigate:stable-tensorrt
|
||||||
|
# ... как обычно
|
||||||
|
|
||||||
|
# cctv-processor — подписывается на cuframes (без отдельного RTSP decode)
|
||||||
|
cctv-backend:
|
||||||
|
image: gx/cctv-processor:cuda
|
||||||
|
restart: unless-stopped
|
||||||
|
runtime: nvidia
|
||||||
|
# CRITICAL: --ipc=container:cuframes-cam-parking для shared CUDA context
|
||||||
|
ipc: container:cuframes-cam-parking
|
||||||
|
volumes:
|
||||||
|
- cuframes_sock:/run/cuframes:ro
|
||||||
|
environment:
|
||||||
|
# cuframes-keys для backend'а:
|
||||||
|
CCTV_SOURCES: cuframes:cam-parking,cuframes:cam-front-gate,...
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
cuframes_sock:
|
||||||
|
```
|
||||||
|
|
||||||
|
**Важно**: все consumer'ы должны использовать **тот же** `ipc:` namespace, что
|
||||||
|
и publisher (через `ipc: container:<publisher_container>`). Это нужно для того,
|
||||||
|
чтобы cudaIpcOpenMemHandle / cudaIpcOpenEventHandle работали корректно.
|
||||||
|
|
||||||
|
### Изменения в cctv-processor
|
||||||
|
|
||||||
|
Нужно добавить новый Source-тип (рядом с RtspSource) — `CuframesSource`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// cpp/apps/cctv-processor/src/sources/cuframes_source.hpp
|
||||||
|
#include <cuframes/cuframes.hpp>
|
||||||
|
|
||||||
|
class CuframesSource : public IVideoSource {
|
||||||
|
public:
|
||||||
|
CuframesSource(const std::string &key) : key_(key) {
|
||||||
|
cuframes::SubscriberOptions opt;
|
||||||
|
opt.key = key;
|
||||||
|
opt.consumer_name = "cctv-processor";
|
||||||
|
opt.mode = CUFRAMES_MODE_NEWEST_ONLY;
|
||||||
|
sub_ = std::make_unique<cuframes::Subscriber>(opt);
|
||||||
|
cudaStreamCreate(&stream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вызывается processing-loop'ом
|
||||||
|
std::optional<GpuFrame> nextFrame() override {
|
||||||
|
auto f = sub_->next(stream_, 100); // 100ms timeout
|
||||||
|
if (!f) return std::nullopt;
|
||||||
|
// cudaStreamWaitEvent уже сделан внутри next() — frame готов на stream_
|
||||||
|
return GpuFrame{
|
||||||
|
.cuda_ptr = f->cuda_ptr(),
|
||||||
|
.width = f->width(),
|
||||||
|
.height = f->height(),
|
||||||
|
.pitch_y = f->pitch_y(),
|
||||||
|
.pitch_uv = f->pitch_uv(),
|
||||||
|
.seq = f->seq(),
|
||||||
|
.pts_ns = f->pts_ns(),
|
||||||
|
.stream = stream_,
|
||||||
|
._release = std::move(f), // RAII release при destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string key_;
|
||||||
|
std::unique_ptr<cuframes::Subscriber> sub_;
|
||||||
|
cudaStream_t stream_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Конфиг `cameras.json` — добавить альтернативный source-тип:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"cameras": [
|
||||||
|
{
|
||||||
|
"id": "parking",
|
||||||
|
"source_type": "cuframes", // вместо "rtsp"
|
||||||
|
"cuframes_key": "cam-parking",
|
||||||
|
// rtsp_url больше не нужен — он используется cuframes-rtsp-source'ом
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Сценарий 2: AI-скрипт на Python (subscriber)
|
||||||
|
|
||||||
|
Python-bindings — в Phase 3 cuframes. Сейчас простой workaround через
|
||||||
|
ctypes:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import ctypes
|
||||||
|
lib = ctypes.CDLL("libcuframes.so")
|
||||||
|
# ... wrap нужные функции — см. include/cuframes/cuframes.h
|
||||||
|
```
|
||||||
|
|
||||||
|
Или: writer simple C-обёртку, которая принимает callback и публикует
|
||||||
|
данные через ZMQ / shared memory в python-process.
|
||||||
|
|
||||||
|
## Сценарий 3: Замена Frigate decode (v0.2+)
|
||||||
|
|
||||||
|
Целевой сценарий — Frigate тоже подписан на cuframes. Реализуется через
|
||||||
|
один из двух путей:
|
||||||
|
|
||||||
|
### Путь A: FFmpeg filter
|
||||||
|
|
||||||
|
Добавить out-of-tree filter `vf_cuda_ipc_input` который читает кадр из
|
||||||
|
cuframes ring и эмитит AVFrame в pipeline. Frigate использует ffmpeg для
|
||||||
|
RTSP/decode — заменяем "RTSP→decode→detect" на
|
||||||
|
"cuframes_ipc_input→detect" (без decode'а вообще).
|
||||||
|
|
||||||
|
Требования:
|
||||||
|
- Patch ffmpeg sources (libavfilter/vf_cuda_ipc_input.c + Makefile)
|
||||||
|
- Сборка кастомного Frigate-образа с patched ffmpeg
|
||||||
|
- Тестирование на совместимость с Frigate's pipeline assumptions
|
||||||
|
|
||||||
|
### Путь B: Frigate plugin
|
||||||
|
|
||||||
|
Engage с upstream Frigate чтобы добавить custom Source-type ("cuframes://").
|
||||||
|
Это требует Python-API изменений в Frigate's source layer.
|
||||||
|
|
||||||
|
## Verification checklist
|
||||||
|
|
||||||
|
После настройки убедитесь:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Publisher запущен и socket существует
|
||||||
|
ls -la /run/cuframes/cam-parking.sock
|
||||||
|
ls -la /dev/shm/cuframes-cam-parking
|
||||||
|
|
||||||
|
# 2. Контейнеры в одном IPC namespace
|
||||||
|
docker inspect cuframes-cam-parking cctv-backend -f '{{.HostConfig.IpcMode}}'
|
||||||
|
# Должно быть "shareable" для publisher и "container:cuframes-cam-parking" для consumer
|
||||||
|
|
||||||
|
# 3. Subscriber connect успешен
|
||||||
|
docker exec cctv-backend /usr/local/bin/sub_count --key cam-parking --max-frames 10
|
||||||
|
# Ожидаем:
|
||||||
|
# [sub_count] connected to 'cuframes-cam-parking'
|
||||||
|
# [sub_count] received=10 gaps=0 elapsed=0.4s avg_fps=25
|
||||||
|
|
||||||
|
# 4. NVDEC utilization — должно быть N decodes, а не N*M
|
||||||
|
nvidia-smi dmon -s u
|
||||||
|
# Колонка %dec должна показать decode-нагрузку одного instance на камеру
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `Subscriber::create: timeout`
|
||||||
|
Subscriber не нашёл publisher. Причины:
|
||||||
|
- Publisher не запущен или crashed — проверь `docker logs cuframes-cam-parking`
|
||||||
|
- Socket-файл не volumes'нут в consumer-контейнер — добавь `volumes:
|
||||||
|
- cuframes_sock:/run/cuframes:ro` в consumer'е
|
||||||
|
- IPC namespace не совпадает — см. checklist пункт 2
|
||||||
|
|
||||||
|
### `cudaIpcOpenMemHandle returned 'invalid device pointer'`
|
||||||
|
- Контейнеры в РАЗНЫХ ipc namespace — должны быть в одном (через
|
||||||
|
`ipc: container:<publisher>` или общий `ipc: shareable`)
|
||||||
|
- Subscriber работает на другом CUDA device — `--cuda-device` должен совпадать
|
||||||
|
у publisher и subscriber (одно и то же физическое GPU)
|
||||||
|
|
||||||
|
### Высокая latency (>50ms tail)
|
||||||
|
- Subscriber slow — frames копятся в ring, по политике DROP_OLDEST они
|
||||||
|
пропускаются. Используй `CUFRAMES_MODE_NEWEST_ONLY` (default) — это нормально
|
||||||
|
для real-time системы.
|
||||||
|
- При STRICT_ORDER + STRICT_WAIT — slow consumer блокирует publisher. Не
|
||||||
|
рекомендуется для CCTV.
|
||||||
|
|
||||||
|
### Frigate показывает чёрный экран после интеграции
|
||||||
|
- Frigate не подключён к cuframes (v0.1 — это not yet supported). В v0.1
|
||||||
|
Frigate должен оставаться на своём RTSP decode (см. Сценарий 1).
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
- **v0.1** (текущая): standalone publisher/subscriber, C/C++ API, examples.
|
||||||
|
- **v0.2**: FFmpeg filter `vf_cuda_ipc_input` (out-of-tree), Python bindings.
|
||||||
|
- **v0.3**: NVENC-bridge для re-encode подписчиков, Frigate plugin
|
||||||
|
proof-of-concept.
|
||||||
|
- **v1.0**: stable ABI, multi-GPU, documented Frigate integration.
|
||||||
Reference in New Issue
Block a user