View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

返回 WWDC25

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 支持 visionOS App 播放沉浸视频

    了解如何在 visionOS App 中播放沉浸视频。我们将介绍各种沉浸感十足的渲染模式、查看支持这些模式的框架,并讲解如何在你的 App 中渲染沉浸视频。为了充分利用好本次视频,我们建议你先观看 WWDC25 讲座“探索 visionOS 的视频体验”。

    章节

    • 0:00 - 简介
    • 1:24 - visionOS 26 支持的视频格式规范
    • 3:09 - 通过快速查看播放沉浸视频
    • 4:25 - 使用 AVKit 播放沉浸视频
    • 9:11 - 不适感缓解检测
    • 9:51 - 利用 RealityKit 打造自定播放体验
    • 11:48 - RealityKit 中的 Progressive 沉浸模式
    • 16:32 - 使用 RealityKit 进行空间视频渲染
    • 21:16 - RealityKit 中的不适感缓解检测
    • 22:57 - RealityKit 内容与 SwiftUI 的深度整合

    资源

    • AVFoundation
    • AVKit
    • HTTP Live Streaming Examples
    • Playing immersive media with AVKit
    • Playing immersive media with RealityKit
    • RealityKit
      • 高清视频
      • 标清视频

    相关视频

    WWDC25

    • 了解 Apple 沉浸视频技术
    • 了解 Apple Projected Media Profile
    • 探索 visionOS 的视频体验
    • 空间网页的新功能

    WWDC24

    • 深入探究空间容器和沉浸式空间

    WWDC23

    • 使用 RealityKit 增强你的空间计算 App
  • 搜索此视频…

    大家好! 我叫 Jamal 是 AVKit 团队的 媒体应用工程师 我叫 Michael 是 visionOS Spatial Media 团队的软件工程师 在 visionOS 上 我最喜欢做的 事情之一就是以这个平台 独有的方式观看视频 在 visionOS 2 中 这包括 停靠播放和空间视频等 令人惊叹的体验 在 visionOS 26 中 我们对所有 你喜爱的媒体框架进行了扩展 比如 Quick Look、AVKit 和 RealityKit 这些框架 以便支持更具沉浸感的媒体描述文件 帮助你在 visionOS 中打造 出色的沉浸式 视频播放体验 今天 我和 Jamal 将分享 如何在应用程序中支持 这种沉浸式视频播放 Jamal 开始吧 谢谢 Michael 首先 我将简要回顾 不同类型的视频描述文件 然后我将介绍 Quick Look 以及 AVKit 中的新 API 如何支持沉浸式媒体播放 最后 Michael 将介绍 应用程序如何 利用 RealityKit 自定 沉浸式播放体验 看完这个视频后 你将 了解到需要了解的一切 以在 visionOS 应用程序中 支持和打造沉浸式 视频播放体验 我将首先回顾 visionOS 26 中支持的 不同类型的视频描述文件

    在 visionOS 1 中 2D 和 3D 视频是应用程序中 提供视频播放的主要方式 空间媒体使人们能够 拍摄出引人入胜的立体内容 以沉浸式的方式 享受自己的创作 visionOS 26 现在包含 Apple Projected Media Profile (APMP) 适用于 180 度、 360 度和广角视频 而终极沉浸式体验 当属 Apple Immersive 视频 这些描述文件的 每一个都有自己的独特之处 如果你对这些术语不熟悉 “探索 visionOS 的视频体验” 讲座将为你提供相关知识 有很多方法可以支持 我刚才列出的所有视频描述文件 为此 为你的应用程序 选择合适的技术 对于提供出色的 沉浸式体验非常重要

    Quick Look 是一个理想框架 可用于快速呈现任何类型的媒体 包括沉浸式媒体 AVKit 在每个平台上提供 熟悉且一致的视频体验 同时为播放体验 提供增强的控制 RealityKit 专为需要 独特沉浸式播放体验的 应用程序而设计 就像在视频游戏 环境中的那些体验一样 最后 如果你正在寻找 浏览器中的沉浸式播放支持 请观看我们的讲座 “空间网页的新功能” 以获取有关网页内容 沉浸式播放的更详细说明

    接下来我将介绍 visionOS 26 中 为 Quick Look 和 AVKit 提供的工具 这样你就可以开始 创建沉浸式视频 播放应用程序 Quick Look 提供了两个 API 用于在 App 中快速显示和预览媒体 一个是 PreviewApplication 这个 API 支持用于媒体 呈现的进程外窗口 另一个是 QLPreviewController 这个 API 用于在 App 窗口中或 在模态呈现样式中预览媒体 在 visionOS 26 中 QLPreviewController 已得到增强 以支持空间照片和视频 除此之外 PreviewApplication 现在 还支持 Apple Immersive 视频 和 Apple Projected Media Profile 视频 包括 180 度、 360 度和广角视频

    QLPreviewController 和 PreviewApplication 可以管理新视频 描述文件的呈现和过渡 它们还会使用适当的 视频样式调整预览 在 visionOS 26 中 所有已实现 Quick Look API 的应用程序 将自动支持 沉浸式媒体描述文件 要进一步了解如何实现 PreviewApplication API 或 QLPreviewController API 请参考 WWDC23 中的视频“探索 ‘快速查看’在空间计算中的应用” 和 WWDC24 中的“visionOS 中‘快速查看’的新功能” 接下来 我将介绍新的 AVKit API 我们推出这些 API 是为了 全面支持沉浸式视频播放 在 visionOS 26 中 AVExperienceController API 用于实现向 新沉浸式体验的过渡 有多种选项可以通过 AVExperienceController 实现 向沉浸式体验的过渡 第一个选项是使用 Expanded Expanded 体验允许 AVPlayerViewController 占用整个 UI 窗口场景 而现在 visionOS 26 中 Expanded 可配置为 实现沉浸式视频播放 Expanded 配置中的新功能是 AutomaticTransitionToImmersive 属性用于 确定是不是应启动 向沉浸式体验的自动过渡 AutomaticTransitionToImmersive 属性可设置为 default (当需要系统默认行为时) 或 none (当不需要自动过渡时)

    通过将 AutomaticTransitionToImmersive 属性的值设置为 none 检测到沉浸式内容时 AVPlayerViewController 会 为它提供门户处理 同时将 AVExperienceController 保留在 Expanded 体验中 以下是一个示例 展示在需要 对沉浸式内容进行门户处理时 禁用对沉浸式体验的自动过渡 我将首先创建一个 AVPlayerViewController 并为它配置沉浸式媒体内容 然后我会将推荐的集合添加到 它的 experienceController 中 其中包括适用于 这个平台的合适体验 同时确保 Expanded 和 Immersive 是其中的一部分 考虑到 AutomaticTransitionToImmersive 属性 最初是默认的 我现在需要将 这个属性的值指定为 .none 假设 AVPlayerViewController 已在应用程序 视图层次结构中 我已准备好将 AVExperienceController 切换到 Expanded 体验 借助新的 Immersive API (AVExperienceController 中体验的一部分) 可以显式 过渡到这种体验 而不仅仅是 依靠自动触发 就像处理 Expanded 一样

    Immersive Experience API 附带了新的 Configuration API 让 App 能够定义 沉浸式视频播放的 呈现位置 这个代码片段展示了 如何将沉浸式体验 与 Configuration API 配合使用 假设 AVPlayerViewController 尚未添加到视图层次结构中 你需要通过 Configuration API 进行指定 你可以通过访问 Experience Controller Configuration 并使用 .over 函数 为首选的窗口 UI 场景 提供 placement 参数值 定义后 AVExperienceController 已准备好 过渡到沉浸式体验 如果视图层次结构中已包含 AVPlayerViewController AVExperienceController 将自动 采用当前所在的窗口场景 作为目标放置场景 这就是应用程序 通过 AVKit 过渡到 沉浸式体验的实现方式 在进入和退出 沉浸式体验时 AVExperienceController 负责处理不同体验间的 动画与过渡效果 这些过渡可由用户操作、 应用程序逻辑或系统 在任意时刻触发

    因此在使用 AVExperienceController 时 务必要了解所有过渡 或展示状态的变化 这能帮助你灵活 适当处理 应用程序的活动状态 为此 AVExperienceController 的 委派协议就是合适的解决方案 这个协议包含 3 个委托方法: didChangeAvailableExperiences 当可用体验发生 变化时触发通知 prepareForTransitionUsing 在 AVExperienceController 即将过渡时触发通知 让 App 能最后一次 为新状态做好准备 和 didChangeTransitionContext 当过渡到新体验 时触发通知

    沉浸式体验依赖于 所提供的内容类型 使用 didChange AvailableExperiences 方法 确定当前内容是否支持 沉浸式体验 例如 如果向 AVPlayerViewController 提供了 2D 媒体内容 沉浸式体验将不可用 要进一步了解如何使用 AVExperienceController 及它的委托方法 请查看“使用 AVKit 播放 沉浸式媒体”示例代码 除了支持沉浸式 视频播放的新 API 外 在 visionOS 26 中 Quick Look 和 AVKit 现在还支持舒适度缓解检测 沉浸式视频可能包含 大幅镜头运动 这可能导致观看者感到不适 为解决这个问题 现在对 Apple Projected Media Profile 内容支持运动检测 现在 QuickLook 和 AVKit 能够 在播放期间检测剧烈运动 并自动降低沉浸程度 观看者可在“设置” App 中调整选项 让 Quick Look 和 AVKit 完全按照自己偏好的运行方式 对于大多数沉浸式 视频播放体验 Quick Look 和 AVKit 都是不错的选择! 如需更加个性化的沉浸式体验 RealityKit 是理想的选择 接下来由 Michael 为大家解释原因 谢谢 Jamal 我同意 RealityKit 是一个 很棒的自定视频播放框架 例如在沉浸式游戏中集成视频 或者通过自定 用户界面渲染视频 在 visionOS 26 中 RealityKit 支持原生播放沉浸式视频 在这个部分中 我将介绍 180 度、360 度和 广角视频和 Apple Immersive 视频的渐进沉浸式模式 以及支持完整空间样式的 空间视频渲染 就像“照片”App 一样 我还将演示如何检测 何时应用了视频舒适度缓解措施 最后 我将分享一些 在 SwiftUI 场景中使用 RealityKit 进行视频播放的技巧 VideoPlayerComponent API 功能强大 用于在 RealityKit 中渲染视频 当附加到 RealityKit 实体时 它会基于 AVPlayer 中的当前视频 以及组件上的属性 打造专属网格和材质 这使得 VideoPlayerComponent 非常适合渲染具有 沉浸式观看模式的视频 因为网格更新和 动画是自动处理的 例如 developer.apple.com/cn 上 Destination Video 项目中的 视频对接示例 如需了解 VideoPlayerComponent 入门知识 请查看“使用 RealityKit 增强空间计算 App”

    在 visionOS 26 中 VideoPlayerComponent 支持 Quick Look 和 AVKit 现在支持的所有 沉浸式视频描述文件 我将先介绍 Apple Projected Media Profile 视频和 Apple Immersive 视频 VideoPlayerComponent 为这些 视频描述文件提供三种沉浸式模式 门户模式在门户中渲染视频 用于窗口式展示 渐进模式是新的 API 让用户可以使用数码旋钮 调节沉浸程度 既能继续欣赏视频 又不与周围环境脱节 在 100% 沉浸模式下 渐进模式等同于 完全沉浸式观看模式

    从 visionOS 26 开始 针对 Apple Projected Media Profile 视频以及 Apple Immersive 视频 推荐使用渐进沉浸式模式 而非完全沉浸式模式 因为它提供了 更高的灵活性 同时也支持舒适度缓解 我稍后将更详细地介绍这一点 在这里 我将创建一个在门户模式下 渲染 180 度视频的视图 并将它放置在共享 空间的 WindowGroup 中 要配置门户播放 请先创建 AVPlayerItem 和 AVPlayer 并使用本地或 HTTP Live Streaming URL 然后用播放器初始化 VideoPlayerComponent 将组件的 desiredImmersiveViewingMode 设置为 portal 并将组件附加到实体 VideoPlayerComponent 的 网格默认高度为 1 米 我将视频缩放到 0.4 米 以适配 SwiftUI 窗口场景 最后将实体添加到场景中 要改为以渐进模式 渲染这个视频 将组件的 desiredImmersiveViewingMode 从 portal 改为 progressive 由于渐进模式下 组件会自动控制缩放 因此缩放操作将失效 为了保持清晰 我将移除相关设置 但在 SwiftUI 创景中渲染时 仅将组件更新为 progressive 还不够 为避免网格扩展时 与窗口场景边界发生裁剪 必须将新的 ProgressiveVideoView 放入 ImmersiveSpace 使用渐进模式进行渲染时 ImmersiveSpace 必须使用 渐进式沉浸样式 这里初始沉浸程度为 1 等同于完全沉浸式体验 我选择了 10% 到 100% 的广泛范围 因此用户可以自由 调节沉浸程度 如果包含 0% 沉浸程度 可能降至内容消失 这不是我想要的 App 行为 SwiftUI 的 ImmersionStyle 以及组件的沉浸式观看模式 对于配置播放非常重要 在 RealityView 中渲染时 务必确保 desiredImmersiveViewingMode 与 ImmersionStyle 匹配 有关沉浸样式的更多信息 请观看 2024 视频“深入探究 空间容器和沉浸式空间” 要在门户模式和 渐进模式之间切换时 需监听切换 SwiftUI 场景时的 ImmersiveViewingModeDidChange 事件 ImmersiveViewingModeWillTransition 和 DidTransition 事件 用于在动画过渡期间 切换 UI 可见性 以减少运动和立体冲突 要查看这些事件的具体示例 请访问 developer.apple.com/cn 并查看 “使用 RealityKit 播放 沉浸式媒体”示例代码 回顾一下:若要对 Apple Projected Media Profile 视频和 Apple Immersive 视频 进行门户渲染 应将 desiredImmersiveViewingMode 设置为 portal 门户通常位于共享空间的 SwiftUI WindowGroup 中 但也可以在具有混合沉浸风格的 沉浸式空间中独占显示 要实现沉浸式渲染 请在采用渐进式 ImmersionStyle 的 ImmersiveSpace 中 将 desiredImmersiveViewingMode 设置为 progressive 就像我之前的代码所示 要获取首选的系统行为 请不要设置 desiredViewingMode 对于单视场视频 viewingMode 会自动设为 mono 而对于立体视频 (例如立体声 180 和 Apple Immersive 视频) 则自动设为 stereo 空间视频属于立体 视频 或许你已经 在 Apple 生态系统中 开始拍摄这类视频 它们包含空间元数据 可实现 更舒适的沉浸式渲染效果 与 Apple Projected Media Profile 视频和 Apple Immersive 视频一样 空间视频现已在 RealityKit 中得到原生支持 并能以完整的空间样式 和沉浸式模式进行渲染

    空间视频的空间样式 通过以下方式配置 使用 VideoPlayerComponent 上的 desiredSpatialVideoMode 属性 设置这个属性可指定 空间视频的渲染方式 读取只读的 spatialVideoMode 属性 来确定空间视频的渲染方式 要为空间视频启用空间样式 请将 desiredSpatialVideoMode 设置为 .spatial

    空间渲染同时支持 .portal 和 .full ImmersiveViewingMode 与其他沉浸式视频类型不同 空间视频的沉浸式渲染 始终配置为完全 沉浸式观看模式 沉浸式空间视频 以固定尺寸渲染 这个尺寸基于内容的视野确定

    将 desiredSpatialVideoMode 设置为 .screen (默认值) 可在屏幕网格上以传统 立体效果渲染空间视频 除非当前视频为有效的空间视频 否则 SpatialVideoMode 不会更新 顾名思义 这个模式 仅适用于空间视频 订阅新的 VideoPlayerEvent: SpatialVideoModeDidChange 或直接观察 spatialVideoMode 属性 来确定 spatialVideoMode 属性 是否更新以及何时更新

    要以门户模式渲染为空间视频 首先创建包含空间视频 AVPlayer 的 VideoPlayerComponent 将 desiredViewingMode 设置为 stereo 这是空间视频的默认设置 但我喜欢显式设置 然后将 desiredSpatialVideoMode 设置为 spatial 并选择 portal 作为 desiredImmersiveViewingMode 如前所述 缩放视频 以适应窗口大小 在空间模式下 可通过将沉浸式观看模式 设置为 full 来扩展视频 我还要移除缩放操作 因为组件会在 沉浸式呈现期间控制尺寸 如我之前的示例所示 视图需要位于 ImmersiveSpace 中以避免裁剪 但沉浸式空间视频渲染 不像其他沉浸式视频类型 那样受头部锁定 因此我需要设置实体的位置 我会选择距离地面 一米半高、向前一米的位置 但为了实现更可靠的解决方案 可使用头部锚点来初始化实体 使它位于观看者前方 最后 我会将这个 ImmersiveSpatialVideoView 包装在 ImmersiveSpace 中 对于空间视频 请使用 混合 ImmersionStyle 以在透视模式下渲染沉浸式模式 为了让空间视频 也能在系统环境中渲染 这是我一直想要的行为 请将新的 immersiveEnvironmentBehavior 场景修饰符与 coexist 选项一起使用

    回顾一下 空间视频门户 通过将 desiredSpatialVideoMode 设置为 spatial 来配置 并在共享空间或具有混合 ImmersionStyle 的 ImmersiveSpace 中 将 desiredImmersiveViewingMode 设置为 portal 空间视频的观看模式 将默认为 stereo 空间视频沉浸式模式通过将 desiredImmersiveViewingMode 设置为 full 和具有混合 ImmersionStyle 的 ImmersiveSpace 来设置 以在透视模式下进行渲染

    要在没有空间样式的 情况下以传统立体模式渲染 请将 desiredSpatialVideoMode 设置为 screen 在这个模式下 沉浸式观看模式不起作用 空间视频也可通过将 desiredViewingMode 设置为 mono 进行单视场模式渲染 在这个模式下 SpatialVideoMode 和 ImmersiveViewingMode 都不起作用 这些非沉浸式模式通常 位于共享空间的 WindowGroup 中 观看沉浸式视频是一种 令人难以置信的沉浸式体验 这意味着播放过程对 视频中的剧烈运动非常敏感 因此 对于 Apple Projected Media Profile 视频 RealityKit 会在播放期间 自动执行舒适度缓解措施 就像 Jamal 之前就 AVKit 和 Quick Look 所描述的那样

    新的 VideoComfortMitigationDidOccur 事件 会在系统应用舒适度 缓解措施时发出信号 以响应视频中的剧烈运动 收到这个事件时 无需采取任何行动 这只是一个表明已应用 特定缓解措施的信号 reducedImmersion 缓解措施仅 在渐进式渲染期间可用 这就是为什么对于 Apple Projected Media Profile 视频 使用渐进沉浸式观看模式和 沉浸样式 (而非完整模式) 很重要的原因 在门户渲染期间 不会执行任何缓解措施 因为门户播放对于大多数内容 而言已经足够舒适 VideoPlayerComponent 的 受支持行为和渲染样式 取决于所呈现的 特定视频描述文件 使用 ContentTypeDidChange 事件 来检测 VideoPlayerComponent 中的视频类型 包括 Apple Projected Media Profile 视频等新类型 每当视频类型发生变化时 请做出响应: 以了解可用的观看模式 是否会应用舒适度缓解措施 或者更新 UI 元素 当 VideoPlayerComponent 与 UI 结合使用时 或者仅在 SwiftUI 场景中呈现时 我有一些将 RealityKit 内容 与 SwiftUI 顺利集成的技巧 例如 管理网格的比例对于 将媒体与 UI 并置非常重要 在门户模式下 网格尺寸 通过实体本地坐标系中的 playerScreenSize 属性反映 门户网格始终 创建为高度 1 米 缩放视频实体时 始终均匀缩放 X 和 Y 以保持纵横比 如果窗口场景的 高度小于 1 米 网格将被场景边界裁剪 除非实体按比例缩小 要缩放视频以适应场景 可使用 GeometryReader3D 基于可用窗口大小设置比例 请参考 developer.apple.com/cn 上的示例项目 “使用 RealityKit 播放沉浸式媒体” 了解缩放视频门户 以适应场景的示例

    另外 关于排序的注意事项: 与视频网格位于同一平面的 自定 UI 将具有未定义的排序行为 将 ModelSortGroupComponent 添加到 VideoPlayerComponent 所在的同一实体 并使用 ModelSortGroup 来指定 planarUIPlacement 类别 以针对共面 UI 对实体进行显式排序 无论是 QuickLook、 AVKit 还是 RealityKit 由你来选择使用哪个框架 来播放沉浸式视频 并且你拥有将这些精彩体验 构建到 App 中的工具!

    你可以通过以下方式 在 App 中打造新的沉浸式体验 在沉浸式游戏中 集成 360 APMP 视频 或者流播放 Apple Immersive 视频或空间视频等用例 要深入了解新的 APMP 视频类型 请观看视频“了解 Apple Projected Media Profile” 要深入了解 Apple Immersive 视频 请观看视频“了解 Apple Immersive 视频技术” 现在 去创造令人惊叹的 沉浸式视频体验吧!

    • 5:03 - AVExperienceController - AutomaticTransitionToImmersive

      struct ExpandedConfiguration {
          enum AutomaticTransitionToImmersive {
        		case `default`
        		case  none
          }
      }
    • 5:50 - Disable Automatic Transitions to immersive

      import AVKit
      
      let controller = AVPlayerViewController()
      
      let experienceController = controller.experienceController
      experienceController.allowedExperiences = .recommended(including: [.expanded, .immersive])
      
      experienceController.configuration.expanded.automaticTransitionToImmersive = .none
      
      await experienceController.transition(to: .expanded)
    • 6:26 - AVExperienceController - Immersive

      enum Experience {
          case immersive
      }
      
      struct Configuration {
      		struct Placement {
      			static var unspecified: Placement
      			static func over(scene: UIScene) -> Placement
      		}
      }
    • 6:53 - Transition to immersive

      import AVKit
      
      let controller = AVPlayerViewController()
      
      let experienceController = controller.experienceController
      experienceController.allowedExperiences = .recommended(including: [.immersive])
      
      let myScene = getMyPreferredWindowUIScene()
      experienceController.configuration.placement = .over(scene: myScene)
      
      await experienceController.transition(to: .immersive)
    • 8:13 - AVExperienceController.Delegate

      func experienceController(_ controller: AVExperienceController, didChangeAvailableExperiences availableExperiences: AVExperienceController.Experiences)
      
      func experienceController(_ controller: AVExperienceController, prepareForTransitionUsing context: AVExperienceController.TransitionContext) async
      
      func experienceController(_ controller: AVExperienceController, didChangeTransitionContext context: AVExperienceController.TransitionContext)
    • 12:52 - PortalVideoView

      @main
      struct ImmersiveVideoApp: App {
          var body: some Scene {
              WindowGroup {
                  PortalVideoView()
              }
          }
      }
    • 13:03 - Portal Rendering

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      struct PortalVideoView: View {
          var body: some View {
              RealityView { content in
                  guard let url = URL(string: "https://cdn.example.com/My180.m3u8") else { return }
                  let player = AVPlayer(playerItem: AVPlayerItem(url: url))
                  let videoEntity = Entity()
                  var videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
                  videoPlayerComponent.desiredImmersiveViewingMode = .portal
                  videoEntity.components.set(videoPlayerComponent)
                  videoEntity.scale *= 0.4
                  content.add(videoEntity)
              }
          }
      }
    • 13:57 - Progressive Immersion Rendering

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      struct ProgressiveVideoView: View {
          var body: some View {
              RealityView { content in
                  guard let url = URL(string: "https://cdn.example.com/My180.m3u8") else { return }
                  let player = AVPlayer(playerItem: AVPlayerItem(url: url))
                  let videoEntity = Entity()
                  var videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
                  videoPlayerComponent.desiredImmersiveViewingMode = .progressive
                  videoEntity.components.set(videoPlayerComponent)
                  content.add(videoEntity)
              }
          }
      }
    • 14:20 - ProgressiveVideoView

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      @main
      struct ImmersiveVideoApp: App {
          var body: some Scene {
              ImmersiveSpace {
                  ProgressiveVideoView()
              }
      				.immersionStyle(selection: .constant(.progressive(0.1...1, initialAmount: 1.0)), in: .progressive)    
          }
      }
    • 17:22 - SpatialVideoMode

      if let vpc = components.get[VideoPlayerComponent.self] {
      	vpc.desiredSpatialVideoMode = .spatial
      }
    • 18:32 - Spatial Video Portal Rendering

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      struct PortalSpatialVideoView: View {
          var body: some View {
              RealityView { content in
                  let url = Bundle.main.url(forResource: "MySpatialVideo", withExtension: "mov")!
                  let player = AVPlayer(url: url)
                  let videoEntity = Entity()
                  var videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
                  videoPlayerComponent.desiredViewingMode = .stereo
                  videoPlayerComponent.desiredSpatialVideoMode = .spatial
                  videoPlayerComponent.desiredImmersiveViewingMode = .portal
                  videoEntity.components.set(videoPlayerComponent)
                  videoEntity.scale *= 0.4
                  content.add(videoEntity)
              }
          }
      }
    • 19:02 - Spatial Video Immersive Rendering

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      struct PortalSpatialVideoView: View {
          var body: some View {
              RealityView { content in
                  let url = Bundle.main.url(forResource: "MySpatialVideo", withExtension: "mov")!
                  let player = AVPlayer(url: url)
                  let videoEntity = Entity()
                  var videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
                  videoPlayerComponent.desiredViewingMode = .stereo
                  videoPlayerComponent.desiredSpatialVideoMode = .spatial
                  videoPlayerComponent.desiredImmersiveViewingMode = .full
                  videoEntity.position = [0, 1.5, -1]
                  videoEntity.components.set(videoPlayerComponent)
                  content.add(videoEntity)
              }
          }
      }
    • 19:46 - ImmersiveSpatialVideoView

      import AVFoundation
      import RealityKit
      import SwiftUI
      
      @main
      struct SpatialVideoApp: App {
          var body: some Scene {
              ImmersiveSpace {
                  ContentSimpleView()
              }
              .immersionStyle(selection: .constant(.mixed), in: .mixed)
              .immersiveEnvironmentBehavior(.coexist)
          }
      }
    • 21:40 - Comfort Mitigation Event

      switch event.comfortMitigation {
      case .reduceImmersion:
          // Default behavior
          break
      case .play:
          // No action
          break
      case .pause:
          // Show custom pause dialog
          break
      }
    • 0:00 - 简介
    • 这个视频介绍了 AVKit 与“快速查看”中用于沉浸式视频播放的新 API,并讲解如何通过 RealityKit 定制沉浸式播放体验。

    • 1:24 - visionOS 26 支持的视频格式规范
    • visionOS 26 引入多个全新视频描述文件,包括适用于 180°、360°和宽视野视频的 APMP,以及 Apple 沉浸视频格式,带来极致的沉浸式体验。你可以在 App 中使用“快速查看”、AVKit 或 RealityKit 进行播放。

    • 3:09 - 通过快速查看播放沉浸视频
    • visionOS 26 中的“快速查看”提供了两套 API:PreviewApplication 用于进程外的媒体呈现;QLPreviewController 用于 App 内媒体预览。这两个 API 均已更新,支持空间照片和视频、Apple 沉浸视频,以及 Apple 投影媒体描述文件。已采用 Quick Look API 的 App 将自动支持这些全新的沉浸式媒体描述文件。

    • 4:25 - 使用 AVKit 播放沉浸视频
    • AVKit 推出了“AVExperienceController”,提供两种主要体验模式:扩展模式与沉浸模式。你现在可以配置扩展模式以实现沉浸式播放,同时可选择停用自动过渡效果。这样可以在检测到沉浸式内容时,以“传送门”的形式进行展示。你也可以通过全新的 Immersive Experience API 显式切换至沉浸式体验。它提供配置 API,用于定义沉浸式视频播放的位置。 “AVExperienceController”还处理不同体验模式间的动画与过渡。此外,控制器的委托协议在监测过渡和呈现状态变化方面至关重要,确保你的 App 能够灵活适配不同类型的内容和用户交互。

    • 9:11 - 不适感缓解检测
    • visionOS 26 在“快速查看”和 AVKit 中为沉浸式视频引入了不适感缓解检测机制。系统会在播放 Apple 投影媒体描述文件内容时自动降低高运动场景的沉浸程度,以防止观看不适。用户可在“设置”App 中进行个性化调整。

    • 9:51 - 利用 RealityKit 打造自定播放体验
    • RealityKit 是在 visionOS 中播放自定沉浸式视频的首选框架,特别适用于具有独特 UI 的游戏和 App。在 visionOS 26 中,RealityKit 的 VideoPlayerComponent 支持原生播放各类沉浸式视频,包括 180°、360°和宽视野格式,以及 Apple 沉浸视频和空间视频渲染,体验效果与“照片”App 一致。这个组件可自动处理网格更新与动画,适合打造动态沉浸式视频体验。

    • 11:48 - RealityKit 中的 Progressive 沉浸模式
    • 在 visionOS 26 中,“VideoPlayerComponent”支持三种 Apple 投影媒体描述文件与 Apple 沉浸视频的观看模式:传送门、渐进式和完全沉浸式。 传送门模式:将视频呈现在传送门中。渐进式模式 (visionOS 26 中新增的模式):让用户通过数码旋钮来调整沉浸程度,兼顾舒适性与灵活性。它相当于在 100% 时达到完全沉浸。要配置播放模式,请设置“desiredImmersiveViewingMode”。使用渐进式模式时,请在“ImmersiveSpace”中使用渐进式的“ImmersionStyle”,并确保样式与模式一致。沉浸式播放模式事件会在切换过程中触发,用于控制 UI 显示状态。

    • 16:32 - 使用 RealityKit 进行空间视频渲染
    • RealityKit 现已原生支持空间视频,可实现具备完整空间风格的沉浸式渲染。你可以通过“VideoPlayerComponent”的“desiredSpatialVideoMode”属性配置空间样式。 将这个属性设为“.spatial”可启用空间样式,并允许在“.portal”或“.full”两种沉浸式观看模式下进行渲染。“.full”模式通常用于沉浸式空间视频,按照内容视角以固定尺寸进行渲染。 默认的“.screen”模式会将空间视频以传统立体方式渲染在屏幕网格上。你可以订阅“SpatialVideoModeDidChange”事件,以监听“spatialVideoMode”属性的更新。 要创建空间视频的传送门播放,请将“desiredSpatialVideoMode”设置为“.spatial”,并将“desiredImmersiveViewingMode”设置为“.portal”。要实现沉浸式空间视频渲染,请使用“.full”模式、混合沉浸样式,并启用“immersiveEnvironmentBehavior”的“coexist”选项。

    • 21:16 - RealityKit 中的不适感缓解检测
    • RealityKit 会自动检测 Apple 投影媒体描述文件视频中是否存在高运动内容,并应用不适感缓解功能。系统通过“VideoComfortMitigationDidOccur”事件将这些调整通知给 App。要启用“reducedImmersion”的不适感缓解功能,必须使用渐进式渲染。而传送门渲染由于本身已适用于大多数内容的舒适观看,无需进行这类处理。“ContentTypeDidChange”事件可帮助你根据不同类型的视频内容,适配所需的观看模式和对应的不适感缓解要求。

    • 22:57 - RealityKit 内容与 SwiftUI 的深度整合
    • 在将 RealityKit 的 VideoPlayerComponent 与 SwiftUI 集成时,应确保视频实体在 X 和 Y 轴上的缩放比例一致,以保持正确的宽高比,这在传送门模式下尤为重要。使用“GeometryReader3D”可根据可用窗口尺寸对视频进行缩放,避免内容被裁切。 当自定 UI 与视频网格位于同一平面时,会出现未定义的渲染排序行为。要解决自定 UI 与视频网格处于同一平面时的渲染排序问题,请添加一个包含“planarUIPlacement”分类的“ModelSortGroupComponent”。

Developer Footer

  • 视频
  • WWDC25
  • 支持 visionOS App 播放沉浸视频
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则