如何让Python在MacOS下以正确帧率录制屏幕?
修复MacOS下Python屏幕录制帧率不匹配问题
问题根源
你判断的完全正确:脚本实际捕获帧率远低于设定的30fps,但ffmpeg被强制按30fps固定帧率编码,导致视频时长被压缩,播放速度过快。后期放慢时,因为实际捕获的帧数量不足,就会出现严重卡顿。此外,ImageGrab.grab()在MacOS上性能较差,是导致捕获帧率上不去的核心原因之一。
修复方案1:修改现有脚本(加入帧率控制+优化捕获)
以下是优化后的脚本,核心改进点:
- 加入帧率控制逻辑,确保每帧捕获间隔符合目标FPS
- 让ffmpeg使用**可变帧率(VFR)**编码,避免强制固定帧率导致的速度偏差
- 替换
ImageGrab为MacOS原生的QuartzAPI,大幅提升屏幕捕获性能
import cv2 import numpy as np import subprocess import time from Quartz import CGDisplayCreateImage, CGDisplayBounds, CGImageGetWidth, CGImageGetHeight, CGDataProviderCopyData, CFDataGetBytePtr from PIL import Image def capture_screen(): # 用Mac原生Quartz API捕获屏幕 display = CGDisplayCreateImage(0) bounds = CGDisplayBounds(0) width = int(CGImageGetWidth(display)) height = int(CGImageGetHeight(display)) # 转换为PIL Image格式 data_provider = CGImageGetDataProvider(display) data = CGDataProviderCopyData(data_provider) bytes_per_row = CGImageGetBytesPerRow(display) img = Image.frombytes('RGBA', (width, height), CFDataGetBytePtr(data), 'raw', 'BGRA', bytes_per_row) return img def record_screen(): screen_width, screen_height = 1440, 900 # 匹配你的屏幕分辨率 target_fps = 30 frame_interval = 1.0 / target_fps # 每帧的理论间隔时间 # 修改ffmpeg命令:移除强制输入帧率,加入可变帧率编码 ffmpeg_cmd = [ 'ffmpeg', '-y', # 覆盖已有输出文件 '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt', 'bgr24', '-s', f'{screen_width}x{screen_height}', '-i', '-', # 从管道读取输入 '-an', # 不录制音频 '-vcodec', 'libx264', '-pix_fmt', 'yuv420p', '-crf', '18', # 高质量编码(18-23为推荐范围) '-preset', 'medium', # 平衡编码速度与文件大小 '-vsync', 'vfr', # 启用可变帧率,匹配实际输入帧率 'screen_recording.mp4' ] ffmpeg_process = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE) frame_count = 0 while True: frame_start = time.time() # 捕获并处理帧 img = capture_screen() img_np = np.array(img) frame = cv2.cvtColor(img_np, cv2.COLOR_RGBA2BGR) resized_frame = cv2.resize(frame, (screen_width, screen_height)) # 写入ffmpeg管道 ffmpeg_process.stdin.write(resized_frame.tobytes()) # 显示录制预览 cv2.imshow('Screen Recording', resized_frame) # 帧率控制:计算需等待的时间,确保符合目标FPS elapsed = time.time() - frame_start if elapsed < frame_interval: time.sleep(frame_interval - elapsed) # 按q键停止录制 if cv2.waitKey(1) & 0xFF == ord('q'): break frame_count += 1 # 清理资源 ffmpeg_process.stdin.close() ffmpeg_process.wait() cv2.destroyAllWindows() if __name__ == "__main__": # 需先安装依赖:pip install pyobjc opencv-python numpy pillow record_screen()
修复方案2:直接使用FFmpeg原生命令(推荐)
对于MacOS,直接用FFmpeg的原生录屏功能性能更优,完全避免帧率不匹配问题,无需Python脚本:
- 先查看可用的屏幕/音频设备:
ffmpeg -f avfoundation -list_devices true -i ""
输出中会显示屏幕设备编号(通常为0或1)和音频设备编号。
- 执行录屏命令(替换
1为你的屏幕设备编号):
ffmpeg -f avfoundation -framerate 30 -i "1:0" -crf 18 -preset medium screen_recording.mp4
参数说明:
-framerate 30:指定目标录制帧率"1:0":前半部分为屏幕设备编号,后半部分为音频设备编号(0表示不录音频,需录音频则替换为对应编号)-crf 18:高质量编码(值越小质量越高)-preset medium:平衡编码速度与文件大小
额外说明
- 方案1需安装依赖:
pip install pyobjc opencv-python numpy pillow - 方案2需先安装FFmpeg,可通过Homebrew安装:
brew install ffmpeg
内容的提问来源于stack exchange,提问作者John Thesaurus
相关产品推荐
相关产品推荐

