Files
cuframes-composer/include/cuframes_composer/composer.h
T
gx 636b70b64c Phase 4: ZMQ control plane + MQTT health publisher
Phase 4a — control plane через ZMQ REP socket с JSON-командами.
Позволяет операторам менять text overlay'и runtime'ом без рестарта.
Live-validated: команды set_text label-parking → "⚠ ВНИМАНИЕ ⚠"
и set_text label-gate → "Машина у ворот" отрабатывают, текст
обновляется в потоке RTSP без перерывов.

Phase 4b — MQTT health publisher через libmosquitto. Каждые 10с в
composer/<instance>/health публикуется JSON {active,stale,dead,total,
uptime_s} с retain=true. Опционально публикуется HA MQTT discovery
config — четыре сенсора (active/stale/dead/total) появляются в HA
автоматически с expire_after=30s.

Содержимое:

- include/cuframes_composer/overlay.h — cfc_overlay_set_id/get_id/get_type
  для lookup'а через control plane.
- include/cuframes_composer/composer.h — cfc_composer_find_overlay(id).
- include/cuframes_composer/control.h — cfc_control_config_t (endpoint +
  composer + cuda_ctx для text rebuild в worker thread).
- src/control.c — ZMQ REP socket в фоновом потоке + zmq_poll с 200мс
  timeout'ом для проверки stop_flag. JSON-диспатчер для команд ping /
  health / set_text / set_visible / list_overlays. cuCtxSetCurrent
  на старте worker'а — без этого update_text валится на cuMemAlloc.
- include/cuframes_composer/health.h — cfc_health_config_t (host/port/
  user/pass + topic_prefix/instance + interval + publish_discovery).
- src/health.c — mosquitto_connect_async + loop_start + background
  thread с publish health каждые N секунд + один разовый publish_discovery
  для HA.
- examples/grid_record — флаги --control tcp://0.0.0.0:5599,
  --mqtt host[:port], --mqtt-instance NAME, --mqtt-user/--mqtt-pass.
  Для text overlay'ев — prefix "id=NAME:" в --text задаёт control-plane ID.

CMakeLists.txt — find_library(zmq), find_library(json-c),
find_library(mosquitto) + linkage всех трёх.

Production TODO: создать отдельного MQTT user'а для composer'а вместо
переиспользования frigate creds (используется только в smoke).
2026-06-03 06:20:38 +01:00

112 lines
5.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 "overlay.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
);
/* Зарегистрировать overlay (border/png/text) для отрисовки поверх grid'а.
* composer takes ownership — на cfc_composer_destroy всё освобождается.
* Порядок добавления = z-order (последний рисуется поверх). Лимит — 64. */
int cfc_composer_add_overlay(cfc_composer_t *comp, cfc_overlay_t *ov);
/* Найти overlay по ID (если был задан через cfc_overlay_set_id). Возвращает
* NULL если не найден. Thread-safe — composer держит overlays в массиве,
* пока add/destroy не пересекаются с lookup'ом — но control plane вызывает
* это из своего потока, draw — из своего; они оба только читают список,
* а update полей overlay'я делается через cfc_overlay_update_text и пр.
* (содержимое overlay'я под mutex'ом не лежит, нужно лочиться вызывающему). */
cfc_overlay_t *cfc_composer_find_overlay(cfc_composer_t *comp, const char *id);
/* Получить 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 */