1e2b5d4e16
Multi-source композитор работает на 4K @ 25fps стабильно. Live-тест с 4 камерами (parking, back_yard, front_yard, gate_lpr): все 4 active, 350 кадров за 14с, 27.6 МБ H.264 файл, кадр декодируется ffmpeg'ом с корректным 2x2 layout'ом. Содержимое: - include/cuframes_composer/cugrid.h — публичный API libcugrid: cfc_cugrid_fill_nv12 (region fill с alpha blend), cfc_cugrid_resize_nv12 (bilinear scale в rect). - src/cugrid/cugrid.cu — извлечённые из vf_cuda_grid kernel'ы (Y+UV fill + bilinear resize), объединены с C launcher'ом в одном .cu файле, под LGPL-2.1+. - include/cuframes_composer/composer.h — публичный API композитора: cfc_composer_cell_t для layout, get_health для observability. - src/composer.c — manager N cfc_source_t + единый NV12 output buffer (cuMemAlloc, переиспользуется на каждом compose'е). compose_clear fillит фон BT.709-чёрным, compose_cell делает resize ACTIVE источника или оставляет blackout для DEAD/STALE/CONNECTING. - examples/grid_record — Phase 2 smoke test: N --cell ключ,x,y,w,h → grid composer → NVENC → file. Сборка: добавлен LANGUAGES CUDA и CMAKE_CUDA_ARCHITECTURES 89;120 (Ada + Blackwell). Compile options раздельные для C и CUDA (-Wpedantic не подходит для .cu). Phase 2 RTSP push отложен на отдельный commit — будет через pipe-out к локальному ffmpeg'у, который публикует в mediamtx (вариант утверждён в Q2 дизайн-документа).
98 lines
4.1 KiB
C
98 lines
4.1 KiB
C
/* cuframes-composer — высокоуровневый композитор N источников в grid.
|
||
*
|
||
* Управляет:
|
||
* - N cfc_source (фоновые подписки на cuframes-publisher'ы)
|
||
* - Layout (cell positions + size)
|
||
* - Output NV12 buffer (cuMemAlloc, переиспользуется)
|
||
* - Композиция на каждом тике: clear background + resize/blit для каждого ACTIVE,
|
||
* fill чёрным для DEAD/STALE.
|
||
*
|
||
* Phase 2 архитектура:
|
||
* Композитор работает синхронно: caller вызывает cfc_composer_compose() →
|
||
* композитор для каждого источника берёт snapshot и пишет в output. После
|
||
* вызова output NV12 buffer готов к encode.
|
||
*
|
||
* Каноническая интеграция:
|
||
* for (;;) {
|
||
* cfc_composer_compose(comp); // grid готов в output buffer
|
||
* cfc_encoder_encode_frame(enc, ...); // → H.264
|
||
* }
|
||
*
|
||
* Лицензия: LGPL-2.1+
|
||
*/
|
||
|
||
#ifndef CUFRAMES_COMPOSER_COMPOSER_H
|
||
#define CUFRAMES_COMPOSER_COMPOSER_H
|
||
|
||
#include "source.h"
|
||
|
||
#include <cuda.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* Описание одной ячейки grid'а — где на output буфере рисуется источник.
|
||
* Все координаты в full-res пикселях, должны быть чётными. */
|
||
typedef struct cfc_composer_cell {
|
||
const char *source_key; /* cuframes key, например "cam-parking" */
|
||
int x, y; /* top-left угол на output буфере */
|
||
int w, h; /* размер ячейки */
|
||
} cfc_composer_cell_t;
|
||
|
||
typedef struct cfc_composer_config {
|
||
/* Output буфер (одно фиксированное разрешение для всего grid'а). */
|
||
int width; /* output ширина (например 3840 для 2×2 1080p) */
|
||
int height; /* output высота (например 2160 для 2×2 1080p) */
|
||
|
||
/* Cells конфигурация. Массив указателей на cells (для удобства user'а). */
|
||
const cfc_composer_cell_t *cells; /* array, не копируется — caller держит */
|
||
int num_cells;
|
||
|
||
/* CUDA устройство. */
|
||
int cuda_device; /* индекс, обычно 0 */
|
||
|
||
/* Backgound цвет (BT.709 limited): Y=16/U=128/V=128 = чёрный. */
|
||
int bg_y, bg_u, bg_v;
|
||
|
||
/* Параметры stale/dead для источников. */
|
||
int reconnect_min_ms; /* default 1000 */
|
||
int reconnect_max_ms; /* default 30000 */
|
||
int stale_threshold_ms; /* default 500 */
|
||
int dead_threshold_ms; /* default 5000 */
|
||
} cfc_composer_config_t;
|
||
|
||
typedef struct cfc_composer cfc_composer_t;
|
||
|
||
/* Создать композитор. Выделяет output NV12 буфер, запускает N source thread'ов. */
|
||
int cfc_composer_create(const cfc_composer_config_t *cfg, cfc_composer_t **out);
|
||
|
||
/* Скомпоновать один кадр. Вернёт указатели на output NV12 (Y + UV) и pitch.
|
||
* Указатели действительны до следующего compose. */
|
||
int cfc_composer_compose(
|
||
cfc_composer_t *comp,
|
||
CUdeviceptr *out_y_ptr,
|
||
int *out_pitch_y,
|
||
int *out_width,
|
||
int *out_height
|
||
);
|
||
|
||
/* Получить layout статистику по источникам — для debug / health-репортов. */
|
||
typedef struct cfc_composer_health {
|
||
int total; /* всего источников */
|
||
int active; /* в состоянии ACTIVE */
|
||
int stale; /* в STALE */
|
||
int dead; /* DEAD/DISCONNECTED/CONNECTING */
|
||
} cfc_composer_health_t;
|
||
int cfc_composer_get_health(cfc_composer_t *comp, cfc_composer_health_t *out);
|
||
|
||
/* Уничтожить композитор. */
|
||
int cfc_composer_destroy(cfc_composer_t *comp);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* CUFRAMES_COMPOSER_COMPOSER_H */
|