diff --git a/include/cuframes_composer/cpp/camera_cell.hpp b/include/cuframes_composer/cpp/camera_cell.hpp index 47685ab..42f18b6 100644 --- a/include/cuframes_composer/cpp/camera_cell.hpp +++ b/include/cuframes_composer/cpp/camera_cell.hpp @@ -17,21 +17,25 @@ #include "../source.h" #include "cell.hpp" +#include + namespace cfc { class CameraCell : public Cell { public: - CameraCell(const Rect& geom, cfc_source_t* source) - : Cell(geom), source_(source) {} + CameraCell(const Rect& geom, cfc_source_t* source, std::string source_key = {}) + : Cell(geom), source_(source), source_key_(std::move(source_key)) {} void set_source(cfc_source_t* src) noexcept { source_ = src; } cfc_source_t* source() const noexcept { return source_; } + const std::string& source_key() const noexcept { return source_key_; } protected: void draw_content(CUstream stream, NV12Ref& dst) override; private: cfc_source_t* source_; /* non-owning — pool владеет */ + std::string source_key_; }; } // namespace cfc diff --git a/include/cuframes_composer/cpp/layout.hpp b/include/cuframes_composer/cpp/layout.hpp index 75fcbc3..4148f2d 100644 --- a/include/cuframes_composer/cpp/layout.hpp +++ b/include/cuframes_composer/cpp/layout.hpp @@ -47,6 +47,11 @@ public: const std::string& name() const noexcept { return current_name_; } int cell_count() const noexcept { return static_cast(cells_.size()); } + /* Найти текущий pixel-rect для камеры с заданным cuframes-key. NULL + * если этой камеры в layout сейчас нет. Используется detbox-overlay'ями + * для пересчёта bbox при смене layout. */ + const Rect* find_camera_cell_rect(const std::string& source_key) const; + private: std::vector> cells_; std::string current_name_; diff --git a/include/cuframes_composer/cpp/source_pool.hpp b/include/cuframes_composer/cpp/source_pool.hpp index 05bb24d..44daa7c 100644 --- a/include/cuframes_composer/cpp/source_pool.hpp +++ b/include/cuframes_composer/cpp/source_pool.hpp @@ -73,6 +73,7 @@ public: int size() const { return static_cast(entries_.size()); } PoolEntry* by_index(int i) { return i >= 0 && i < size() ? entries_[i].get() : nullptr; } PoolEntry* by_key(const std::string& key); + PoolEntry* by_frigate_camera(const std::string& frigate_camera); /* Уведомить о motion (вызывается из Frigate MQTT subscriber'а через * C-shim). Если zone-filter задан — проверяет пересечение. */ diff --git a/include/cuframes_composer/overlay.h b/include/cuframes_composer/overlay.h index 3f74584..a67554d 100644 --- a/include/cuframes_composer/overlay.h +++ b/include/cuframes_composer/overlay.h @@ -176,6 +176,13 @@ int cfc_overlay_create_detection_boxes( * правильный overlay по incoming event'у. */ const char *cfc_overlay_detbox_camera_key(cfc_overlay_t *ov); +/* Обновить cell-геометрию runtime (при смене layout композитора). Композитор + * вызывает перед draw каждым detbox-overlay'ем — пересчитывает положение + * рамки под текущую позицию камеры. */ +int cfc_overlay_detbox_set_cell_geom(cfc_overlay_t *ov, + int cell_x, int cell_y, + int cell_w, int cell_h); + /* Проверить пересечение current_zones события с required_zones overlay'я. * - если required_zones пуст → всегда 1 (filter off) * - если current_zones пуст → 0 (объект вне зон) diff --git a/src/cpp/composer.cpp b/src/cpp/composer.cpp index 1f731df..5743994 100644 --- a/src/cpp/composer.cpp +++ b/src/cpp/composer.cpp @@ -362,6 +362,26 @@ NV12Ref Composer::compose_frame() /* Backward-compat overlays (CLI text/icon, detbox) — поверх Layout. */ for (auto* ov : overlays_) { if (!ov) continue; + + /* Detection box рисуется в координатах cell камеры. Cell может + * перемещаться по экрану при смене layout — синхронизируем cell-geom + * перед каждым draw. */ + if (cfc_overlay_get_type(ov) == CFC_OVERLAY_DETECTION_BOXES) { + const char* fcam = cfc_overlay_detbox_camera_key(ov); + if (fcam) { + PoolEntry* e = pool_.by_frigate_camera(fcam); + if (e) { + const Rect* r = layout_.find_camera_cell_rect(e->cuframes_key); + if (r) { + cfc_overlay_detbox_set_cell_geom(ov, r->x, r->y, r->w, r->h); + } else { + /* Камеры нет в текущем layout — скрываем рамки. */ + cfc_overlay_detbox_set_cell_geom(ov, 0, 0, 0, 0); + } + } + } + } + cfc_overlay_draw(ov, reinterpret_cast(stream_), y, pitch_y_, uv, pitch_uv_, cfg_.width, cfg_.height); diff --git a/src/cpp/layout.cpp b/src/cpp/layout.cpp index 493219c..046e847 100644 --- a/src/cpp/layout.cpp +++ b/src/cpp/layout.cpp @@ -45,7 +45,8 @@ void Layout::apply(const LayoutTemplate& tpl, for (std::size_t i = 0; i < camera_templates.size(); ++i) { Rect r = to_pixels(*camera_templates[i], frame_w, frame_h); if (i < active_sorted.size() && active_sorted[i] && active_sorted[i]->source) { - auto cell = std::make_unique(r, active_sorted[i]->source); + auto cell = std::make_unique(r, active_sorted[i]->source, + active_sorted[i]->cuframes_key); cell->add_decoration(std::make_unique(border_style)); /* Label с именем камеры и приоритетом. */ char label_buf[96]; @@ -79,4 +80,15 @@ void Layout::render(CUstream stream, NV12Ref& dst) for (auto& c : cells_) c->draw(stream, dst); } +const Rect* Layout::find_camera_cell_rect(const std::string& source_key) const +{ + for (auto& c : cells_) { + auto* cc = dynamic_cast(c.get()); + if (cc && cc->source_key() == source_key) { + return &cc->geometry(); + } + } + return nullptr; +} + } // namespace cfc diff --git a/src/cpp/source_pool.cpp b/src/cpp/source_pool.cpp index a458586..8169e1e 100644 --- a/src/cpp/source_pool.cpp +++ b/src/cpp/source_pool.cpp @@ -77,6 +77,14 @@ PoolEntry* SourcePool::by_key(const std::string& key) return nullptr; } +PoolEntry* SourcePool::by_frigate_camera(const std::string& fcam) +{ + for (auto& e : entries_) { + if (e->frigate_camera == fcam) return e.get(); + } + return nullptr; +} + void SourcePool::motion_pulse(const std::string& frigate_camera, const std::vector& current_zones) { diff --git a/src/overlay.c b/src/overlay.c index 52a3d26..0a31771 100644 --- a/src/overlay.c +++ b/src/overlay.c @@ -647,6 +647,21 @@ const char *cfc_overlay_detbox_camera_key(cfc_overlay_t *ov) return ov->u.detbox.camera_key; } +int cfc_overlay_detbox_set_cell_geom(cfc_overlay_t *ov, + int cell_x, int cell_y, + int cell_w, int cell_h) +{ + if (!ov || ov->type != CFC_OVERLAY_DETECTION_BOXES) return -1; + detbox_data_t *d = &ov->u.detbox; + pthread_mutex_lock(&d->mu); + d->cfg.cell_x = cell_x; + d->cfg.cell_y = cell_y; + d->cfg.cell_w = cell_w; + d->cfg.cell_h = cell_h; + pthread_mutex_unlock(&d->mu); + return 0; +} + int cfc_overlay_detbox_match_zones(cfc_overlay_t *ov, const char *const *current_zones, int n)