/* SourcePool — пул cuframes-источников композитора (Phase 11b). * * Каждая запись: cuframes_key + frigate_camera + priority + cfc_source_t* + * motion state (last_motion_ms, zone-filter). Pool создаётся при старте * композитора (через add() вызовы) и живёт всю сессию. * * Cells (CameraCell) держат non-owning указатели на cfc_source_t — pool * владеет. * * Лицензия: LGPL-2.1+ */ #ifndef CUFRAMES_COMPOSER_CPP_SOURCE_POOL_HPP #define CUFRAMES_COMPOSER_CPP_SOURCE_POOL_HPP #include "../source.h" #include #include #include #include #include namespace cfc { struct PoolEntry { std::string cuframes_key; std::string frigate_camera; int priority = 0; cfc_source_t* source = nullptr; std::atomic last_motion_ms{0}; std::vector required_zones; /* Получить snapshot для drawable-checks без локов. */ cfc_source_state_t state() const { if (!source) return CFC_SOURCE_DISCONNECTED; cfc_source_snapshot_t s{}; cfc_source_get_latest(source, &s); return s.state; } bool drawable() const { cfc_source_state_t st = state(); return st == CFC_SOURCE_ACTIVE || st == CFC_SOURCE_STALE; } }; class SourcePool { public: SourcePool() = default; ~SourcePool(); SourcePool(const SourcePool&) = delete; SourcePool& operator=(const SourcePool&) = delete; /* Параметры подписки cuframes (default per cfc_source_config_t). */ struct SubscribeOpts { int cuda_device = 0; std::string consumer_prefix = "composer"; int reconnect_min_ms = 1000; int reconnect_max_ms = 30000; int stale_threshold_ms = 500; int dead_threshold_ms = 5000; }; /* Добавить источник в pool. Возвращает индекс или -1. */ int add(const std::string& cuframes_key, const std::string& frigate_camera, int priority, const std::vector& zones, const SubscribeOpts& opts); 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 задан — проверяет пересечение. */ void motion_pulse(const std::string& frigate_camera, const std::vector& current_zones); /* Итерация (для best-fit selection и health). */ template void for_each(F&& fn) { for (auto& e : entries_) fn(*e); } private: std::vector> entries_; std::mutex mu_; }; } // namespace cfc #endif /* CUFRAMES_COMPOSER_CPP_SOURCE_POOL_HPP */