From 7b341d9f4f6cfe7e87f201847cb7a93571551d7e Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 19 Oct 2026 22:52:40 +0200 Subject: [PATCH] Cancel desktop decoder probing when a call stops --- tools/chatgui/src/call_video_decoder.cpp | 21 ++++++++++++++----- tools/chatgui/src/call_video_decoder.h | 4 +++- tools/chatgui/src/call_video_engine.cpp | 2 +- .../chatgui/tests/test_audio_diagnostics.cpp | 4 ++-- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tools/chatgui/src/call_video_decoder.cpp b/tools/chatgui/src/call_video_decoder.cpp index 5196b1a4..179a0fdb 100644 --- a/tools/chatgui/src/call_video_decoder.cpp +++ b/tools/chatgui/src/call_video_decoder.cpp @@ -230,19 +230,29 @@ int CallVideoDecoder::receive(call_video_frame& f, QImage& image) { #endif } -call_video_caps CallVideoDecoder::capabilities() { +call_video_caps CallVideoDecoder::capabilities(const std::atomic* running) { static call_video_caps caps{}; - static std::once_flag once; - std::call_once(once, [] { + static std::mutex lock; + static bool initialized = false; + auto cancelled = [running] { + if (!running || running->load()) return false; + DEBUG_INFO(DEBUG_CATEGORY_CALL, "video decoder capability probe cancelled by stop"); return true; + }; + std::unique_lock guard(lock, std::defer_lock); + while (!guard.try_lock()) { if (cancelled()) return {}; QThread::usleep(1000); } + if (initialized) return caps; + call_video_caps probed{}; for (unsigned codec = 1; codec <= 2; ++codec) { unsigned profiles = 0, maximumTier = 0; for (unsigned profile = 1; profile <= (codec == 1 ? 2u : 1u); ++profile) { for (unsigned tier = 0; tier < 2; ++tier) { const unsigned width = tier ? 1920 : 1280, height = tier ? 1080 : 720; for (Backend backend : {Backend::HardwareOnly, Backend::SoftwareOnly}) { + if (cancelled()) return {}; bool bothOrientations = true; unsigned backendPipeline = 0; for (int portrait = 0; portrait <= 1 && bothOrientations; ++portrait) { + if (cancelled()) return {}; const unsigned w = portrait ? height : width, h = portrait ? width : height; uint8_t bytes[8192]; int size = call_video_probe_key(codec, profile, w, h, bytes, sizeof(bytes)); if (size < 0) { bothOrientations = false; break; } @@ -254,6 +264,7 @@ call_video_caps CallVideoDecoder::capabilities() { unsigned sent = 0, received = 0; bool valid = true, outputBeforeEos = false; const int64_t start = call_video_playout_now_us(); while (valid && received < 8 && call_video_playout_now_us() - start < 1500000) { + if (cancelled()) return {}; if (sent < 8 && call_video_playout_now_us() - start >= sent * 33333ll) { input.frame_id = sent + 1; input.pts_us = 1000000 + sent * 33333ll; int result = decoder.submit(input); if (result < 0) valid = false; else if (result) ++sent; @@ -293,9 +304,9 @@ call_video_caps CallVideoDecoder::capabilities() { const uint16_t width = maximumTier ? 1920 : 1280, height = maximumTier ? 1080 : 720; call_video_limit limit{width, height, 30, uint32_t(width) * height * 30, 4000000, (uint8_t)profiles, (uint8_t)(codec == 1 ? (maximumTier ? 40 : 31) : (maximumTier ? 120 : 93))}; - if (!call_video_limit_orientations(&limit, codec)) caps.decode[codec - 1] = limit; + if (!call_video_limit_orientations(&limit, codec)) probed.decode[codec - 1] = limit; } } - }); + caps = probed; initialized = true; return caps; } diff --git a/tools/chatgui/src/call_video_decoder.h b/tools/chatgui/src/call_video_decoder.h index a3eba27d..4c8f14d8 100644 --- a/tools/chatgui/src/call_video_decoder.h +++ b/tools/chatgui/src/call_video_decoder.h @@ -2,6 +2,7 @@ #include "../../../src/call/call_video.h" #include #include +#include // Один RX worker. Независимые submit/receive сохраняют PTS при задержанном выходе. // Automatic использует проверенный capabilities() GPU, затем четыре CPU slice-потока. @@ -21,7 +22,8 @@ public: QString error() const; void useSoftware(); // После реального отказа устройства: следующий KEY открывает CPU, без повторной GPU пробы. void close(); - static call_video_caps capabilities(); + // running отменяет длительную пробу при stop; незавершённый результат не кэшируется. + static call_video_caps capabilities(const std::atomic* running = nullptr); private: struct Impl; std::unique_ptr m; diff --git a/tools/chatgui/src/call_video_engine.cpp b/tools/chatgui/src/call_video_engine.cpp index 4826eca5..48c98f24 100644 --- a/tools/chatgui/src/call_video_engine.cpp +++ b/tools/chatgui/src/call_video_engine.cpp @@ -253,7 +253,7 @@ void CallVideoEngine::setVideo(bool enabled, const QByteArray& cameraId, int wid } void CallVideoEngine::transmit() { - call_video_caps caps = CallVideoDecoder::capabilities(); + call_video_caps caps = CallVideoDecoder::capabilities(&m->running); // Не связываем приём с наличием собственного encoder. for (unsigned codec = 1; codec <= 2 && m->running; ++codec) { for (const QSize size : {QSize(1920, 1080), QSize(1280, 720)}) { diff --git a/tools/chatgui/tests/test_audio_diagnostics.cpp b/tools/chatgui/tests/test_audio_diagnostics.cpp index 2ead1d97..060f9238 100644 --- a/tools/chatgui/tests/test_audio_diagnostics.cpp +++ b/tools/chatgui/tests/test_audio_diagnostics.cpp @@ -35,7 +35,7 @@ int main() { assert(capture.captureLatency.low == 96000 && capture.captureLatency.high == 100000); assert(capture.captureLatency.count == 3 && capture.captureLatency.average() == 97333); assert(capture.captureBlock.low == 10000 && capture.captureBlock.high == 10000); - report(devices, now(CLOCK_MONOTONIC), 1.0); + report(devices, wallNow(), 1.0); timing.first_us = 1034000; timing.missing = 0; timing.measured = 0; audio_diag_capture_clock(nullptr, &timing); assert(take(e)); consume(e, devices); @@ -54,7 +54,7 @@ int main() { assert(capture.playbackLatency.low == -1000 && capture.playbackLatency.high == 30000); assert(capture.playbackBlock.high == 25000 && capture.playbackMaxConverter == 1000); assert(capture.playbackLatency.average() == 14500 && capture.playbackBlock.low == 20000); - report(devices, now(CLOCK_MONOTONIC), 1.0); + report(devices, wallNow(), 1.0); assert(capture.playbackBlocks == 0 && capture.playbackLatency.count == 0 && capture.playbackBlock.high == 0); std::vector workers; for (int p = 0; p < producers; ++p) workers.emplace_back([p, &done]() {