feat(filter): FFmpeg 7.1 cuframes:// input demuxer (PoC v1) #1

Merged
gx merged 1 commits from feat/ffmpeg-demuxer into main 2026-05-17 09:08:09 +01:00
Owner

Что делает

Out-of-tree patch для FFmpeg 7.1, добавляющий новый input format
cuframes://<key>. Любой FFmpeg-based потребитель (Frigate, кастомные
рекордеры, re-streamers) теперь может подписаться на уже декодированные
кадры от cuframes-rtsp-source через
обычный URL — без своего NVDEC pass.

Камера ──RTSP──► cuframes-rtsp-source (1× NVDEC decode)
                       │
                       ├─► cuframes://cam-X (CUDA IPC)
                             ├─► ffmpeg / Frigate (через этот demuxer)
                             ├─► cctv-processor (CuframesSource)
                             └─► AI-script (ctypes)

Это шаг к v0.2 cuframes из roadmap (FFmpeg-side integration без форка
Frigate).

Состав

Файл Что
filter/cuframesdec.c Реализация demuxer'а (libavformat-style): read_header подключается к publisher'у и кеширует 1-й frame для определения размеров; read_packet копирует NV12 GPU → CPU через cudaMemcpy2DAsync + выдаёт AVPacket
filter/ffmpeg-7.1-cuframes-demuxer.patch 332-строчный patch для FFmpeg n7.1: правит libavformat/Makefile, libavformat/allformats.c, configure (--enable-libcuframes); кладёт cuframesdec.c в libavformat/
filter/README.md Инструкции по сборке patched FFmpeg + CLI smoke test + план интеграции с Frigate

