使用AVFoundation录制Mac屏幕时AVCapture Session录制失败求助
解决AVFoundation命令行录屏工具的Cannot Capture错误(Code=-11844)
我之前在做Mac命令行录屏工具时也碰到过一模一样的错误,结合AVFoundation在非GUI环境下的特性,这个问题通常和权限、配置或者命令行环境的特殊性有关,咱们一步步来排查:
1. 优先检查屏幕录制权限
MacOS对屏幕录制有严格的权限控制,命令行工具的权限逻辑和GUI应用不一样:
- 打开「系统偏好设置」→「安全性与隐私」→「隐私」→「屏幕录制」
- 把你的命令行工具(或者运行它的终端/Xcode,如果是调试的话)添加到权限列表里
- 重启终端/Xcode或者你的工具,确保权限生效
很多时候这个错误就是因为权限没给到位,AVFoundation没法访问屏幕捕获接口。
2. 检查Capture Session的配置是否合理
错误里提到的图形子系统问题,大概率和输入输出的格式不兼容有关:
- 避免使用自定义的过高分辨率,先试试用系统预设的
AVCaptureSessionPresetHigh(Swift里是.high) - 检查
AVCaptureScreenInput的preferredActiveFormat,确保选择的是当前显示器支持的格式,比如可以通过screenInput.availableActiveFormats枚举所有支持的格式,选一个合适的 - 不要同时尝试捕获多个屏幕或者不支持的像素格式(比如某些旧Mac不支持4K@60fps的录制)
3. 确保命令行工具运行了RunLoop
GUI应用默认有NSApplication的事件循环,但命令行工具没有,而AVFoundation的Capture Session依赖RunLoop来处理捕获事件:
- 如果你用Objective-C,在启动录制后要启动RunLoop,比如:
// 启动录制后,让RunLoop运行指定时长 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];
- 如果是Swift,类似这样:
// 运行RunLoop直到指定时间点 RunLoop.current.run(until: Date().addingTimeInterval(10))
要是不启动RunLoop,Capture Session还没初始化完成,程序就直接退出了,自然会抛出捕获失败的错误。
4. 排查硬件/系统兼容性
如果上面的方法都没用,可能是硬件或者系统版本的问题:
- 确认你的Mac系统版本是否支持
AVCaptureScreenInput(这个API从macOS 10.11开始可用) - 旧款Mac的图形硬件可能不支持某些高分辨率录制,试试降低录制分辨率再测试
示例代码片段(Swift)
这里给一个简化的正确配置示例,你可以参考调整:
import AVFoundation class RecorderDelegate: NSObject, AVCaptureFileOutputRecordingDelegate { func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { if let error = error { print("录制出错:\(error.localizedDescription)") } else { print("录制完成,文件路径:\(outputFileURL.path)") } // 退出RunLoop RunLoop.current.stop() } } let recorderDelegate = RecorderDelegate() let session = AVCaptureSession() session.sessionPreset = .high // 创建屏幕输入 guard let screenInput = AVCaptureScreenInput(displayID: CGMainDisplayID()), session.canAddInput(screenInput) else { fatalError("无法初始化屏幕输入") } session.addInput(screenInput) // 创建视频输出 let movieOutput = AVCaptureMovieFileOutput() guard session.canAddOutput(movieOutput) else { fatalError("无法添加视频输出") } session.addOutput(movieOutput) // 开始录制 let outputPath = "/tmp/screen_recording.mp4" let outputURL = URL(fileURLWithPath: outputPath) movieOutput.startRecording(to: outputURL, recordingDelegate: recorderDelegate) // 启动RunLoop session.startRunning() RunLoop.current.run()
先从权限和RunLoop这两个最常见的问题入手排查,应该能解决大部分情况。
内容的提问来源于stack exchange,提问作者Suresh Kumar S
相关产品推荐
相关产品推荐

