You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Windows桌面复制API限制捕获帧率至60fps以内

针对Windows Desktop Duplication API的帧率限制方案

正确利用AcquireNextFrame()的超时参数

AcquireNextFrame()的wait参数不是直接设置固定帧间隔,而是等待新帧可用的最长超时时间。如果硬设为16ms(对应60fps理论间隔),当主显示器刷新率更高(比如200Hz)时,桌面合成器会更频繁生成帧,API会在新帧出现时立刻返回,导致捕获帧率跟着主显示器走。

要稳定限制在60fps,得结合时间戳动态计算等待时长,既保证间隔符合要求,又不会错过新帧:

  1. 用QueryPerformanceCounter或GetTickCount64记录每次成功捕获帧的时间戳
  2. 计算60fps对应的目标间隔:1000/60 ≈16.666ms
  3. 每次捕获前,计算当前时间与上次捕获时间的差值,若差值小于目标间隔,把wait参数设为剩余时间;若已超过,设为0立即尝试捕获

示例伪代码:

LARGE_INTEGER freq, lastCaptureTime, currentTime;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&lastCaptureTime);

while (true) {
    // 计算当前到下次目标捕获的剩余时间
    QueryPerformanceCounter(&currentTime);
    double elapsedMs = (currentTime.QuadPart - lastCaptureTime.QuadPart) * 1000.0 / freq.QuadPart;
    DWORD waitMs = max(0, (DWORD)(16.666 - elapsedMs));

    // 尝试捕获帧
    HRESULT hr = duplication->AcquireNextFrame(waitMs, &frameInfo, &desktopResource);
    if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
        // 超时无新帧,直接进入下一轮循环
        continue;
    }
    else if (SUCCEEDED(hr)) {
        // 处理捕获到的帧
        ProcessCapturedFrame(desktopResource);

        // 释放资源
        duplication->ReleaseFrame();

        // 更新捕获时间戳
        QueryPerformanceCounter(&lastCaptureTime);
    }
}

解决多显示器帧率异常问题

外接60Hz显示器捕获帧率跑到200fps,是因为Desktop Duplication API的帧更新和桌面合成器同步——主显示器高刷新率会让合成器频繁生成帧,哪怕外接显示器画面没变化,API也会触发捕获。

额外优化方案:

  • 检查frameInfo.LastPresentTime,如果和上一帧的时间戳一致(说明画面无更新),直接释放帧不处理,减少无效捕获
  • 若需求是匹配显示器原生刷新率,可通过IDXGIOutput::GetDisplayModeList获取外接显示器的实际刷新率,用该值计算目标间隔,而非固定60fps

为什么直接睡眠会丢帧

在AcquireNextFrame()之间加Sleep(16)会丢帧,原因有二:一是Windows系统睡眠精度有限(默认约10-15ms),实际间隔会偏离目标;二是睡眠期间如果有新帧生成,API不会主动通知,等睡眠结束再调用时,已经错过了多帧更新,导致画面延迟或丢帧。而动态调整wait参数的方式,是让API在等待期间主动监听新帧,有新帧就立刻返回,同时保证两次有效捕获的间隔不低于目标帧率要求。

内容的提问来源于stack exchange,提问作者unstuckkk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:12:12