大多数浏览器和
Developer App 均支持流媒体播放。
-
ScreenCaptureKit 中的新增功能
使用 ScreenCaptureKit 中的最新功能提升你的屏幕共享体验。探索内置系统选择器、Presenter Overlay 和截屏功能,并了解如何将这些功能纳入你现有的 ScreenCaptureKit App 或游戏中。
章节
- 0:08 - Intro
- 1:36 - Presenter Overlay
- 4:36 - Screen sharing picker
- 9:46 - Screenshot API
- 13:01 - Wrap-Up
资源
相关视频
WWDC23
WWDC22
-
下载
♪ ♪
Christopher:大家好 欢迎来到本次讲座! 我叫 Christopher, 是 ScreenCaptureKit 团队的 一名软件工程师 我将与我的同事 Natalie Lindsay 一起介绍一些新功能 这些功能将增强 你的 App 中的屏幕捕捉功能
ScreenCaptureKit 是在 macOS 12.3 中引入的 旨在帮助你创建 App 的屏幕共享体验 ScreenCaptureKit 提供了一组 API 让你可以自定义要共享的内容 根据 App 需求动态应用控制 该框架聚焦性能品质 提供高质量的内容 能够达到显示器原生分辨率和帧率 并兼顾隐私安全 今年 ScreenCaptureKit 提供了几个 与新的 macOS 功能集成的 开发者 API Presenter Overlay 是一项 允许人们 将自己嵌入到共享的内容中 使屏幕共享和演示更个性化的功能 通过全新的屏幕共享选择器 你将能够 集成系统范围的屏幕共享体验 屏幕捕捉不仅适用于实时流 今年还提供了一个全新的 API 允许你捕捉任何内容的高清截屏 人们每天在世界各地进行互动 在这些互动中我们分享思想、观点 还能解决重要问题 它们既专业又私人 为此 你的 App 可以与一种 名为 Presenter Overlay 的 新视频特效无缝配合使用 在共享内容时 Presenter Overlay 通过将主讲人置于共享内容之上 提升了主讲人的存在感 为远程会议带来个人化的触感 更有助于提高生产力 借助先进的分割算法 小型悬浮窗 将主讲人放置在可移动窗口中 大型悬浮窗将主讲人的脸部、身体 与背景分离开来 并在它们之间叠加屏幕内容 实现更沉浸式的效果 每个使用 ScreenCaptureKit 的 App 都可以使用 Presenter Overlay 对于每个创建的 SCStream ScreenCaptureKit 将通知屏幕共享选择器 在新的视频菜单栏项中展示 带有控制的实时预览 视频菜单栏将显示 每个具有活动流的 App 并显示与任何 App 相关的流的实时预览 从该菜单栏 你将能够 通过展示屏幕共享选择器来控制 正在传输和共享的屏幕内容 这也是启用 Presenter Overlay 的地方 将摄像头帧嵌入内容流中 你还可以使用此功能控制流 例如替换或结束屏幕共享 此外该菜单栏还提供其他有用功能 用于自定义相机和麦克风效果
使用 ScreenCaptureKit 和 摄像头的每个 App 都会自动启用这些功能 当前 流中的内容帧是从 ScreenCaptureKit 发送到其进程的 现在 当 App 在活动流期间启用摄像头时 Presenter Overlay 将在视频菜单项中提供 一旦启用 ScreenCaptureKit 将使用摄像头 并将渲染应用于 你的 App 已经运行的选定流 你将自动从活动流中获得合成帧 如果你想明确知道何时应用了 Presenter Overlay 该怎么办呢?
让我们从创建一个 新的流并将其添加为代理开始 然后 在 SCStream 上实现 新的代理回调函数 outputEffectDidStart 这是你被通知 Presenter Overlay 已被应用的方式 当收到通知时 你需要检查效果是开始还是停止 Presenter Overlay 是 macOS 的一个新系统功能 因此当应用了叠加效果时 你的 App 可能需要考虑一些情况
当 Presenter Overlay 被打开时 AVCaptureSession 将不会发送典型的实时相机流 这是因为 你的相机会直接用于叠加效果 这将是更新 App UI 以适应这种变化的好时机 例如 视频会议 App 可能希望调整音视频同步 以适应 混合了摄像头和共享内容的情况 你可能还想隐藏演讲者的相机图块 以获得更优化的外观 Presenter Overlay 是摄像头和视频功能 因此你的 App 应该针对更高的帧率进行优化
除了 Presenter Overlay 你还可以利用一个 全新的系统级屏幕共享选择器 该选择器允许你的 App 完全集成 多个与选择共享内容相关的功能 这些是你通常创建流的一般结构 目前 你可调用 SCSharableContent 来获取所有可共享的屏幕内容 你将使用它来创建 SCContentFilter SCContentFilter 用于确定你要捕获的内容 目前 你是通过 SCSharableContent 构建它的 但今年新推出的方式 是通过选择器获取内容过滤器 选择器有两种方式生成 SCContentFilter 首先 可以通过 系统选择器共享所需的内容 其次 可以直接从 打开的窗口中选择内容 在这两种情况下 系统会将 SCContentFilter 与你的 App 共享 但是 如何将新的内容过滤器 引入到你的 App 中呢? 通过使用新的 API SCContentSharingPicker SCContentSharingPicker 充当你的 App 与操作系统之间的接口 为你的 App 提供委托回调 包括新的流请求、新的内容过滤器 以及当前流和内容过滤器的更新 SCContentSharingPicker 具有一个内置的系统级内容选择器 可基于窗口、 App 甚至显示器选择内容 无论是通过 App 中的按钮、 新的视频菜单栏 还是直接从窗口中选择内容 你的 App 都可以利用 SCContentSharingPicker 添加、删除或替换 任何正在进行的流的活动选择 SCContentSharingPicker 也内置了流请求回调 可以让你的 App 接收新的流请求 最后 它还带有每个流的自定义功能 你可以定义系统 如何应用于每个流的体验 获取 SCStream 的过滤器的构造方式 已从使用 SCSharableContent 转为使用系统选择器接口 和 SCContentSharingPicker 单例 来传递 SCContentFilter 让我向你展示 你的 App 如何轻松利用 这个新的屏幕共享选择器 你将从 SCContentSharingPicker 的共享实例开始 并将自身添加为观察者 以便获取所有适当的类回调 为了使系统识别选择器实例 请将其设置为激活状态 一旦活动 系统将了解你的选择器 并将你的 App 包括在系统 UI 中 使人们可以与之交互 你想要创建一个 允许人们通过选择器选择窗口的流 因此你将调用单例方法 picker.present 并传入 nil 和 你想要呈现的选择器样式 当用户按下你的 UI 按钮后 选择器将被呈现 允许他们选择他们希望捕捉的窗口 在选择内容之后 你将通过观察者回调 接收到一个新的过滤器的通知 现在 你可以自由地 使用此过滤器创建一个新的流 或更新现有的流 剩下的观察者回调同样重要 通过将其设置为激活并呈现它 再次设置选择器 你还希望 在请求呈现选择器时了解是否失败 如果不合格 你将希望在 你的 App 发送通知来告知用户 此外 如果选择器已经呈现但被取消 即没有选择内容 你希望确保相应地设置流的状态
SCContentSharingPicker 还提供了一些方法 允许你在 每个流级别自定义系统的行为 SCContentSharingPickerConfiguration 允许进行几种自定义设置 AllowedPickingModes 告诉系统在内容过滤器中 允许选择窗口、 App 或显示器选择中的哪些选择模式 它还允许明确声明 不允许系统体验选择的 excludedWindowIDs 和 bundleIDs 如果你有一个不希望用户更改的流 SCContentSharingPickerConfiguration 具有一个属性可以强制实现该功能 首先 获取一个 共享的 picker 实例 然后将自己添加为观察者 并将选择器设置为激活状态 现在 设置适当的配置设置 对于这个流 也许你希望排除 两个特定 App 的选择 并且不允许重新选择 一旦配置设置完毕 请调用 picker 上的 setConfiguration 方法 传入配置和适用的流
现在 选择器将准确地 知道如何针对给定的流进行操作 此外 请注意每个流 可能具有不同的选择器配置 以最适合 App 的需求
回顾一下 现在将所有的 ScreenCaptureKit 流整合到了 macOS 体验中 使任何 App 都能 利用 Presenter Overlay 等新功能 我也向你介绍了 SCContentSharingPicker 这是一个用于将你的 App 集成到 新的系统选择器 UI 的新 API 但是 在你的 App 中 进行屏幕捕捉不仅仅涉及到实时流 接下来由我的同事 Natalie, 更详细地介绍一下 这个新的截屏 API Natalie:谢谢 Christopher 今年 ScreenCaptureKit 中 有一个新的 API 旨在使你能够 轻松地从屏幕上捕获静态图像 新的截屏 API 将 ScreenCaptureKit 流的优势 带到了截屏中 包括按 App 或窗口进行高级过滤、 多种像素格式和色彩空间 以及光标可见性等选项都可用 现在 你将能够使用熟悉的 ScreenCaptureKit 结构 高效地捕获 你想要的精确屏幕内容的图像
新的 API 是异步的 对于输出图像 你可以选择 CMSampleBuffer 或 CGImage 格式 CMSampleBuffer 选项 提供了额外的像素格式 非常适合 你对特定格式感兴趣的情况 如果你已经 在你的代码中使用 CGImage 那么使用这种格式将更容易集成 无论使用哪种格式 你的截屏将使用 几乎与 ScreenCaptureKit 流相同的配置选项 并遵循类似的设置流程 如果你使用 CGWindowListCreateImage 有几个方面将使过渡到 ScreenCaptureKit 更容易 你在 CGWindowList API 中 可使用的所有窗口图像选项 都可以在 ScreenCaptureKit 的 SCStreamConfiguration 类中找到 窗口列表选项 如获取 特定窗口 ID 上方的所有窗口 可以在 SCShareableContent 中找到 如果你习惯使用 CGImage 输出 新的截屏 API 提供了一个 CGImage 输出格式 可以轻松集成到你现有的代码中 获取截屏的过程与 ScreenCaptureKit 流类似 但在创建 SCStream 的位置 你将调用截屏 API 开始时 就像创建流一样 使用 SCShareableContent 来获取你想要的内容 并创建你的 SCContentFilter 不要忘记设置你的 SCStreamConfiguration 以满足你对截屏的所有需求 一旦你拥有内容过滤器和流配置 就调用截屏 API 并将它们传递进去 这个 API 是在 SCScreenshotManager 类上的一个类方法 所以你不需要创建 SCScreenshotManager 对象 来进行截屏 当截屏图像准备好时 它将以你选择的格式 以异步方式返回给你 你还可以使用新的 系统选择器来创建你的内容过滤器 然后使用它来调用截屏 API 这将是一种让用户以直观的方式 选择所需内容的好方法 在进行截屏时 根据你的需要 有两个版本的 API 可供选择: CMSampleBuffer 输出类型和 CGImage 输出类型 除此之外 这两个版本的工作方式是相同的 都会异步返回你的截屏 以下是一个代码示例 展示了如何使用截屏 API 首先 设置你的 SCContentFilter 和 SCStreamConfiguration 一旦准备就绪 你可以调用截屏 API 并等待其返回 然后你将得到你的截屏 这就是 ScreenCaptureKit 中的所有新内容 总结一下 有一个新 API 用于创建 SCContentFilters 该 API 用系统级别的 UI 与你的 App 一起使用 以实现完全集成的屏幕共享体验 全新的 Presenter Overlay 视频效果 提供了更动态的屏幕共享体验 而新的截屏 API 利用 ScreenCaptureKit 的强大功能 允许你进行一次性的屏幕捕捉 如欲了解有关 ScreenCaptureKit 的更多信息, 请查看去年的讲座 “认识 ScreenCaptureKit”和 “将 ScreenCaptureKit 提升到新水平”
感谢观看
-
-
3:32 - Set up delegate for stream
// Set up delegate for stream let stream = SCStream(filter: filter, configuration: config, delegate: self) // delegate method for Presenter Overlay applied func stream(_ stream: SCStream, outputEffectDidStart didStart: bool) { // if Presenter Overlay is on, present banner in app to notify if didStart == true { presentBanner() turnOffCamera() } else { turnOnCamera() } }
-
6:48 - Set up content sharing picker instance
// Set up content sharing picker instance let picker = SCContentSharingPicker.shared() picker.addObserver(self) picker.active = true // show system level picker button func showSystemPicker(sender: UIButton!) { picker.present(for stream: nil, using contentStyle:.window) } // observer call back for picker func contentSharingPicker(_ picker: SCContentSharingPicker, didUpdateWith filter: SCContentFilter, for stream: SCStream?) { if let stream = stream { stream.updateContentFilter(filter) } else { let stream = SCStream(filter: filter, configuration: config, delegate: self) } }
-
7:41 - Observer call back for picker did fail and did cancel
// Set up content sharing picker instance let picker = SCContentSharingPicker.shared() picker.addObserver(self) picker.active = true // show system level picker button func showSystemPicker(sender: UIButton!) { picker.present(for stream: nil, using contentStyle:.window) } // observer call back for picker did fail func contentSharingPicker(contentSharingPickerStartDidFailWith error:NSError) { if error { presentNotifications(error: error) } } // observer call back for picker did cancel func contentSharingPicker(_ picker: SCContentSharingPicker, didCancel for stream: SCStream?) { if stream { resetStateForStream(stream: stream) } }
-
8:41 - Per-stream configuration
// Set up content sharing picker instance let picker = SCContentSharingPicker.shared() picker.addObserver(self) picker.active = true // Create configurations let pickerConfig = SCContentSharingPickerConfiguration() // Set Picker configuration pickerConfig.excludedBundleIDs = [“com.foo.myApp”,”com.foo.myApp2”] pickerConfig.allowsRepicking = true // Create configurations picker.setConfiguration(pickerConfig, for: stream) func showSystemPicker(sender: UIButton!) { picker.present(for stream: nil, using contentStyle:.window) }
-
12:26 - Call the screenshot API
// Call the screenshot API class SCScreenshotManager : NSObject { class func captureSampleBuffer(contentFilter: SCContentFilter, configuration: SCStreamConfiguration) async throws -> CMSampleBuffer class func captureImage(contentFilter: SCContentFilter, configuration: SCStreamConfiguration) async throws -> GImage }
-
12:44 - Take a screenshot with ScreenCaptureKit
// Don't forget to customize the content you want in your screenshot // Use SCShareableContent or SCContentSharingPicker to pick your content let display = nil; // Create your SCContentFilter and SCStreamConfiguration // Customize these lines to use the content you want and desired config options let myContentFilter = SCContentFilter(display: display, excludingApplications: [], exceptingWindows: []); let myConfiguration = SCStreamConfiguration(); // Call the screenshot API and get your screenshot image if let screenshot = try? await SCScreenshotManager.captureSampleBuffer(contentFilter: myContentFilter, configuration: myConfiguration) { print("Fetched screenshot.") } else { print("Failed to fetch screenshot.") }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。