Files
cuframes-docs/site/i18n/ru/docusaurus-plugin-content-docs/current/concepts/frame-vs-packet-ring.md
T
Claude Opus 7f45c36aa2 init
2026-05-26 23:23:25 +01:00

6.5 KiB
Raw Blame History

title, sidebar_position
title sidebar_position
Frame ring vs Packet ring 1

Frame ring vs Packet ring

cuframes даёт publisher'у два независимых ring buffer'а с разной семантикой и разной стоимостью:

  • Frame ring — decoded NV12 (или другой pixel format), shared zero-copy через CUDA VMM.
  • Packet ring — encoded H.264 / H.265 NAL units, shared через POSIX shared memory.

Это два разных канала на одной паре publisher↔subscriber. Можно использовать один, оба, или иметь несколько consumer'ов где одни читают frame ring, другие — packet ring.

Зачем два канала

Один publisher обычно обслуживает разные классы потребителей. AI-детектор и GPU-композитор хотят уже decoded GPU pointer (frame ring); NVR-recorder и replay-сервис хотят compact encoded stream (packet ring). Заставлять recorder декодировать ради того чтобы потом снова encode'нуть для сохранения — пустая работа.

flowchart LR
  RTSP[RTSP camera] --> Dec[NVDEC decode]
  Dec --> Pub[Publisher]
  Pub -- frame ring<br/>CUDA VMM --> AI[AI inference<br/>GPU consumer]
  Pub -- frame ring<br/>CUDA VMM --> Comp[GPU compositor<br/>CUDA filter]
  Pub -- packet ring<br/>POSIX shm --> NVR[NVR / recorder<br/>mp4 mux]
  Pub -- packet ring<br/>POSIX shm --> Replay[Replay / seek service]

Frame ring

Что: ring из N CUDA-allocated slot'ов (cuMemCreate(POSIX_FILE_DESCRIPTOR)), экспортируются через SCM_RIGHTS consumer'у, импортируются через cuMemImportFromShareableHandle. Consumer получает CUDA device pointer на ту же физическую HBM-память что и publisher.

Когда использовать:

  • consumer работает на GPU и хочет данные as-is (AI inference, CUDA filter, NVENC re-encode на другом codec);
  • латентность критична — между publish и consume hardware coherence, без encode/decode roundtrip;
  • consumer декодировать сам не хочет.

Стоимость: ring_size × frame_size GPU-памяти на publisher. Для NV12 1920×1080 ring=4 это ≈ 12 MiB на publisher (VMM granularity на RTX 5090 — 2 MiB, реально ≈ 16 MiB). Consumer'ы memory не платят — это та же физическая память.

API:

cuframes_publisher_create(&cfg, &pub);            // ring аллоцируется
cuframes_publisher_acquire(pub, &cuda_ptr);       // получаем slot
// ... NVDEC / kernel пишут в cuda_ptr ...
cuframes_publisher_publish(pub, stream, pts_ns);

Packet ring

Что: ring из slot'ов с metadata (pts, dts, size, flags) + отдельная data-секция (default 8 MiB) в POSIX shm /dev/shm/cuframes-<key>-packets. Publisher закидывает туда encoded NAL units (Annex B byte stream).

Когда использовать:

  • consumer декодирует сам (FFmpeg demuxer, recorder, на остальном GPU нет места);
  • нужен compact stream для записи на диск;
  • late subscriber должен сам resync'нуться от ближайшего keyframe — это семантика ring'а (см. protocol reference).

Стоимость: POSIX shm на host — data_size + ring_slots × 64 байта. На GPU расход нулевой.

Packet ring опционален и отдельно активируется на уже созданном publisher'е:

cuframes_publisher_create(&cfg, &pub);

cuframes_packet_ring_options_t pkt_opts = {
    .ring_slots      = 64,
    .data_size       = 8 * 1024 * 1024,
    .max_packet_size = 2 * 1024 * 1024,
    .codec_id        = 27,   // AV_CODEC_ID_H264
};
cuframes_publisher_enable_packets(pub, &pkt_opts);
cuframes_publisher_set_codec_extradata(pub, sps_pps, sps_pps_size);

// в цикле:
cuframes_publisher_publish_packet(pub, nal_data, nal_size,
                                  pts_ns, dts_ns,
                                  CUFRAMES_PKT_FLAG_KEY);

Аналогично на subscriber'е:

cuframes_subscriber_create(&cfg, &sub);
cuframes_subscriber_enable_packets(sub);   // открывает второй SHM

cuframes_packet_t *pkt;
cuframes_subscriber_next_packet(sub, &pkt, -1);

Subscriber может включить любую комбинацию: только frame ring, только packet ring, оба сразу. Это два независимых SHM segment'а с разными magic.

Сравнение

Frame ring Packet ring
Содержимое Decoded NV12 / RGB / etc Encoded H.264 / H.265 NAL
Транспорт CUDA VMM + POSIX FD POSIX shm
Sync mechanism atomic seq + cuStreamSynchronize atomic seq (нет CUDA)
Latency publish→consume sub-frame, без encode roundtrip sub-frame, но consumer декодирует
Memory cost (publisher) ring_size × frame_size GPU data_size host shm
Memory cost (consumer) 0 (shared physical pages) 0 (mmap same shm)
Требует CUDA на consumer да нет
Late join semantics newest frame документирован resync на last keyframe
Типичный use case AI inference, GPU compositor NVR recording, replay

Можно ли один без другого

Да. Frame ring аллоцируется в cuframes_publisher_create — без него publisher вообще не существует. Packet ring опционален: если cuframes_publisher_enable_packets не вызвать, publisher просто не примет publish_packet, а subscriber на enable_packets получит CUFRAMES_ERR_NOT_FOUND.

Обратное (packet ring без frame ring) в текущем API не поддерживается — для pure encoded-only сценариев это TODO будущей версии.

Следующее