avfilter/vsrc_gfxcapture: fix possible missed wakeup race in capture loop

This commit is contained in:
Timo Rothenpieler
2025-09-16 00:13:46 +02:00
parent af35a13f6d
commit 61378d6b91

View File

@@ -123,8 +123,8 @@ struct GfxCaptureContextWgc {
std::mutex frame_arrived_mutex;
std::condition_variable frame_arrived_cond;
std::atomic<bool> window_closed { false };
std::atomic<uint64_t> 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<GfxCaptureContextWgc> &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<GfxCaptureContextWgc> &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;
}