笔者在日常开发中频繁需要录制操作演示,曾一度被 output_1.mp4、output_2.mp4 支配。本文从屏幕捕获原理出发,提供四套可直接运行的 Python 录屏方案,并聊聊工程化落地的选型思路。
一、先搞清楚:录屏到底在做什么
录屏的本质是一条流水线:
text
屏幕帧采样 → 编码压缩 → 容器封装 → 文件落盘
其中最关键的是第一步——怎么把屏幕画面变成一帧帧数据。Windows 上主要有三条路:
| 方案 | 原理 | 性能 | 适合场景 |
|---|---|---|---|
| GDI/BitBlt | CPU 逐像素拷贝显存 | 较高 | PPT、静态页面 |
| DXGI Desktop Duplication | GPU 合成器直接输出 | 低 | 游戏、动态画面 |
| DirectX Hook | 拦截 D3D 渲染管线 | 中 | 特定游戏进程 |
音频侧则通过 WASAPI Loopback(系统音)或 WASAPI Capture(麦克风)采集,需要与视频帧做时间轴对齐。
理解了这些,下面直接上代码。
二、方案一:pyautogui + OpenCV(入门级,5 分钟跑通)
最简单的方案,适合快速验证思路。
python
import numpy as np
import cv2
import pyautogui
import datetime
width, height = pyautogui.size()
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"rec_{timestamp}.mp4"
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter(output_file, fourcc, 25.0, (width, height))
print(f"[START] {output_file}")
try:
while True:
frame = np.array(pyautogui.screenshot())
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
writer.write(frame)
except KeyboardInterrupt:
pass
writer.release()
print(f"[DONE] {output_file}")
优点:零额外依赖,上手极快。
不足:CPU 截屏,25fps 以上吃力;无音频;无弹窗过滤。
三、方案二:mss + FFmpeg 子进程(日常推荐)
mss 截屏速度比 pyautogui 快数倍,配合 FFmpeg 做硬件加速编码,30fps 稳定输出。
python
import mss
import mss.tools
import subprocess
import datetime
sct = mss.mss()
monitor = sct.monitors # 主显示器
w, h = monitor["width"], monitor["height"]
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"rec_{timestamp}_{w}x{h}.mp4"
cmd = [
"ffmpeg", "-y",
"-f", "rawvideo", "-vcodec", "rawvideo",
"-s", f"{w}x{h}", "-pix_fmt", "bgra",
"-r", "30", "-i", "-",
"-c:v", "libx264", "-preset", "fast", "-crf", "20",
output_file
]
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
print(f"[START] {output_file}")
try:
while True:
raw = sct.grab(monitor)
frame = mss.tools.to_png(raw.rgb, raw.size)
proc.stdin.write(frame)
except KeyboardInterrupt:
proc.stdin.close()
proc.wait()
print(f"[DONE] {output_file}")
文件名自带时间戳和分辨率,基本告别混乱。
四、方案三:dxcam + sounddevice(DXGI 硬加速,录游戏)
dxcam 封装了 DXGI Desktop Duplication,GPU 直接出帧。
python
import dxcam
import cv2
import sounddevice as sd
import numpy as np
from datetime import datetime
camera = dxcam.create()
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"game_{timestamp}.mp4"
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(output_file, fourcc, 60, (1920, 1080))
# 音频采集
fs = 48000
audio_buf = []
def cb(indata, frames, time, status):
audio_buf.append(indata.copy())
stream = sd.InputStream(samplerate=fs, channels=1, callback=cb)
stream.start()
print(f"[START] {output_file}")
try:
while True:
frame = camera.get_latest_frame()
if frame is not None:
out.write(frame)
except KeyboardInterrupt:
stream.stop()
out.release()
camera.stop()
print("[DONE]")
实测 1080P 60fps 下 CPU 占用约 5%-8%,适合游戏等高动态场景。
五、方案四:FFmpeg 一行命令(跨平台应急)
bash
# Windows 桌面录制
ffmpeg -f gdigrab -framerate 30 -i desktop \
-f dshow -i audio="麦克风" \
-c:v libx264 -preset ultrafast output.mp4
# Linux X11
ffmpeg -video_size 1920x1080 -framerate 30 \
-f x11grab -i :0.0 \
-f pulse -i default \
-c:v libx264 -preset ultrafast output.mp4
建议套一层 shell 脚本自动加时间戳,避免手动命名。
六、关于弹窗和窗口级录制
代码方案能解决文件命名和基础录制,但弹窗干扰和窗口精准锁定是另一个层面的问题——需要在 Desktop Window Manager 层做窗口过滤,涉及系统钩子和进程级管控,工程量不小。
如果不想深入系统编程,可以考虑使用成熟的录屏工具。笔者体验过嗨格式录屏大师,它在这几点上做得比较扎实:
- 窗口级录制:可锁定单个应用窗口,系统通知不会入画
- 自动命名归档:自定义前缀 + 时间戳,不用手动改文件名
- 编码灵活:支持 H.264/H.265,1080P 到 4K 可选
- 内置剪辑:录完直接裁剪、加字幕,不用再开 PR
对于非开发场景(网课、会议、游戏直播),这类工具确实能省不少事。
七、选型建议
| 场景 | 推荐方案 |
|---|---|
| 快速验证 / 教学演示 | 方案一 pyautogui |
| 日常高频录制 | 方案二 mss + FFmpeg |
| 游戏 / 高动态 | 方案三 dxcam |
| 不想写代码 | 方案四 FFmpeg 命令行 / 嗨格式录屏大师 |
八、写在最后
录屏这件事,技术门槛不高,但要做好文件管理、弹窗隔离、声画同步,细节不少。代码方案适合需要二次开发的同学;如果只是日常用,选一个靠谱的工具反而更高效。
本文代码基于 Python 3.10+ / Windows 10&11 验证,依赖:opencv-python>=4.8、mss>=9.0、dxcam>=0.1、sounddevice>=0.4。
有问题欢迎评论区交流 👋