Limitations v1 (намеренно)

  • Только NV12 (нативный формат NVDEC)
  • GPU → CPU копия через cudaMemcpy2DAsync (для PoC совместимости со всеми
    FFmpeg pipeline'ами). Zero-copy через AVHWFramesContext — запланировано
    в v2
  • Один input = один stream

Главный выигрыш v1 всё равно достигнут: 1× NVDEC у publisher'а на N
consumer'ов
вместо N× NVDEC.

Опции

-cuda_device       <int>  CUDA device index (must match publisher's). Default 0.
-connect_timeout   <int>  Wait for publisher (ms); -1 = forever. Default 5000.

CLI smoke test (прошёл)

2026-05-17, host build FFmpeg 7.1 patched + libcuframes 0.1, publisher на
камере 192.168.88.98 (1920×1080 HEVC 25fps):

$ ffmpeg -f cuframes -i cuframes://cam-ff -c:v copy -f null -
[cuframes @ ...] cuframes: connected to 'cam-ff' — 1920x1080 NV12
Stream #0:0: Video: rawvideo (NV12 / 0x3231564E), nv12, 1920x1080, 1000k tbr
...
frame=  100 fps= 25 q=-1.0 size=N/A time=00:00:03.96 speed=1x

speed=1x = pipeline в реальном времени с частотой камеры, 0 drops.

Frigate integration (план, не в этом PR)

После пересборки Frigate image с patched FFmpeg в config.yml:

cameras:
  cam_parking:
    ffmpeg:
      inputs:
        - path: cuframes://cam-parking      # detect через cuframes (без своего NVDEC)
          roles: [detect]
        - path: rtsp://admin:***@cam/main   # recording — прямой RTSP (mux без decode)
          roles: [record]

Detect-стрим декодируется один раз в publisher'е, recording продолжает
mux'иться Frigate'ом из encoded RTSP без декода (как сейчас).

Не входит в PR: Dockerfile-патч самого Frigate image (тяжёлая сборка
с CUDA + TensorRT base, требует много трафика и build-времени; делается
отдельным PR в инфраструктурном репо).

Зависимости

  • FFmpeg n7.1 (для precise patch; на других 7.x может потребоваться minor
    adjust в allformats.c / configure offset'ах)
  • libcuframes ≥ 0.1 (из этого же repo)
  • CUDA runtime (cudart) — для cudaMemcpy2D* функций

Roadmap v2+

  • Zero-copy через AVHWFramesContext (NV12 остаётся в VRAM весь pipeline)
  • Forматы кроме NV12 (YUV420P, RGB)
  • pkg-config .pc файл для libcuframes (вместо ручных --extra-cflags/--extra-ldflags)
  • Подача upstream PR в FFmpeg (после стабилизации API)

Checklist

  • Demuxer регистрируется (ffmpeg -formats | grep cuframes)
  • Опции видны (ffmpeg -h demuxer=cuframes)
  • CLI smoke test на реальной камере — 100/100 frames, speed=1×
  • Cleanup pipeline (read_close освобождает CUDA stream + host buffer + subscriber)
  • README с инструкцией apply patch + build + Frigate plan
  • Frigate image rebuild (отдельный PR)
  • Zero-copy v2 (отдельный PR)
## Что делает Out-of-tree patch для **FFmpeg 7.1**, добавляющий новый input format `cuframes://<key>`. Любой FFmpeg-based потребитель (Frigate, кастомные рекордеры, re-streamers) теперь может подписаться на уже декодированные кадры от [`cuframes-rtsp-source`](../tools/cuframes-rtsp-source/) через обычный URL — **без своего NVDEC pass**. ``` Камера ──RTSP──► cuframes-rtsp-source (1× NVDEC decode) │ ├─► cuframes://cam-X (CUDA IPC) ├─► ffmpeg / Frigate (через этот demuxer) ├─► cctv-processor (CuframesSource) └─► AI-script (ctypes) ``` Это шаг к **v0.2 cuframes** из roadmap (FFmpeg-side integration без форка Frigate). ## Состав | Файл | Что | |---|---| | `filter/cuframesdec.c` | Реализация demuxer'а (libavformat-style): `read_header` подключается к publisher'у и кеширует 1-й frame для определения размеров; `read_packet` копирует NV12 GPU → CPU через `cudaMemcpy2DAsync` + выдаёт `AVPacket` | | `filter/ffmpeg-7.1-cuframes-demuxer.patch` | 332-строчный patch для FFmpeg n7.1: правит `libavformat/Makefile`, `libavformat/allformats.c`, `configure` (`--enable-libcuframes`); кладёт `cuframesdec.c` в `libavformat/` | | `filter/README.md` | Инструкции по сборке patched FFmpeg + CLI smoke test + план интеграции с Frigate | ## Limitations v1 (намеренно) - **Только NV12** (нативный формат NVDEC) - **GPU → CPU копия** через `cudaMemcpy2DAsync` (для PoC совместимости со всеми FFmpeg pipeline'ами). Zero-copy через `AVHWFramesContext` — запланировано в v2 - Один input = один stream Главный выигрыш v1 всё равно достигнут: **1× NVDEC у publisher'а на N consumer'ов** вместо N× NVDEC. ## Опции ``` -cuda_device <int> CUDA device index (must match publisher's). Default 0. -connect_timeout <int> Wait for publisher (ms); -1 = forever. Default 5000. ``` ## CLI smoke test (прошёл) 2026-05-17, host build FFmpeg 7.1 patched + libcuframes 0.1, publisher на камере 192.168.88.98 (1920×1080 HEVC 25fps): ``` $ ffmpeg -f cuframes -i cuframes://cam-ff -c:v copy -f null - [cuframes @ ...] cuframes: connected to 'cam-ff' — 1920x1080 NV12 Stream #0:0: Video: rawvideo (NV12 / 0x3231564E), nv12, 1920x1080, 1000k tbr ... frame= 100 fps= 25 q=-1.0 size=N/A time=00:00:03.96 speed=1x ``` `speed=1x` = pipeline в реальном времени с частотой камеры, 0 drops. ## Frigate integration (план, не в этом PR) После пересборки Frigate image с patched FFmpeg в `config.yml`: ```yaml cameras: cam_parking: ffmpeg: inputs: - path: cuframes://cam-parking # detect через cuframes (без своего NVDEC) roles: [detect] - path: rtsp://admin:***@cam/main # recording — прямой RTSP (mux без decode) roles: [record] ``` Detect-стрим декодируется один раз в publisher'е, recording продолжает mux'иться Frigate'ом из encoded RTSP без декода (как сейчас). **Не входит в PR**: Dockerfile-патч самого Frigate image (тяжёлая сборка с CUDA + TensorRT base, требует много трафика и build-времени; делается отдельным PR в инфраструктурном репо). ## Зависимости - FFmpeg n7.1 (для precise patch; на других 7.x может потребоваться minor adjust в `allformats.c` / `configure` offset'ах) - libcuframes ≥ 0.1 (из этого же repo) - CUDA runtime (cudart) — для `cudaMemcpy2D*` функций ## Roadmap v2+ - Zero-copy через `AVHWFramesContext` (NV12 остаётся в VRAM весь pipeline) - Forматы кроме NV12 (YUV420P, RGB) - pkg-config `.pc` файл для libcuframes (вместо ручных `--extra-cflags`/`--extra-ldflags`) - Подача upstream PR в FFmpeg (после стабилизации API) ## Checklist - [x] Demuxer регистрируется (`ffmpeg -formats | grep cuframes`) - [x] Опции видны (`ffmpeg -h demuxer=cuframes`) - [x] CLI smoke test на реальной камере — 100/100 frames, speed=1× - [x] Cleanup pipeline (read_close освобождает CUDA stream + host buffer + subscriber) - [x] README с инструкцией apply patch + build + Frigate plan - [ ] Frigate image rebuild (отдельный PR) - [ ] Zero-copy v2 (отдельный PR)
gx added 1 commit 2026-05-17 09:03:32 +01:00
Out-of-tree patch + sources для FFmpeg-демаксера, который позволяет любому
FFmpeg-based потребителю (Frigate, кастомные рекордеры, re-streamers)
читать "cuframes://<key>" как обычный URL — без своего NVDEC.

Состав:
- filter/cuframesdec.c — реализация (libavformat-style)
- filter/ffmpeg-7.1-cuframes-demuxer.patch — patch для FFmpeg n7.1
  (Makefile / allformats.c / configure)
- filter/README.md — инструкции по сборке + CLI smoke test + Frigate plan

v1 ограничения (намеренно):
- только NV12
- GPU → CPU копия через cudaMemcpy2DAsync (zero-copy AVHWFramesContext — v2)

CLI smoke test 2026-05-17 (host build FFmpeg + libcuframes,
publisher на камере 192.168.88.98 1920x1080 HEVC 25fps):
  ffmpeg -f cuframes -i cuframes://cam-ff -c:v copy -f null -
  → frame=100 fps=25 q=-1.0 speed=1x  ✓
  → "cuframes: connected to 'cam-ff' — 1920x1080 NV12"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
gx merged commit 99ab0e0524 into main 2026-05-17 09:08:09 +01:00
gx deleted branch feat/ffmpeg-demuxer 2026-05-17 09:08:09 +01:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gx/cuframes#1