From 4db89eeb3202425bb36d3e4a0b924b6dfc4e55b1 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 20 Oct 2026 01:25:24 +0200 Subject: [PATCH] Check cancelled codec preparation cannot publish partial capabilities --- tools/chatgui/tests/test_call_video_clock.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/chatgui/tests/test_call_video_clock.cpp b/tools/chatgui/tests/test_call_video_clock.cpp index 2af0e9a4..1ab3a95a 100644 --- a/tools/chatgui/tests/test_call_video_clock.cpp +++ b/tools/chatgui/tests/test_call_video_clock.cpp @@ -25,13 +25,16 @@ static int64_t start; static bool disturbed = false; static bool slowDecoder = false, holdAck = false, limitedDisplay = false; static std::atomic decodedFrames{0}; -static std::atomic codecOpens{0}; +static std::atomic codecOpens{0}, decoderOpens{0}; +static std::atomic* cancelEncoderProbe = nullptr; static std::atomic displayThread{0}; static std::atomic unsafeTimer{false}; static size_t threadId() { return std::hash{}(std::this_thread::get_id()); } static int64_t nowUs() { return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); } extern "C" int __real_avcodec_open2(AVCodecContext*, const AVCodec*, AVDictionary**); extern "C" int __wrap_avcodec_open2(AVCodecContext* context, const AVCodec* codec, AVDictionary** options) { + if (av_codec_is_decoder(codec)) ++decoderOpens; + else if (cancelEncoderProbe) *cancelEncoderProbe = false; ++codecOpens; return __real_avcodec_open2(context, codec, options); } extern "C" int __real_avcodec_receive_frame(AVCodecContext*, AVFrame*); @@ -115,6 +118,11 @@ static bool queuePressure() { int main(int argc, char** argv) { QCoreApplication app(argc, argv); debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_CALL, DEBUG_LEVEL_DEBUG); + // Отмена после готового decoder, но посреди encoder: частичная общая матрица не должна попасть в кэш. + std::atomic interrupted{true}; cancelEncoderProbe = &interrupted; + const auto abandoned = CallVideoEngine::capabilities(&interrupted); cancelEncoderProbe = nullptr; + if (interrupted || abandoned.encode[0].profiles || abandoned.decode[0].profiles || !decoderOpens) return 1; + const unsigned decodedBeforeWarmup = decoderOpens; // Как при старте GUI: подготовка в worker, event loop работает, повторный вызов не открывает codec. std::atomic preparing{true}, prepared{false}; call_video_caps ready{}; @@ -124,7 +132,8 @@ int main(int argc, char** argv) { const int64_t warming = nowUs(); while (!prepared && nowUs() - warming < 10000000) { app.processEvents(); QThread::msleep(1); } preparing = false; warmup.join(); pulse.stop(); - if (!ticks || !ready.decode[0].profiles || !ready.decode[1].profiles || !codecOpens) return 1; + if (!ticks || !ready.decode[0].profiles || !ready.decode[1].profiles || !codecOpens + || decoderOpens != decodedBeforeWarmup) return 1; const unsigned opened = codecOpens; const auto cancelled = CallVideoEngine::capabilities(&preparing); if (cancelled.encode[0].profiles || cancelled.decode[0].profiles) return 1;