1文章来自:吕大千 字节跳动飞书 2022-07-10 WWDC22 iOS;如有侵权请及时反馈联系;非商用仅记录;支持小专栏正版https://xiaozhuanlan.com/topic/0458326917
目前 ScreenCaptureKit 只支持 MacOS 12.3+,Mac Catalyst 15.4+ ,是比较新的操作系统。 这意味着如果应用需要支持更老的操作系统,兼容性还是需要考虑的。此外 ScreenCaptureKit 音频采集还是应用级别的, API 文档中很多音频相关的 API 还被标注为 Beta,这意味着以后还有变化的可能。
导言
屏幕录制一直以来都是一个桌面系统需要提供的基本能力,可以应用到很多场景,例如:视频会议中的桌面共享、电脑游戏直播、远程桌面控制等。 今年的 WWDC 苹果新推出了一个 MacOS 上的高性能屏幕录制框架 ScreenCaptureKit。 ScreenCaptureKit 不仅通过提供更加易于理解的 API 来简化开发成本,还大大提升了屏幕录制的性能,以便 MacOS 用户可以获得更佳的使用体验。
本文主要信息来源于以下两个 WWDC session:
Session 10155 Take ScreenCaptureKit to the next level ;https://developer.apple.com/videos/play/wwdc2022/10155
Session 10156 Meet ScreenCaptureKit
ScreenCaptureKit 前时代
在介绍 ScreenCaptureKit 之前,我们先看看苹果在推出 ScreenCaptureKit 前,MacOS 下有哪些主要的方法可以进行屏幕录制。
AVCaptureScreenInput
与正常采集摄像头视频流数据一样,将 AVCaptureScreenInput 作为 AVCaptureSession 的输入源,就能得到当前的屏幕图像数据。 这种方式的优点是:
- 可以通过调整
scaleFactor
来指定分辨率。 - 可以配置是否包含鼠标光标。
- 性能很好,可以达到 60fps,CPU 占用不显著。
不过也有显著的缺点,可定制性较差:
- 只能捕获整个屏幕,不能忽略窗口抓屏,不能只捕获某个窗口
CGDisplayStreamCreate
使用CGDisplayStreamCreate API 可以不通过 AVCaptureSession 直接创建一个屏幕图像数据流。 与 AVCaptureSession + AVCaptureScreenInput 的方式类似。优势:
- 可以通过来参数指定分辨率。
- 可以配置是否包含鼠标光标。
- 实时屏幕流,可以增量,性能很好,CPU 占用不显著。
也有同样的缺点,可定制性较差:
- 只能捕获整个屏幕,不能忽略窗口抓屏,不能只捕获某个窗口
CGDisplayCreateImage
CGDisplayCreateImage 以及 CGDisplayCreateImageForRect 系统 API 可以直接截取当前屏幕的图像。相对于视频采集 API, 这种方式的优点是:
- 可以排除特定窗口,抓屏时会自动忽略掉所有 sharingType 为 NSWindowSharingType::NSWindowSharingNone 的 NSWindow
但是缺点也很多:
- 无法指定分辨率, 只能是显示到屏幕的物理分辨率。
- 不能只抓去特定的窗口。
- 抓屏时会同时包含鼠标光标,无法去除。
- 调用开销比较大,CPU 占用显著提高,帧率不可控。
- 输出数据类型是 CGImageRef,需要应用层转换成原始数据
CGWindowListCreateImageFromArray
CGWindowListCreateImageFromArray 以及 CGWindowListCreateImage 系统 API 可以获得对应窗口的图像。虽然不可以指定任意分辨率抓屏,但是可以通过 CGWindowImageOption 参数选择按照原始物理分辨率抓屏(kCGWindowImageBestResolution),还是坐标分辨率抓屏(kCGWindowImageNominalResolution)。 同时也可以灵活控制捕获或者忽略特定窗口。
相对缺点是:
- 最小化或者被隐藏的窗口无法捕获图像
- 无法捕获到鼠标光标的图像,需要额外处理
- 和 CGDisplayCreateImage 类似,调用开销比较大,CPU 占用显著提高。
- 输出数据类型是 CGImageRef,需要应用层转换成原始数据
ReplayKit
还有一个取巧的方法,我们都知道在 iOS 平台有一个 ReplayKit 的框架,支持在 iOS 设备上抓屏。 近年来苹果在推动各个平台融合,ReplayKit 也被移植到 Mac 平台上了。 因此也可以通过 ReplayKit 在 Mac 上实现抓屏。参考 WWDC 2020 ReplayKit 相关 session。
Capture and stream apps on the Mac with ReplayKit - WWDC 2020 - Videos - Apple Developer
相对于其他方案 ReplayKit 的优点是:
- 能够捕获当前应用输出的音频
- 性能相对较好
但是 ReplayKit 也有很大的限制:
- ReplayKit 在 Mac 上仅可以实现当前应用的屏幕录制,因此也限制了应用场景
- 捕获图像不会包含鼠标光标
总结
在 ScreenCaptureKit 之前, macOS 上捕获特定窗口图像和捕获性能不可兼得。相关 API 使用起来也相对复杂,可配置性也不高。这些都促使了 ScreenCaptureKit 的推出。
ScreenCaptureKit
ScreenCaptureKit 集合了以前所有抓屏方法的优点,提供
- 提供整个屏幕、应用、窗口等不同级别的捕获能力
- 支持配置是否包含鼠标光标图像,输出的像素格式、色彩空间,帧率以及分辨率。 帧率和分辨率最高可与实际显示器显示的帧率分辨率一致。
- 支持以应用级别的声音采集,配置音频采集通道数量和采样率, 最高可达双通道 48khz 采样率
- 支持动态的选择捕获图像内容,以及动态的配置捕获参数
- 高性能: 充分利用 GPU 能力,低 CPU 消耗
- 隐私体验:苹果生态的隐私权限控制
总体架构
ScreenCaptureKit 提供了一套易于理解的 Swift 风格的 API 。结构如下:
应用层使用 ScreenCaptureKit 的核心对象是 SCStream
,SCStream
可以创建多个实例,每个实例相互独立,可以同时进行多路屏幕图像的捕获。
创建一个SCStream
对象,需要提供内容过滤器(SCContentFilter
)和配置参数(SCStreamConfiguration
)来控制捕获屏幕图像的内容。 通过配置 SCStream delegate 来处理屏幕捕获过程中的错误,通过配置 SCStreamOutput
对象来获得捕获到的数据。
ShareableContent
ShareableContent 是一个用来枚举当前系统可以被用来屏幕录制的实体的工具。我们能够通过它对应的数组属性得到当前有效的 SCDisplay, SCRunningApplication, SCWindow 对象。可以参考苹果官方文档:SCShareableContent
如何控制捕获内容
SCContentFilter
顾名思义这是一个用来控制共享内容的对象。 可以通过一系列的构造方法来创建SCContentFilter
对象。通过SCContentFilter
对象我们可以指定需要显示或者排除哪些应用或者窗口。
参考苹果官方文档:SCContentFilter
- CMSampleBuffer | Apple Developer Documentation
- ScreenCaptureKit | Apple Developer Documentation
- Meet ScreenCaptureKit
- Take ScreenCaptureKit to the next level
- https://blog.csdn.net/quanhaoH/article/details/126869537