大多数浏览器和
Developer App 均支持流媒体播放。
-
AVKit 中的新功能
了解 macOS 上的画中画功能增强和全屏幕改进。探索新内容来源 API,并了解 AVPictureInPictureController 如何支持 AVSampleBufferDisplayLayer,以及为 app 建议的步骤,以便在 macOS 上或 Mac Catalyst app 中提供无缝的全屏幕体验。
资源
相关视频
WWDC21
WWDC19
-
下载
♪播放重低音音乐♪ ♪ 欢迎来到AVKit新功能介绍 我是马帝派 AVKit团队的工程师 今天想跟大家聊聊 我们针对以下功能的改良 包括子母画面 也就是PiP 还有macOS上的全屏幕体验 我们先说明子母画面 启用子母画面时 使用者可以继续观看影片 同时使用设备上的其他功能 比方说 原本用全屏幕看影片 这时收到一则信息 你可以简短回复一下 但影片不会被中断 影片会自动进入PiP模式 当你回完信息 又可以马上回到影片播放 这创造了完全无缝的观影体验 而且使用者也会预设 看影片时有这个功能存在 想了解更多子母画面 要如何与你的app整合 请观看2019的讲座视频 说明AVKit的直觉式媒体播放 今年的新功能是 当影片正在播放 使用者回到桌面时 可以选择是否自动进入子母画面 要建立这项功能就要靠 canStartPictureInPicture AutomaticallyFromInline 这个属性 使用原生控制的app 在AVPlayerViewController就有提供 用其他用户界面定制的app 要用AVPictureInPictureController 记得这边只能标true 才会让正在播放的影片 成为使用者的主要焦点 若使用AVPlayerViewController 呈现影片内容 会直接设定好 你不需要再去处理 若不是用AVPlayerViewController AVPictureInPictureController能够 把子母画面功能添加到你的app 首先 你需要先配置 你app的音效播放栏位 让子母画面可以背景执行 接着你只需要 建立PictureInPictureController 传送参考给播放界面 只要用户想用你提供的按钮 切换到子母画面 你只需要用控制对象 去唤醒或终止子母画面 目前为止 我们的子母画面功能 都只限于影音相关内容的播放 我在此郑重宣布 同样的功能 也支持AVSampleBufferDisplayLayer 不需另外建立子母画面控制器 你先建立一个ContentSource 可以用AVPlayerLayer建立 AVSampleBufferDisplayLayer也行 对用户来说 子母画面模式 效果都会是一样的 对开发者来说 有一些AVSampleBufferDisplayLayer 支持子母画面需要注意的新地方 我们看一下这个播放委托 先找到最新的播放状态 就记录在 AVPictureInPictureSample BufferPlaybackDelegate 才能算绘出PiP UI 因为媒体播放不归播放器管 当用户想通过PiP用户界面控制 我们就把指令转给委托处理 我们一步一步来看这五个独立回呼 setPlaying在使用者按下 PiP窗口播放暂停键时 会被调用 skipByInterval则是在使用者 按下快转键的时候会被调用 依照相应的回呼 控制媒体 timeRangeForPlayback是为了 当前可播放的时间范围 这样可以算出时间轴 并显示当前的播放进度 有限时长的时间范围 必须包含现在时点 在预览缓冲播放界面时间基准的位置 至于无限时长的时间范围 比如直播的内容 通过didTransitionToRenderSize 就会在子母画面改变大小 例如拉近放大时 被调用 请将算绘的窗口尺寸一并考虑 并选取合适的媒体变量 以避免非必要的额外解码 isPlaybackPaused会被定期调用 并通知子母画面用户界面 是否要反映暂停或播放状态 概念上这就等于 媒体播放器的timeControlStatus 接着我们来看macOS上一些 全屏幕体验的改良 在Big Sur 当你用Mac Catalyst的app 播放全屏幕影片 影片会是窗口大小 但不是屏幕大小 现在在macOS Monterey 影片就会是全屏幕大小 这样真正的全屏幕体验 在macOS和Mac Catalyst都可以获得 两者的播放控制看起来也一样 所有Mac Catalyst程序 会自动取得这个新行为 如同所有macOS原生的全屏幕体验 用户可以返回app窗口 原本影片位置会有一张替代图像 代表该内容正被全屏幕播放 这跟用子母画面播放影片 显示的替代画面非常类似 使用者选取内容后 播放控制器全屏幕显示的情况下 控制器还是只有全窗口显示 然而 在新的macOS Monterey 用户可以变成真正的全屏幕播放 只要按下绿色的全屏幕按钮 在窗口的左上方 全屏幕播放循环可以被精确管理 以提供更好的使用经验 并符合你的应用程序需求 这边我们看一个例子 刚刚已经看到 使用者应该能够 观看全屏幕影片并返回app 但影片继续播放 使用者能够自由使用你的app 就算因此造成播放控制器 从浏览阶层被移除 无论任何时候 他们都能返回 或是用“调度中心”回到 全屏幕影片 所以我们来看看这要如何进行 你需要注意的是 playerViewController的播放循环 为了达到优化的体验 就算playerViewController 不在你app的浏览阶层里面 也要确保它能持续运作 否则 当使用者离开页面去看影片 全屏幕播放就会终止 playerViewController就被释出 你只需在你收到 willBeginFullScreenPresentation回呼时 留下一个强大的参考 给playerViewController 接着只要用户离开全屏幕 就会收到 willEndFullScreenPresentation回呼 这时候你就可以放掉 持续运作的playerViewController 假定使用者已经离开 原本提供的原始浏览 就跟macOS原生一样 你可以用新的playerViewDelegate 来维持playerView运作 直到收到 playerViewWillExitFullScreen的回呼 当用户离开全屏幕 你也会收到 这个restoreUserInterface回呼 这会让你的app 导览回原本有影片的页面 假定这是你所希望的结果 这会跟使用者中止子母画面 所接收到的回放非常相似 记得要回到这个completionHandler 越快越好 以免挡住 全屏幕到在线的转换 return false就代表储存失败 或是无法储存 这样的话 就会因为没有动画而退出全屏幕 今天的讲座就到此为止了 我们学习到如何运用新的内容来源API 支持你app的子母画面功能 是通过AVSampleBufferDisplayLayer 而不是AVPlayerLayer 而针对macOS和Mac Catalyst 我们介绍了全屏幕体验的改良 并描述了无缝融入编码 所需的必要步骤 希望你们喜欢今天的内容 我很期待看到今天介绍的这些功能 出现在你的app上 祝各位在接下来的讲座也收获满满 ♪
-
-
1:16 - New canStartPictureInPictureAutomaticallyFromInline property
// New property on AVPlayerViewController / AVPictureInPictureController. var canStartPictureInPictureAutomaticallyFromInline: Bool { get set }
-
1:40 - Setting up AVPictureInPictureController with an AVPlayerLayer
func setupPictureInPicture() { // Ensure PiP is supported by current device. if AVPictureInPictureController.isPictureInPictureSupported() { // Create a new controller, passing the reference to the AVPlayerLayer. pictureInPictureController = AVPictureInPictureController(playerLayer: playerLayer) pictureInPictureController.delegate = self // Observe AVPictureInPictureController.isPictureInPicturePossible to update the PiP // button’s enabled state. } else { // PiP isn't supported by the current device. Disable the PiP button. pictureInPictureButton.isEnabled = false } }
-
2:11 - Starting and stopping picture in picture
@IBAction func togglePictureInPictureMode(_ sender: UIButton) { if pictureInPictureController.isPictureInPictureActive { pictureInPictureController.stopPictureInPicture() } else { pictureInPictureController.startPictureInPicture() } }
-
2:56 - AVPictureInPictureSampleBufferPlaybackDelegate
public protocol AVPictureInPictureSampleBufferPlaybackDelegate: NSObjectProtocol{ // Delegate is responsible for: // // - Supplying playback state information for PiP UI. // - Responding to user input from PiP UI. }
-
3:17 - Toggle playback of the video and seek back / ahead 15 seconds
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, skipByInterval skipInterval: CMTime, completion completionHandler: @escaping () -› Void)
-
3:31 - Provide elapsed time information
func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange
-
3:51 - Choose appropriate media variant for render size
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, didTransitionToRenderSize newRenderSize: CMVideoDimensions)
-
4:06 - Update playback state
func pictureInPictureControllerIsPlaybackPaused(pictureInPictureController: AVPictureInPictureController) -> Bool
-
6:05 - iOS / MacCatalyst - Persist full screen playback
func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: nil) { context in // Keep a strong reference to the playerViewController while in full screen. self.detachedPlayerViewController = playerViewController } }
-
6:38 - iOS / MacCatalyst - Release the playerViewController
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator){ coordinator.animate(alongsideTransition: nil) { context in // Stop keeping the playerViewController alive when transition completes, self.detachedPlayerViewController = nil } }
-
6:46 - Persist full screen playback on macOS
func playerViewWillEnterFullScreen(_ playerView: AVPlayerView) { // Start keeping the player view alive while it is not in the view hierarchy. self.detachedPlayerView = playerView } func playerViewWillExitFullScreen(_ playerView: AVPlayerView) { // Stop keeping the player view alive. self.detachedPlayerView = nil }
-
6:55 - Restoring UI when exiting full screen
// Restoring UI when exiting full screen // iOS / MacCatalyst func playerViewControllerRestoreUserInterfaceForFullScreenExit(_ playerViewController: AVPlayerViewController) async -> Bool { // Custom UI restoration logic return true } // macOS func playerViewRestoreUserInterfaceForFullScreenExit(_ playerView: AVPlayerView) async -> Bool { // custom UI restore logic here return true }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。