Files
cuframes-composer/include/cuframes_composer/cpp/composer.hpp
T
gx 6e0273f4b4 Phase 11b F: extern "C" ABI shim + production deploy
В прод деплоен 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>
2026-06-04 08:57:30 +01:00

148 lines
5.0 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.
/* Composer — оркестратор Phase 11b.
*
* Owns:
* - SourcePool (cuframes-источники + motion state)
* - vector<LayoutTemplate> (loaded from JSON или builtins)
* - Layout (текущее состояние cells)
* - OutputSurface (CudaBuffer для NV12 output)
*
* Compose loop (по кадру):
* 1. select_template_and_active() → (LayoutTemplate*, vector<PoolEntry*>)
* по правилам: motion_mode? motion-based best-fit : idle top-1 single
* 2. hysteresis: рост сразу, уменьшение — wait shrink_hysteresis_ms
* 3. если sig != committed → layout_.apply(template, active, W, H)
* 4. compose_clear() → output буфер чёрный
* 5. layout_.render(stream, NV12Ref)
*
* Public API экспортируется через composer_c_api.cpp с extern "C" для
* совместимости с control.c, grid_record.c, frigate_mqtt.c.
*
* Лицензия: LGPL-2.1+
*/
#ifndef CUFRAMES_COMPOSER_CPP_COMPOSER_HPP
#define CUFRAMES_COMPOSER_CPP_COMPOSER_HPP
#include "../overlay.h" /* C API — backward compat для CLI overlays */
#include "cuda_raii.hpp"
#include "layout.hpp"
#include "source_pool.hpp"
#include "template.hpp"
#include "types.hpp"
#include <cuda_runtime.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
namespace cfc {
struct ComposerConfig {
int width = 1920;
int height = 1080;
int cuda_device = 0;
int bg_y = 16, bg_u = 128, bg_v = 128;
/* Motion-mode параметры. */
int motion_ttl_ms = 45000;
int shrink_hysteresis_ms = 3000;
/* Templates JSON path (empty → built-in). */
std::string templates_path;
};
class Composer {
public:
explicit Composer(const ComposerConfig& cfg);
~Composer();
Composer(const Composer&) = delete;
Composer& operator=(const Composer&) = delete;
bool ok() const noexcept { return output_.ok(); }
SourcePool& pool() noexcept { return pool_; }
const SourcePool& pool() const noexcept { return pool_; }
/* Motion mode + relayout policy. */
void set_motion_mode(bool on, int ttl_ms = 0);
bool motion_mode() const noexcept { return motion_mode_; }
/* Загрузить templates из JSON. Возвращает количество, либо <0. */
int load_templates(const std::string& path);
/* Перейти на named template (только если motion_mode == false). */
bool set_layout(const std::string& name);
const std::string& current_layout_name() const noexcept {
return layout_.name();
}
int templates_count() const noexcept {
return static_cast<int>(templates_.size());
}
const std::vector<LayoutTemplate>& templates() const noexcept {
return templates_;
}
/* Overlays — backward compat для grid_record.c CLI (--text/--icon/--border)
* и Frigate detection_boxes. Рисуются на выходе compose_frame ПОСЛЕ Layout.
* Composer takes ownership — destroy()'ит на ~Composer(). */
int add_overlay(cfc_overlay_t* ov);
cfc_overlay_t* find_overlay(const std::string& id) const;
/* Health отчёт для C ABI shim. */
struct Health {
int total = 0;
int active = 0;
int stale = 0;
int dead = 0;
};
Health get_health() const;
/* Manual cells — для C API без motion-mode (grid_record --cell без --motion-mode).
* Каждый вход {source_key, rect} рендерится CameraCell без template'а. */
void set_manual_cells(const std::vector<std::pair<std::string, Rect>>& cells);
/* Один кадр: relayout (если нужно) + clear + render.
* Возвращает NV12Ref на output (ptr действителен до следующего compose). */
NV12Ref compose_frame();
private:
/* Selection + hysteresis. */
const LayoutTemplate* pick_best_fit(int need) const;
std::vector<PoolEntry*> collect_active() const;
void maybe_relayout();
static std::string build_signature(const std::string& tpl_name,
const std::vector<PoolEntry*>& active);
ComposerConfig cfg_;
SourcePool pool_;
std::vector<LayoutTemplate> templates_;
Layout layout_;
/* Output NV12 буфер (VMM, zero-copy для NVENC). */
CudaBuffer output_;
int pitch_y_ = 0;
int pitch_uv_ = 0;
cudaStream_t stream_ = nullptr; /* default = 0 */
bool motion_mode_ = false;
std::int64_t committed_at_ms_ = 0;
std::int64_t pending_first_seen_ms_ = 0;
std::string committed_signature_;
std::string pending_signature_;
/* Backward-compat overlay list (CLI overlays + detbox). */
std::vector<cfc_overlay_t*> overlays_;
/* Manual cells — alternative режим без motion-mode (grid_record --cell). */
std::vector<std::pair<std::string, Rect>> manual_cells_;
bool manual_applied_ = false;
};
} // namespace cfc
#endif /* CUFRAMES_COMPOSER_CPP_COMPOSER_HPP */