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

Python开发屏幕录制程序出现低FPS、掉帧卡顿问题如何解决?

问题原因
  • 屏幕捕获模块性能极差:PIL.ImageGrab.grab() 为纯Python实现的截屏接口,1920*1080分辨率下单次截屏耗时普遍超过100ms,叠加后续数组转换、编码耗时,实际循环帧率远达不到你设定的fps值。拖动窗口时系统桌面渲染负载升高,截屏耗时会进一步上涨,必然出现大量掉帧。
  • 色彩空间转换逻辑错误且冗余:ImageGrab 输出的图像为RGB通道顺序,OpenCV的VideoWriter写入需要BGR通道顺序,你代码中调用cv2.cvtColor时传入参数cv2.COLOR_BGR2RGB,转换方向完全写反,既额外消耗CPU算力,输出的视频还会出现蓝红通道互换的偏色问题。
  • 编码器与帧率设置不合理:你选用的XVID为软编码器,1080P分辨率下单帧编码耗时高,进一步拖慢整体处理速度;代码中设置fps=8.0本身远低于显示器120Hz的刷新率,就算没有性能问题,输出视频也会有明显卡顿感。
  • 缺少帧率控制与流程解耦:当前代码单线程串行执行截屏、转换、写入操作,循环运行速度完全受每一步耗时影响,实际采集帧率波动极大,写入视频的帧时间戳完全错乱,播放时自然会出现卡顿、速度不均的问题。
优化方案

按优先级执行以下优化:

  • 替换高性能截屏库:Windows平台优先用dxcam(基于DXGI桌面复制接口,1080P下单次截屏耗时不到1ms,支持百帧级采集),跨平台场景可以用mss,性能是ImageGrab的3-5倍,完全可以满足流畅录屏需求。
  • 砍掉冗余计算:截屏时直接输出OpenCV需要的BGR格式,省掉色彩空间转换步骤。
  • 更换编码器:用mp4v编码器替代XVID,编码效率更高,输出的mp4文件兼容性也更好。
  • 多线程解耦流程:把截屏和视频写入拆成两个独立线程,截屏线程只负责抓帧存入队列,写入线程从队列取帧编码,避免截屏等待时阻塞编码流程,减少掉帧。
  • 增加帧率控制逻辑:通过计时稳定采集间隔,保证输出帧率和设定值一致,避免帧率波动导致的播放卡顿。
优化后参考代码
import cv2
import time
import queue
import threading
import dxcam  # 安装命令:pip install dxcam opencv-python
# 非Windows平台替换为mss即可,性能同样远高于ImageGrab

# 录屏配置
TARGET_FPS = 60  # 日常录屏60fps足够流畅,性能够也可以设为120
SCREEN_RES = (1920, 1080)
SAVE_PATH = "output.mp4"

frame_queue = queue.Queue(maxsize=20)
is_running = True

def capture_worker():
    """截屏线程:仅负责高速抓帧"""
    # 直接输出BGR格式,无需额外色彩转换
    cam = dxcam.create(output_idx=0, output_color="BGR")
    cam.start(target_fps=TARGET_FPS)
    interval = 1 / TARGET_FPS
    next_trigger = time.time()
    while is_running:
        now = time.time()
        if now >= next_trigger:
            frame = cam.get_latest_frame()
            # 队列满就丢最旧的帧,避免延迟累积
            if frame is not None:
                if frame_queue.full():
                    try:
                        frame_queue.get_nowait()
                    except queue.Empty:
                        pass
                frame_queue.put(frame)
            next_trigger += interval
            # 修正时间累积误差
            if next_trigger < now:
                next_trigger = now + interval
    cam.stop()

def write_worker():
    """写入线程:仅负责视频编码存盘"""
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    writer = cv2.VideoWriter(SAVE_PATH, fourcc, TARGET_FPS, SCREEN_RES)
    while is_running or not frame_queue.empty():
        if not frame_queue.empty():
            frame = frame_queue.get()
            writer.write(frame)
        else:
            time.sleep(0.001)
    writer.release()

def start_record():
    global is_running
    # 启动工作线程
    t_capture = threading.Thread(target=capture_worker, daemon=True)
    t_write = threading.Thread(target=write_worker, daemon=True)
    t_capture.start()
    t_write.start()

    # 按键盘q键停止录制
    while True:
        if cv2.waitKey(1) & 0xFF == ord('q'):
            is_running = False
            break
        time.sleep(0.01)
    
    t_capture.join()
    t_write.join()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    start_record()

注:如果不想用dxcam,替换为mss时只需要修改capture_worker里的截屏逻辑即可,其余多线程、写入逻辑不用改。不要强行把目标帧率设到超过硬件实际能处理的上限,否则还是会出现帧时间戳错乱的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:18:37