用 ScreenCaptureKit 捕获 HDR 内容
Capture HDR content with ScreenCaptureKit
2024年6月10日
一句话判断
ScreenCaptureKit 今年的三个更新都很实用:HDR 流和截图捕获、麦克风音频混入同一个 SCStream、以及一个一行代码就能用的录制 API(SCRecordingOutput)——从此你不需要自己把 CMSampleBuffer 写进文件了。
这场 Session 讲了什么
ScreenCaptureKit 是 macOS 上做屏幕共享、截图、远程桌面的核心框架。今年的更新覆盖了三个场景:HDR 内容捕获、麦克风采集、以及录制输出。
HDR 捕获支持两种模式:Local Display(本机同时采集和渲染 HDR 内容)和 Canonical Display(HDR 内容优化后分享给其他设备)。配置方式很人性化,SCStreamConfiguration 提供了两个预置方法 captureHDRStreamLocalDisplay() 和 captureHDRStreamCanonicalDisplay(),把 colorSpace、pixelFormat、colorMatrix 这些细节全部预填好。如果你需要自定义,也可以逐项覆盖。
麦克风采集允许你在同一个 SCStream 上同时获取屏幕画面、系统音频和麦克风输入三种媒体。配置只需设置 captureMicrophone = true 和指定 microphoneCaptureDeviceID,然后用新的 .microphone 类型添加 SCStreamOutput。
SCRecordingOutput 是最省心的更新。以前要把屏幕内容录制成文件,你需要自己处理 CMSampleBuffer 的写入逻辑。现在只要给 SCStream 添加一个 SCRecordingOutput,指定文件路径、格式和编码器,ScreenCaptureKit 帮你搞定一切。
值得深挖的点
HDR 的两种显示模式该怎么选
Local Display 和 Canonical Display 的区别在于使用场景。如果你做一个同屏演示工具(比如把 Mac 画面投到同一台 HDR 显示器上),用 Local Display——它保留最原始的色彩信息,不做色调映射。如果你做视频会议或远程桌面(接收端可能是不同的显示器),用 Canonical Display——它会把内容转换成标准化的 HDR 信号,确保在不同设备上的观感一致。
背后的技术参数差异:Local Display 使用 10-bit BGRA 和 Display P3 PQ 色彩空间;Canonical Display 使用 10-bit YCbCr 和 ITU-R BT.2020 PQ 色彩空间。如果你不懂这些参数也没关系——预置方法帮你选好了最佳组合。但如果你做专业视频工具,可能需要覆盖 colorMatrix 属性来精确控制色彩转换。
ScreenshotManager 也同样支持 HDR 截图,提供 captureHDRScreenshotLocalDisplay() 和 captureHDRScreenshotCanonicalDisplay() 两个预置。截图可以输出为 CMSampleBuffer 或 CGImage,取决于你的后续处理流程。
SCRecordingOutput 把录制门槛降到了最低
以前的录制流程是:从 SCStream 拿到 CMSampleBuffer -> 创建 AVAssetWriter -> 手动处理时间戳和同步 -> 写入文件 -> 处理中断和错误。这套流程能写对的人不多,而且很容易出 bug。
SCRecordingOutput 把整个流程封装成一个 delegate 模式:你配置好 SCRecordingOutputConfiguration(文件路径、格式、编码器),添加到 SCStream 上,然后通过 SCRecordingOutputDelegate 协议接收录制事件通知。ScreenCaptureKit 内部处理所有 asset 写入细节。
这意味着录制功能不再是高级玩家的专属。任何一个已经在用 SCStream 做屏幕捕获的应用,加几行代码就能支持录制。文件格式支持标准视频容器,编码器可以选择 HEVC 等主流格式。
代码片段
用预置配置捕获 HDR 流
// 获取可分享内容
let content = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true)
let display = content.displays.first!
// 创建内容过滤器(捕获整个屏幕)
let filter = SCContentFilter(display: display, excludingWindows: [])
// 用预置方法获取 HDR 配置,不用手动设参数
let config = SCStreamConfiguration()
config.captureDynamicRange = .hdrCanonicalDisplay
config.pixelFormat = kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
config.colorSpaceName = CGColorSpace.itUR_2020_PQ
let stream = SCStream(filter: filter, configuration: config, delegate: nil)
stream.addStreamOutput(self, type: .screen, sampleHandlerQueue: .main)
try await stream.startCapture()
场景:捕获 HDR 屏幕内容用于远程共享。坑:如果捕获的不是 HDR 屏幕,设置了 HDR 参数也不会报错,输出会回退到 SDR——需要自己检查显示器的 HDR 能力。
截取 HDR 截图
// HDR 截图也支持预置
let config = SCStreamConfiguration.captureHDRScreenshotLocalDisplay()
// 需要原始数据用 captureSampleBuffer
if let sampleBuffer = try? await SCScreenshotManager.captureSampleBuffer(
contentFilter: filter, configuration: config) {
// 处理 CMSampleBuffer
}
// 需要 CGImage 用 captureImage(更方便)
if let image = try? await SCScreenshotManager.captureImage(
contentFilter: filter, configuration: config) {
// 直接拿到 CGImage
}
场景:截取单张 HDR 截图。坑:captureImage 返回的 CGImage 包含 HDR 色彩信息,直接显示在 SDR 上下文里可能看起来不对——需要确保渲染目标也支持 HDR。
添加麦克风采集
let config = SCStreamConfiguration()
config.captureMicrophone = true
config.microphoneCaptureDeviceID = getDefaultMicrophoneID()
let stream = SCStream(filter: filter, configuration: config, delegate: nil)
// 新的 .microphone 输出类型
stream.addStreamOutput(self, type: .microphone, sampleHandlerQueue: .main)
// 在 delegate 里区分三种类型
func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {
switch type {
case .screen: // 视频帧
case .audio: // 系统音频
case .microphone: // 麦克风音频
@unknown default: break
}
}
场景:在屏幕录制中同时采集麦克风旁白。坑:三种输出类型可能在不同的 sampleHandlerQueue 上回调,如果需要做音视频同步,要注意线程安全。
最佳实践
已有项目: 如果你已经在用 SCStream,HDR 支持是最容易加的——切换到预置配置就行。录制功能则建议用 SCRecordingOutput 替换你手写的 AVAssetWriter 逻辑,减少维护负担。麦克风采集适合给现有屏幕共享加旁白功能。
新项目: 直接用预置方法初始化 SCStreamConfiguration,不要手动设 colorSpace 和 pixelFormat。除非你做的是专业视频工具,否则预置值够用了。录制功能从第一天就集成 SCRecordingOutput,不要重复造轮子。
还有什么值得关注
- SCRecordingOutput 支持通过 SCRecordingOutputDelegate 接收录制事件通知(开始、暂停、恢复、完成),方便做 UI 状态同步。
- 麦克风设备选择通过
microphoneCaptureDeviceID控制,默认选系统默认麦克风,也可以让用户自选。 - Presenter Overlay 功能仍然可用,和 HDR、麦克风采集不冲突。