Graphics & Games 进阶 20m
在 Mac 上使用 ReplayKit 录屏和直播
Capture and stream apps on the Mac with ReplayKit
2020年6月26日
一句话判断
如果你的 Mac 应用需要录屏或直播功能,ReplayKit 现在可以在 macOS 上用了——而且是系统级的、低性能开销的实现。
这场 Session 讲了什么
这场 Session 介绍了 ReplayKit 在 macOS 上的首次完整支持。ReplayKit 最初是 iOS 的录屏框架,2020 年终于来到了 macOS,让 Mac 应用也能集成录制和直播功能。
演讲者首先介绍了 macOS 上 ReplayKit 的三种录制模式:App Recording(只录制应用自身的窗口)、Screen Recording(录制整个屏幕,包括其他应用)和 Broadcast(直播推流到服务器)。每种模式有不同的权限要求和隐私考量。
App Recording 是最简单的模式,只需要用户在应用内确认即可。Screen Recording 需要用户在系统偏好设置中授予权限。Broadcast 则需要一个 Broadcast Upload Extension 来处理视频帧的编码和推流。
Session 的核心部分讲解了如何配置录制参数(分辨率、帧率、音频源),以及如何使用 RPScreenRecorder 的 API 来控制录制的开始/暂停/恢复/停止。演讲者还介绍了录制后的编辑界面——RPPreviewViewController 提供了内置的视频裁剪和分享功能。
最后讨论了性能考量。ReplayKit 使用系统的硬件编码器,CPU 开销很低。但录制会占用 GPU 资源,对于已经 GPU 密集的应用(如游戏),可能会影响帧率。
值得深挖的点
- Broadcast Upload Extension 的架构:直播推流需要创建一个 App Extension,ReplayKit 会将每一帧的视频和音频数据发送到这个 Extension 中处理。Extension 负责编码和推流。这种架构将录制逻辑和应用逻辑隔离,即使应用崩溃,直播流也不会中断。
- 隐私与权限模型:macOS 的屏幕录制权限在系统偏好设置 > 安全性与隐私 > 屏幕录制中管理。如果用户拒绝了这个权限,你的应用无法录制屏幕。Apple 要求所有使用 Screen Recording 的应用必须在 App Store 审核时说明录制用途。
代码片段
// 开始录制应用窗口
import ReplayKit
class RecordingManager: NSObject, RPScreenRecorderDelegate {
let recorder = RPScreenRecorder.shared()
func startRecording() {
// 检查是否可用
guard recorder.isAvailable else {
print("ReplayKit 不可用")
return
}
recorder.isMicrophoneEnabled = true // 启用麦克风
recorder.isCameraEnabled = false // 不需要摄像头
recorder.startRecording(
handler: { error in
if let error = error {
print("录制启动失败: \(error)")
} else {
print("录制已开始")
}
}
)
}
func stopRecording() {
recorder.stopRecording { [weak self] previewVC, error in
if let previewVC = previewVC {
previewVC.previewControllerDelegate = self
self?.present(previewVC, animated: true)
}
}
}
}
// 处理录制预览的回调
extension RecordingManager: RPPreviewViewControllerDelegate {
func previewController(
_ previewController: RPPreviewViewController,
didFinishWithActivityTypes activityTypes: Set<RPActivityType>
) {
if activityTypes.contains(.saveToCameraRoll) {
print("视频已保存到相册")
}
if activityTypes.contains(.share) {
print("用户选择了分享")
}
previewController.dismiss(animated: true)
}
}
// 直播推流的 Broadcast Setup
// 在 Broadcast Upload Extension 中处理视频帧
class SampleHandler: RPSampleBufferQueueHandler {
override func processSampleBuffer(
_ sampleBuffer: CMSampleBuffer,
with sampleBufferType: RPSampleBufferType
) {
switch sampleBufferType {
case .video:
// 处理视频帧
if let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
encodeAndStreamVideoFrame(pixelBuffer)
}
case .audioMic:
// 处理麦克风音频
encodeAndStreamAudio(sampleBuffer)
case .audioApp:
// 处理应用音频
encodeAndStreamAppAudio(sampleBuffer)
@unknown default:
break
}
}
func encodeAndStreamVideoFrame(_ frame: CVPixelBuffer) {
// 使用 VideoToolbox 编码为 H.264
// 然后通过 RTMP 或其他协议推流
}
}
最佳实践
- 录制前检查
RPScreenRecorder.shared().isAvailable,某些设备或场景下可能不可用 - 使用 App Recording 模式而非 Screen Recording,除非你确实需要录制其他应用
- 录制时在 UI 上提供清晰的指示(如红色录制按钮),让用户知道正在录制
- 处理录制中断(如系统内存不足强制停止)和错误恢复
- GPU 密集型应用考虑降低录制分辨率以减少性能影响
还有什么值得关注
- macOS 的 ReplayKit 后来在 Monterey 中增加了更多功能,包括窗口级别录制的选择
- 如果你在做游戏直播工具,搭配 “Support performance-intensive apps and games” 一起看,了解性能优化的全局策略
- ReplayKit 的 iOS 实现已经有几年历史了,很多 macOS 上的 API 与 iOS 版本一致
WWDC 2020