Phase 11b: hybrid PTZ — set_layout с timed motion freeze
User: "PTZ снова не переключает сетки". Причина: при motion-mode set_layout
игнорировался. Теперь: применяется + замораживает motion-mode на
manual_override_duration_ms_ (60s default). По истечении — auto-возврат
в motion-mode.
В Composer добавлено:
- manual_override_until_ms_ (моноклоk монотонное время)
- manual_override_duration_ms_ (default 60s)
- set_layout: применяет template, ставит override timestamp
- maybe_relayout: пока now < override → пропускаем (sustain manual layout),
после → лог "expired, возврат в motion-mode" + force relayout
ONVIF server.py одновременно обновлён под актуальные template имена:
- PTZ_PRESETS: tpl_1 / tpl_4 / tpl_9 / tpl_16 (вместо single/quad/...)
- ContinuousMove zoom-in → tpl_1, zoom-out → tpl_16,
pan/tilt → cycle через эти 4
Production smoke:
GotoPreset tpl_4 → composer log "manual override 'tpl_4' до +60000ms" PASS.
Refs: #195.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,11 @@ private:
|
||||
std::string committed_signature_;
|
||||
std::string pending_signature_;
|
||||
|
||||
/* Manual override (PTZ через set_layout): пока now < manual_override_until_ms_
|
||||
* motion-mode "заморожен", композитор держит зафиксированный layout. */
|
||||
std::int64_t manual_override_until_ms_ = 0;
|
||||
int manual_override_duration_ms_ = 60000;
|
||||
|
||||
/* Backward-compat overlay list (CLI overlays + detbox). */
|
||||
std::vector<cfc_overlay_t*> overlays_;
|
||||
|
||||
|
||||
+18
-7
@@ -114,11 +114,8 @@ void Composer::set_motion_mode(bool on, int ttl_ms)
|
||||
|
||||
bool Composer::set_layout(const std::string& name)
|
||||
{
|
||||
if (motion_mode_) {
|
||||
std::fprintf(stderr, "[cfc/composer] set_layout('%s') ignored: motion_mode active\n",
|
||||
name.c_str());
|
||||
return false;
|
||||
}
|
||||
/* В motion-mode set_layout не игнорируется: применяем + freezing motion
|
||||
* на manual_override_duration_ms_ (default 60s). После — auto возврат. */
|
||||
const auto& reg = current_templates();
|
||||
auto it = std::find_if(reg.begin(), reg.end(),
|
||||
[&](const LayoutTemplate& t) { return t.name == name; });
|
||||
@@ -131,9 +128,15 @@ bool Composer::set_layout(const std::string& name)
|
||||
pool_.for_each([&](PoolEntry& e) { snap.push_back(&e); });
|
||||
std::sort(snap.begin(), snap.end(),
|
||||
[](PoolEntry* a, PoolEntry* b) { return a->priority > b->priority; });
|
||||
std::int64_t now = now_ms_mono();
|
||||
layout_.apply(*it, snap, cfg_.width, cfg_.height);
|
||||
committed_signature_ = build_signature(it->name, snap);
|
||||
committed_at_ms_ = now_ms_mono();
|
||||
committed_at_ms_ = now;
|
||||
if (motion_mode_) {
|
||||
manual_override_until_ms_ = now + manual_override_duration_ms_;
|
||||
std::fprintf(stderr, "[cfc/composer] manual override '%s' до +%dms\n",
|
||||
it->name.c_str(), manual_override_duration_ms_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -207,6 +210,15 @@ void Composer::maybe_relayout()
|
||||
if (!motion_mode_) return;
|
||||
if (current_templates().empty()) return;
|
||||
|
||||
/* Manual override freeze. */
|
||||
std::int64_t now = now_ms_mono();
|
||||
if (manual_override_until_ms_ > now) return;
|
||||
if (manual_override_until_ms_ != 0) {
|
||||
std::fprintf(stderr, "[cfc/composer] manual override expired, возврат в motion-mode\n");
|
||||
manual_override_until_ms_ = 0;
|
||||
committed_signature_.clear(); /* форс relayout */
|
||||
}
|
||||
|
||||
auto active = collect_active();
|
||||
const LayoutTemplate* tpl = pick_best_fit(static_cast<int>(active.size()));
|
||||
if (!tpl) return;
|
||||
@@ -266,7 +278,6 @@ void Composer::maybe_relayout()
|
||||
if (is_grow && nkeys.size() == ckeys.size()) is_grow = false; /* идентичны */
|
||||
}
|
||||
|
||||
std::int64_t now = now_ms_mono();
|
||||
if (is_grow) {
|
||||
layout_.apply(*tpl, active, cfg_.width, cfg_.height);
|
||||
committed_signature_ = sig;
|
||||
|
||||
Reference in New Issue
Block a user