User: "при движении объект оборачивается в рамку, но функционал не
учитывает что сетки могут переключаться и координаты ячеек меняются".
Был баг: detbox-overlay хранил cell_x/y/w/h из --detection-cell CLI
(заданы при старте), при смене layout рамки рисовались по старым
координатам — мимо камеры.
Изменения:
- overlay.h/.c: новый API cfc_overlay_detbox_set_cell_geom(ov,x,y,w,h).
Mutex-защищённое обновление detbox config'а — composer вызывает
перед каждым draw.
- CameraCell: добавлено поле source_key (хранит cuframes-key камеры,
рендерящейся в этом cell). Layout::apply передаёт его из pool entry.
- Layout::find_camera_cell_rect(key) — возвращает Rect текущей cell
для камеры с заданным cuframes-key (или nullptr если её нет в layout).
- SourcePool::by_frigate_camera(name) — lookup pool-entry по
Frigate-camera-key (frigate event'ы приходят с этим именем).
- Composer::compose_frame: перед draw каждого DETECTION_BOXES overlay'я
— lookup frigate→cuframes_key→layout cell rect, обновляет detbox geom.
Если камера не в layout сейчас — cell_w/h=0, detbox draw skip'ает.
Теперь bbox от Frigate переезжает за камерой:
- tpl_1 → bbox в full screen 1920×1080
- tpl_3 → bbox в main 1440×810
- tpl_4 → bbox в quad ячейке 960×540
- камера не в layout → bbox скрыт
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User: "у него есть полупрозрачная подложка? у него правильный z-order?"
Z-order был ок (overlays draw'аются после layout.render). Но без bg
текст плохо читался на пёстром кадре — и до прихода MQTT overlay был
visible=0 (не виден вообще).
Изменения:
- overlay.h: cfc_overlay_text_config_t расширена bg_alpha / bg_y/u/v / bg_pad.
bg_alpha=0 — фон отключён (default).
- overlay.c draw_text: если bg_alpha>0, перед blit'ом текста рисуем fill
rect (atlas_w+2*pad) × (atlas_h+2*pad) с заданным цветом и alpha.
- overlay.c update_text: пробрасывает bg-поля при апдейте.
- mqtt_overlay: MqttOverlayCfg + JSON loader научились читать bg_alpha,
bg_y/u/v, bg_pad, placeholder. Default bg = чёрный 160 alpha, pad 10.
- MqttOverlayItem::start: overlay сразу visible=1 с placeholder (default "—"),
reposition_overlay вызывается до получения MQTT — placeholder
позиционируется в anchor сразу.
User'у теперь видна тёмная подложка с текстом в правом-нижнем углу даже
если sensor молчит.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User: "в предыдущих версиях у нас показывалась температура, можешь
сделать в нижнем правом углу оверлей не привязанный к сеткам?". Восстановили
прежнее поведение из vf-cuda-grid/controller (dynamic_overlays.py).
Новый класс cfc::TempMqttOverlay:
- libmosquitto subscriber в отдельном thread'е, auto-reconnect 1→30s
- json-c для parse JSON payload — extract поле .temperature (double)
- Формат: "%+.1f°C" (например "+18.5°C")
- Persistent FreeType text overlay (cfc_overlay_create_text), kept в
Composer::overlays_[] backward-compat листе — рендерится поверх Layout
- reposition_overlay() — пересчёт x/y после text_size() (right-bottom anchor)
C-shim (composer_c_api.cpp) для grid_record.c:
- cfc_temp_overlay_start(composer, host, port, user, pw, topic, W, H)
- singleton (один temp overlay на процесс, прода-композитору хватит)
CLI: --temp-topic="zigbee2mqtt/Температура на улице". MQTT credentials
переиспользуются из --mqtt-host/--mqtt-user/--mqtt-pass.
Compose override (localhost-infra):
--temp-topic=zigbee2mqtt/Температура на улице
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
В прод деплоен gx/cuframes-composer:0.11b-step1 — C++ ядро
работает через ABI shim, старые C-callers (grid_record.c, control.c,
frigate_mqtt.c) использует те же cfc_composer_* функции.
Что в этом коммите:
- src/cpp/composer_c_api.cpp: extern "C" обёртки над cfc::Composer
методами. Полный набор: _create/_destroy/_compose/_add_overlay/
_find_overlay/_set_layout/_current_layout/_add_pool_source/
_set_motion_mode/_get_motion_mode/_motion_pulse/_get_health.
- src/cpp/layouts_c_api.cpp: extern "C" обёртки над template_loader
для cfc_layout_find/_all/_load_file/_reload/_loaded_path/_to_pixels.
- cpp/template_loader: global registry (current_templates / set_*
/ load_into_current) — единый источник истины. Composer и C ABI
shim читают один и тот же mutex-защищённый vector<LayoutTemplate>.
Hot-reload через ZMQ cfc_layout_load_file подхватывается composer'ом
на следующем кадре без рестарта.
- cpp/composer: pick_best_fit, set_layout, maybe_relayout читают
current_templates() вместо локального snapshot.
- cpp/composer: backward-compat overlay list (add_overlay/find_overlay)
+ manual cells support (для C API без motion-mode).
- cpp/composer compose_frame: после Layout.render() рендерит overlays
(CLI text/icon/border + Frigate detbox) поверх.
- Удалены: src/composer.c (заменён composer_c_api.cpp + composer.cpp),
src/layouts.c (заменён layouts_c_api.cpp + template_loader.cpp).
- Оставлено как есть: src/overlay.c (PNG/text/border/detbox CLI overlays
— реализация не меняется, доступ через cfc_overlay_*).
- src/CMakeLists.txt: COMPOSER_SOURCES_C минус composer.c, layouts.c,
COMPOSER_SOURCES_CPP плюс composer_c_api.cpp, layouts_c_api.cpp.
Production smoke (R9-88.23):
[cfc/loader] /opt/templates.json: loaded 7 templates
[cfc/composer] templates loaded: 7 (path='/opt/templates.json')
[cfc/composer] pool+ cam-parking prio=100 / cam-gate_lpr prio=90 / ...
[cfc/composer] motion_mode=1 ttl=45000ms pool=4
[cfc/composer] grow → template='tpl_1' active=1
PASS.
Refs: #195 (Phase 11b C++ refactor).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Что в этом коммите:
Decoration реализации:
- cpp/label_decoration.hpp/.cpp — FreeType atlas + cugrid_blit_rgba_nv12.
UTF-8 декодер, atlas в VRAM (RAII через CudaBuffer), rebuild при set_text.
- cpp/border_decoration.hpp/.cpp — 4 cugrid_fill_nv12 (top/bottom/left/right).
Cell реализации:
- cpp/camera_cell.hpp/.cpp — cfc_source_get_latest + cugrid_resize_nv12.
Non-owning указатель на cfc_source_t (pool владеет).
- cpp/widget_cell.hpp/.cpp — тёмный fill placeholder.
- cpp/blank_cell.hpp/.cpp — BT.709 black fill.
Layout и Template:
- cpp/template.hpp — LayoutTemplate { name, cells[], priority }.
8×8 микро-сетка (kGridCols=kGridRows=8). to_pixels() переводит в Rect.
- cpp/layout.hpp/.cpp — vector<unique_ptr<Cell>>, apply() создаёт
CameraCell/WidgetCell/BlankCell + Decorations (Label с "{key} prio={N}").
- cpp/template_loader.hpp/.cpp — JSON → vector<LayoutTemplate> через json-c.
builtin_templates() = { tpl_1, tpl_4 } как fallback.
SourcePool:
- cpp/source_pool.hpp/.cpp — owner cfc_source_t*, motion state атомарный,
zone-filter в motion_pulse. Pool entries — non-copyable unique_ptr.
Composer:
- cpp/composer.hpp/.cpp — owner SourcePool + templates + Layout + output.
Алгоритмы: pick_best_fit (min nb_camera_cells >= need + priority tie-break),
collect_active (drawable AND motion_within_TTL), asymmetric hysteresis
(рост сразу через std::includes, сжатие — wait shrink_hysteresis_ms).
Public C++ API: set_motion_mode / set_layout / load_templates / compose_frame.
ООП-гипотеза smoke:
- examples/grid_record_cpp.cpp — минимальный smoke без NVENC. Init composer,
compose_frame N раз, dump NV12 в файл. Проверяет что C++ модель
компилируется, линкуется с C-кодом (source.c, nvenc.c остались на C через
extern "C"), и реально рисует кадр.
Производительность сохранена:
- Один output буфер VMM, передаётся как NV12Ref (read-write reference) во все
cells/decorations — НИКАКИХ memcpy на cells boundary.
- Virtual call overhead: 1 indirect call per cell per frame. Negligible.
- Heap allocations только при apply_template (раз в N секунд при relayout).
Build:
- CMakeLists.txt: CXX language, C++17.
- src/CMakeLists.txt: COMPOSER_SOURCES_CPP добавлен в lib.
- examples/CMakeLists.txt: grid_record_cpp.
Smoke test run jammy:
[cfc/loader] docker/templates.json: loaded 7 templates
[smoke] composer 1920x1080 templates=7 sources=0 motion=0
[smoke] wrote 3317760 bytes (Y=2211840 UV=1105920) to /out/blank.nv12
Build PASS, init PASS, compose PASS, dump PASS.
Что НЕ сделано:
- extern "C" ABI shim для control.c / grid_record.c (старый C-композитор
всё ещё единственный для prod stack).
- Удаление старых composer.c / overlay.c / layouts.c.
- Live deploy в прод (Step 1-3 функциональность).
- JSON ZMQ hot-reload (был в Step 3 C-version, восстановить в C++).
Refs: #195 (Phase 11b C++ refactor).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>