Files
cuframes-composer/include/cuframes_composer/overlay.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

147 lines
7.6 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 — overlay'и (border, png-иконка, текст) поверх
* композиции.
*
* Архитектура:
* cfc_overlay_t — opaque объект одного overlay'я (border, png, text).
* composer ведёт список overlays + порядок (z-order); на каждом compose'е
* проходит по списку и рисует их поверх NV12 grid'а.
*
* Типы overlay'ев:
* BORDER — цветная рамка вокруг rect'а (Phase 3a). Реализован через 4
* fill_nv12 операции (top/bottom/left/right). Полезно для:
* - визуальной отбивки ячеек grid'а
* - подсветки активных/неактивных источников (красная при DEAD)
* PNG — RGBA-изображение (Phase 3b). Decode-раз через stb_image,
* upload в VRAM, на каждом кадре alpha-blit через
* cfc_kern_alpha_blit_rgba_*. Для статичных иконок (NO SIGNAL,
* offline, recording dot).
* TEXT — динамический рендер строки (Phase 3c). Требует FreeType +
* font atlas. Сделать позже когда FreeType добавлен как зависимость.
*
* Жизненный цикл:
* cfc_overlay_create_*() — выделяет ресурсы (для PNG/TEXT — VRAM-атлас).
* cfc_overlay_update_*() — обновляет параметры (положение, видимость, текст).
* cfc_overlay_draw() — вызывается composer'ом на каждом кадре.
* cfc_overlay_destroy() — освобождает VRAM.
*
* Phase 3a лимит: только BORDER через fill_nv12.
*
* Лицензия: LGPL-2.1+
*/
#ifndef CUFRAMES_COMPOSER_OVERLAY_H
#define CUFRAMES_COMPOSER_OVERLAY_H
#include <cuda.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum cfc_overlay_type {
CFC_OVERLAY_BORDER = 0,
CFC_OVERLAY_PNG = 1, /* Phase 3b */
CFC_OVERLAY_TEXT = 2, /* Phase 3c */
} cfc_overlay_type_t;
typedef struct cfc_overlay cfc_overlay_t;
/* Назначить overlay'ю короткий ID для lookup через control plane (Phase 4).
* ID копируется внутрь overlay'я (макс 31 символ). Без ID overlay тоже работает,
* но управлять им runtime'ом нельзя. Можно вызвать после create. */
int cfc_overlay_set_id(cfc_overlay_t *ov, const char *id);
/* Получить ID overlay'я (NULL если не задан). */
const char *cfc_overlay_get_id(const cfc_overlay_t *ov);
/* Получить тип overlay'я. */
cfc_overlay_type_t cfc_overlay_get_type(const cfc_overlay_t *ov);
/* Параметры BORDER overlay'я. */
typedef struct cfc_overlay_border_config {
int x, y, w, h; /* прямоугольник в full-res пикселях */
int thickness; /* толщина рамки в пикселях */
int color_y, color_u, color_v; /* цвет в BT.709 (Y:16-235, UV:16-240) */
int alpha; /* 0..255; 0 = invisible */
int visible; /* 0/1 — выводить ли вообще */
} cfc_overlay_border_config_t;
/* Создать BORDER overlay. */
int cfc_overlay_create_border(const cfc_overlay_border_config_t *cfg,
cfc_overlay_t **out);
/* Параметры PNG overlay'я. */
typedef struct cfc_overlay_png_config {
const char *path; /* путь к PNG-файлу (декод один раз) */
int x, y; /* позиция top-left на output буфере (чётные) */
int extra_alpha; /* 0..255 общий множитель прозрачности */
int visible; /* 0/1 — выводить ли */
} cfc_overlay_png_config_t;
/* Создать PNG overlay. Декодирует файл через libpng, аллоцирует RGBA-атлас
* в VRAM (cuMemAlloc), копирует туда декодированные пиксели один раз.
*
* Размер изображения берётся из PNG header'а — caller узнаёт width/height
* через cfc_overlay_png_size после create. */
int cfc_overlay_create_png(const cfc_overlay_png_config_t *cfg,
cfc_overlay_t **out);
/* Получить реальный размер декодированного PNG. После create — стабильны
* до destroy. */
int cfc_overlay_png_size(cfc_overlay_t *ov, int *width, int *height);
/* Обновить параметры PNG overlay'я (без re-decode). */
int cfc_overlay_update_png(cfc_overlay_t *ov,
const cfc_overlay_png_config_t *cfg);
/* Параметры TEXT overlay'я (Phase 3c). */
typedef struct cfc_overlay_text_config {
const char *font_path; /* путь к .ttf / .otf */
const char *text; /* UTF-8 строка для рендера */
int pixel_size; /* высота glyph'а в пикселях (10..200) */
int x, y; /* top-left на output буфере (чётные) */
int r, g, b; /* sRGB цвет 0..255 */
int extra_alpha; /* 0..255 общий множитель прозрачности */
int visible; /* 0/1 — выводить ли */
} cfc_overlay_text_config_t;
/* Создать TEXT overlay. Открывает font через FreeType, рендерит строку
* в RGBA-атлас на CPU (alpha-channel из glyph bitmap'ов anti-aliased),
* заливает в VRAM. */
int cfc_overlay_create_text(const cfc_overlay_text_config_t *cfg,
cfc_overlay_t **out);
/* Обновить TEXT overlay. Если text изменился — re-render atlas (VRAM
* перевыделяется). font_path и pixel_size менять нельзя — заведите новый
* overlay (face и связанные ресурсы пере-init'ить дорого). */
int cfc_overlay_update_text(cfc_overlay_t *ov,
const cfc_overlay_text_config_t *cfg);
/* Получить ширину/высоту текущего рендеренного текста (в пикселях). */
int cfc_overlay_text_size(cfc_overlay_t *ov, int *width, int *height);
/* Обновить параметры BORDER overlay'я (можно переключить visible,
* сменить цвет, изменить позицию). Thread-safe? Нет — caller должен сам
* заботиться о том, чтобы update не пересекался с draw. В рамках одного
* compose-thread'а это естественно. */
int cfc_overlay_update_border(cfc_overlay_t *ov,
const cfc_overlay_border_config_t *cfg);
/* Нарисовать overlay поверх NV12 кадра. Вызывается из cfc_composer_compose.
* Возвращает 0 при успехе. */
int cfc_overlay_draw(cfc_overlay_t *ov,
CUstream stream,
CUdeviceptr dst_y, int pitch_y,
CUdeviceptr dst_uv, int pitch_uv,
int frame_w, int frame_h);
/* Уничтожить overlay (освободить VRAM если был). */
int cfc_overlay_destroy(cfc_overlay_t *ov);
#ifdef __cplusplus
}
#endif
#endif /* CUFRAMES_COMPOSER_OVERLAY_H */