From 61378d6b911d30ef7ec095bcbb25b243ea07673c Mon Sep 17 00:00:00 2001 From: Timo Rothenpieler Date: Tue, 16 Sep 2025 00:13:46 +0200 Subject: [PATCH] avfilter/vsrc_gfxcapture: fix possible missed wakeup race in capture loop --- libavfilter/vsrc_gfxcapture_winrt.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/libavfilter/vsrc_gfxcapture_winrt.cpp b/libavfilter/vsrc_gfxcapture_winrt.cpp index 6477e56918..0849380b3a 100644 --- a/libavfilter/vsrc_gfxcapture_winrt.cpp +++ b/libavfilter/vsrc_gfxcapture_winrt.cpp @@ -123,8 +123,8 @@ struct GfxCaptureContextWgc { std::mutex frame_arrived_mutex; std::condition_variable frame_arrived_cond; - std::atomic window_closed { false }; - std::atomic frame_seq { 0 }; + bool window_closed { false }; + uint64_t frame_seq { 0 }; SizeInt32 cap_size { 0, 0 }; RECT client_area_offsets { 0, 0, 0, 0 }; @@ -196,12 +196,18 @@ static HRESULT get_activation_factory(GfxCaptureContextCpp *ctx, PCWSTR clsid, T ****************************************************/ static void wgc_frame_arrived_handler(const std::unique_ptr &wgctx) { - wgctx->frame_seq.fetch_add(1, std::memory_order_release); + { + std::lock_guard lock(wgctx->frame_arrived_mutex); + wgctx->frame_seq += 1; + } wgctx->frame_arrived_cond.notify_one(); } static void wgc_closed_handler(const std::unique_ptr &wgctx) { - wgctx->window_closed.store(true, std::memory_order_release); + { + std::lock_guard lock(wgctx->frame_arrived_mutex); + wgctx->window_closed = true; + } wgctx->frame_arrived_cond.notify_one(); } @@ -1455,23 +1461,22 @@ static int gfxcapture_activate(AVFilterContext *avctx) if (!ff_outlink_frame_wanted(outlink)) return FFERROR_NOT_READY; - std::unique_lock frame_lock(wgctx->frame_arrived_mutex); - for (;;) { - uint64_t last_seq = wgctx->frame_seq.load(std::memory_order_acquire); + uint64_t last_seq = wgctx->frame_seq; int ret = process_frame_if_exists(outlink); if (ret != AVERROR(EAGAIN)) return ret; - if (wgctx->window_closed.load(std::memory_order_acquire)) { + std::unique_lock frame_lock(wgctx->frame_arrived_mutex); + + if (wgctx->window_closed && wgctx->frame_seq == last_seq) { ff_outlink_set_status(outlink, AVERROR_EOF, ctx->last_pts - ctx->first_pts + 1); break; } if (!wgctx->frame_arrived_cond.wait_for(frame_lock, std::chrono::seconds(1), [&]() { - return wgctx->frame_seq.load(std::memory_order_acquire) != last_seq || - wgctx->window_closed.load(std::memory_order_acquire); + return wgctx->frame_seq != last_seq || wgctx->window_closed; })) break; }