大多数浏览器和
Developer App 均支持流媒体播放。
-
ScreenCaptureKit 简介
了解 ScreenCaptureKit 可以如何为您的 macOS 屏幕共享 App、视频会议 App、游戏流媒体服务等提供优质的屏幕捕获体验。我们将探索此 API 的构建块,学习如何配置流媒体以截取屏幕上的视频和音频内容,并分享相关技巧,帮助您将它集成到您的现有 App 中。
资源
相关视频
WWDC23
WWDC22
-
下载
Ernest: 大家好 欢迎 我是 Ernest ScreenCaptureKit 团队的 一名软件工程师 在过去的几年中 我们对远程协作的依赖度 日益提高 屏幕共享就是其中的 常用功能之一
最重要的是 总的来说 使用如 OBS Studio 录制 App 的 流媒体游戏和内容创作 已经成为了人们教育和娱乐 持续增长的领域
在这一概念下 我们创建了 满足开发者们需求的 高性能 稳定的屏幕捕获框架 那就是 ScreenCaptureKit
ScreenCaptureKit 是 macOS 中 一款全新框架 专为帮助您搭建 App 屏幕共享体验而设计 ScreenCaptureKit 提供 可让您选择 想要捕获内容的 API 开发者可按 App 需要 进行控制和切换 所有的过滤程序和控制 都可以实时更新
该框架可以高品质 高性能 提供高达屏幕显示的 原生分辨率和帧率 同时隐私安全 通过全局守卫得以保障
在这个讲座中 我会为您讲解 如何开始 ScreenCaptureKit 框架
您掌握基础知识后 可查看讲座 将 ScreenCaptureKit 提升到全新境界 以了解更高阶的内容
首先 我先回顾下该框架的 关键功能
然后 我将于 API 概述中 阐述 ScreenCaptureKit 的 主要构造
接着 我会为大家演示 如何用过滤器和配置 来配置您的 stream 流
最后 我带大家看下如何将您 App 的视频 和音频样本流媒体化
首先是 ScreenCaptureKit 的 关键功能
ScreenCaptureKit 可让您 指定您想要共享或过滤的 内容类型 您可以捕获任意屏幕内容 不管是屏幕显示 App 窗口以及音频的组合
ScreenCaptureKit 支持 多种开发者控制 包括像素格式 色彩空间 帧率 分辨率 以及音频方面 也可控制 采样率和通道数
这些过滤程序和配置 都可以实时调整 为 App 设计 提供了更高的灵活性
为了发送高达 48kHz 立体声的 音频样本 以及高达您屏幕显示原始分辨率 和帧率的视频 ScreenCaptureKit 主要聚焦于性能 并充分利用 Mac GPU 的能力 却比当前屏幕捕获方式 耗费更少的 CPU 当然 ScreenCaptureKit 非常注重隐私安全 为使用该框架的所有 App 都提供全局隐私保障
该框架在捕获视频和音频内容前 会请求用户许可 该选择也会存储于系统偏好中的 屏幕录制隐私设置中
现在您已经了解了 ScreenCaptureKit 的基本内容 我为大家演示下 API 中 一些最重要的概念 ScreenCaptureKit 框架 主要以 SCStream 为中心
SCStream 处理如开始 和停止的控制 与 SCShareableContent SCContentFilter 和 SCStreamConfiguration 一起创建
这些对象决定您想要捕获的 是什么内容 以及您想要如何捕获它
一旦创建并启动后 媒体样本将会通过 SCStreamOutput 协议 发送到您的 App 中 我稍后会进一步解释
现在 我为大家演示下如何使用 API 在您 App 中配置 stream 流
这些是配置 stream 流时 您需要熟悉的对象
这些对象确定了您捕获的 内容 品质和性能
首先我要看的 是 SCShareableContent
在这个桌面 有窗口 App 和屏幕显示本身
ScreenCaptureKit 针对 每个您可用于 构建共享内容的部件 都有对应的类
首先 我们看下 SCDisplay
ScreenCaptureKit 将屏幕显示 分类为 SCDisplays 只读属性 包括显示标识符 大小属性宽度和高度
在屏幕显示中 可能会有不同的 App 在运行 每个都有 对应的 SCRunningApplication
SCRunningApplication 中的 App 级别信息 有只读属性 如 bundle 标识符 App 名称及其进程标识符
在这个例子中 Keynote 和 Safari 各有一个 SCRunningApplication
当然 这些 App 都有窗口
这些窗口都有 对应的 SCWindow 包括定义窗口的只读属性 比如窗口 id frame 标题 窗口是否在屏幕上或最小化
SCWindow 也会有一个 所属 App
在这个情况下 两个 Safari SCWindows 都会有一样的 Safari 所属 App
SCWindows SCRunningApplications 和 SCDisplays 相结合 为您提供在 SCShareableContent 中 可以共享的潜在内容 您可以获得设备中 所有可共享内容的列表 或者也可以指定某个参数
假如您想要列出屏幕上 所有 App 和窗口 这样用户可以选择 需要共享的内容 ScreenCaptureKit 有一个 简单的 API 来完成
这个简短的代码片段 是捕获示例代码 可在 developer.apple.com 中找到
只有屏幕上的窗口 会通过 SCShareableContent 返回 包括相关联的 SCWindows SCApplications 和 SCDisplays
现在您有了可共享内容 就可以创建一个过滤器了
SCContentFilter 有 两种主要类型 显示器无关的窗口过滤器 它可以捕获 在多个显示器间移动的窗口 以及依赖显示器的过滤器 可以选择包含或排除 指定的窗口或 App
要注意音频捕获只能 在 App 级别上 进行过滤
我会给大家演示几个 过滤程序的例子
假如您只对共享 keynote 窗口感兴趣
您可以选择显示器无关的 窗口过滤器 从而在它跨屏幕移动时 可以捕获对应的窗口
即使您想要共享 屏幕上的所有内容 也可能会有一些内容 是您想要排除在外的 比如 您会想将 自己的捕获 App 排除在外 从而避免镜厅效应
有些窗口或 App 中可能还有 您不想捕获的敏感信息 这些场景都可通过 SCContentFilter 来处理 现在我们跳转到代码 看下如何完成
这是我之前展示的代码片段
查询了可共享内容后 代码会查找与捕获示例 App bundle 标识符相同的 App
然后 依赖显示器的内容过滤器 将 App 排除在 stream 流之外
除了内容过滤器 ScreenCaptureKit 提供 高品质 高性能 可于 每个 stream 流调整的控制
这些控制可在 SCStreamConfiguration 中设置
有些视频控制包括 输出分辨率 帧率 以及是否显示鼠标光标
在音频方面 您可以启用音频 改变采样率 调整通道数
我会为大家演示一些 应用这些参数的场景
当共享文本清晰度更重要的 低频运动屏幕内容时 如票据或电子数据表 设置捕获的输出分辨率 为 4K 每秒 10 帧
由于内容中不含有音频 您也可以禁用音频
但如果是高动态内容 如共享最近假期的视频 您应该以帧率优先 而非分辨率 将输出分辨率 降低为 1080p 帧率增加为每秒 60 帧
鼠标光标的移动可能会让人分心 您可能会想隐藏光标
您也可以启用音频捕获 会更有沉浸式的体验感
这些控制都可以 在 SCStreamConfiguration 中 通过不同的属性来设置
这是共享高动态内容的 一种可能的配置
在这个示例代码中 捕获的 输出分辨率设置为 1080p 然后 最小帧间隔设置为 1/60 从而以每秒 60 帧的帧率 进行捕获
最后 stream 流配置 会隐藏鼠标光标
在音频方面 首先通过将 capturesAudio 设置为 true 以启用音频 然后 设置采样率为 48kHz 通道数为 2
有了 SCContentFilter 和 SCStreamConfiguration 您就有了 App 设置屏幕捕获 所需的所有信息
有了这些 您现在可以 创建 SCStream 了
我们回到概述
您要用所需的过滤器和配置 来初始化 stream 流
您也可以传送可选代理 来处理错误
设置好后 您可以调用 startCapture ScreenCaptureKit 在可用的时候 会提供带采样的 SCStream
创建了过滤器和配置后 启动 stream 流代码就易如反掌了 我来给大家演示下
同样的 有了您需要的 过滤器和配置 您就可以初始化 SCStream 对象
在捕获样本项目中 self 作为错误处理代理传送
创建 SCStream 后 您现在可以调用 startCapture
您初始化 和开始 stream 流后 下一步就是通过 App 获得媒体样本
音频和视频样本都会以 CMSampleBuffers 的形式 发送到您的 App
为了从 stream 流中 获取媒体样本 您需要添加一个对象 为 stream 流实现 SCStreamOutput 协议
当您添加 stream 流输出时 可能也会指定一个处理队列
这在您想要在特定队列中 传送样本时会很有用 无需额外的分发
如果您没有指定队列 将会使用默认队列
stream 流已开始 输出已添加 新样本准备好后 ScreenCaptureKit 会提供 一个回调函数
现在 我给大家演示下 如何用代码来获取媒体样本
这是 SCStreamOutputProtocol 的实现 在新媒体样本准备好后调用
ScreenCaptureKit 将这些样本 作为 CMSampleBuffers 来传送 提供 stream 流和样本类型
实现了样本缓冲处理程序后 您只需要添加 stream 流输出
这样 stream 流中的媒体样本 有了您需要的内容和格式 将会传送到您的 App
ScreenCaptureKit 以 CMSampleBuffers 的形式传送样本 那我们再来看下如何使用
在视频方面 CMSampleBuffer 有 IOSurface 支持
ScreenCaptureKit 也为 SCStreamFrameInfo 中的 CMSampleBuffer 提供附件
附件可提供您收到的 视频样本的信息
检查 stream 当前状态下的 帧状态 complete 帧状态表示 有一个新的视频帧 idle 帧状态意味着 视频样本没有改变 所以没有新的 IOSurface
否则 所提供的样本 与所有 CMSampleBuffer 一样 您可以使用当前 CMSampleBuffer 工具
ScreenCaptureKit 的 API 可帮您获得过滤后屏幕的 音频和视频内容 最重要的是 该框架可提供 许多不同的开发者控制 从而匹配您 App 的需求
我还讲到了一些基础知识 能帮您开始创建 不同的屏幕捕获体验
有了全新推出的 ScreenCaptureKit 旧的捕获框架 CGDisplayStream 和 CGWindowList 未来将会被弃用
我希望大家和我一样 对 ScreenCaptureKit 的推出 感到激动不已
您如果准备好了查看 更多进阶话题 请观看将 ScreenCaptureKit 提升到全新境界 的相关内容
感谢收看
-
-
6:53 - Creating a SCShareableContent object
// Creating a SCShareableContent object // Get the content that's available to capture. let content = try await SCShareableContent.excludingDesktopWindows( false, onScreenWindowsOnly: true )
-
8:32 - Creating a SCContentFilter object
// Creating a SCContentFilter object // Get the content that's available to capture. let content = try await SCShareableContent.excludingDesktopWindows( false, onScreenWindowsOnly: true ) // Exclude the sample app by matching the bundle identifier. let excludedApps = content.applications.filter { app in Bundle.main.bundleIdentifier == app.bundleIdentifier } // Create a content filter that excludes the sample app. filter = SCContentFilter(display: display, excludingApplications: excludedApps, exceptingWindows: [])
-
10:23 - Creating a SCStreamConfiguration object
// Creating a SCStreamConfiguration object let streamConfig = SCStreamConfiguration() // Set output resolution to 1080p streamConfig.width = 1920 streamConfig.height = 1080 // Set the capture interval at 60 fps streamConfig.minimumFrameInterval = CMTime(value: 1, timescale: CMTimeScale(60)) // Hides cursor streamConfig.showsCursor = false // Enable audio capture streamConfig.capturesAudio = true // Set sample rate to 48000 kHz stereo streamConfig.sampleRate = 48000 streamConfig.channelCount = 2
-
11:46 - Creating and starting a SCStream object
// Creating and starting a SCStream object // Create a capture stream with the filter and stream configuration stream = SCStream(filter: filter, configuration: streamConfig, delegate: self) // Start the capture session try await stream?.startCapture() // ... // Error handling delegate func stream(_ stream: SCStream, didStopWithError error: Error) { DispatchQueue.main.async { self.logger.error("Stream stopped with error: \(error.localizedDescription)") self.error = error self.isRecording = false } }
-
13:07 - Getting media samples
// SCStreamOutput protocol implementation func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) { switch type { case .screen: handleLatestScreenSample(sampleBuffer) case .audio: handleLatestAudioSample(sampleBuffer) } } // ... // Create a capture stream with the filter and stream configuration stream = SCStream(filter: filter, configuration: streamConfig, delegate: self) // Add a stream output to capture screen and audio content try stream?.addStreamOutput(self, type: .screen, sampleHandlerQueue: screenFrameOutputQueue) try stream?.addStreamOutput(self, type: .audio, sampleHandlerQueue: audioFrameOutputQueue) // Start the capture session try await stream?.startCapture()
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。