You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RealityKit的VideoMaterial中异步加载网络视频到AVPlayer

解决RealityKit视频加载卡顿及占位显示问题

核心思路

  1. 检测到参考图像后,先在主线程创建带占位材质(SimpleMaterial)的平面,立即添加到场景,避免用户看到卡顿或空白
  2. 异步加载网络视频资源,将视频加载逻辑放到后台队列,不阻塞主线程
  3. 视频加载完成后,切回主线程替换材质为VideoMaterial,再启动播放

修改后的完整代码

class Coordinator: NSObject, ARSessionDelegate {
    var parent: ARViewContainer
    var videoPlayer: AVPlayer?

    init(parent: ARViewContainer) {
        self.parent = parent
    }

    func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        guard let imageAnchor = anchors.first as? ARImageAnchor,
              imageAnchor.name == "referenceimg1" else { return }
        
        // 1. 主线程创建占位平面(带SimpleMaterial),立即显示
        let planeSize = imageAnchor.referenceImage.physicalSize
        let placeholderMaterial = SimpleMaterial(
            color: .gray,
            isMetallic: false
        )
        let videoPlane = ModelEntity(
            mesh: .generatePlane(
                width: Float(planeSize.width),
                depth: Float(planeSize.height),
                cornerRadius: 10
            ),
            materials: [placeholderMaterial]
        )
        
        let anchorEntity = AnchorEntity(anchor: imageAnchor)
        anchorEntity.addChild(videoPlane)
        parent.arView.scene.addAnchor(anchorEntity)
        
        // 2. 后台队列异步加载视频,避免阻塞主线程
        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
            guard let self = self,
                  let videoURL = URL(string: "https://swiftanytime-content.s3.ap-south-1.amazonaws.com/SwiftUI-Beginner/Video-Player/iMacAdvertisement.mp4") else { return }
            
            let playerItem = AVPlayerItem(url: videoURL)
            // 监听视频加载状态
            let statusObservation = playerItem.observe(\.status, options: [.new]) { [weak self, weak videoPlane] item, change in
                guard let self = self, let videoPlane = videoPlane else { return }
                
                DispatchQueue.main.async {
                    switch item.status {
                    case .readyToPlay:
                        // 3. 主线程替换为VideoMaterial并播放
                        self.videoPlayer = AVPlayer(playerItem: item)
                        let videoMaterial = VideoMaterial(avPlayer: self.videoPlayer!)
                        videoPlane.model?.materials = [videoMaterial]
                        self.videoPlayer?.play()
                    case .failed:
                        // 加载失败可添加错误处理,比如显示错误材质
                        let errorMaterial = SimpleMaterial(color: .red, isMetallic: false)
                        videoPlane.model?.materials = [errorMaterial]
                    case .unknown:
                        break
                    @unknown default:
                        break
                    }
                }
            }
            // 保留观察对象,避免被提前释放
            statusObservation.retain()
        }
    }
}

关键细节说明

  • 异步加载:用DispatchQueue.global(qos: .userInitiated)将视频加载逻辑放到后台,主线程只负责UI相关操作,彻底解决卡顿
  • 占位材质:先显示灰色SimpleMaterial,你可以根据需求修改颜色、添加纹理(比如加载动画图片)
  • 状态监听:通过KVO监听AVPlayerItem的status属性,确保视频真正准备好后再替换材质,避免播放异常
  • 弱引用处理:使用[weak self]和[weak videoPlane]避免循环引用,防止内存泄漏

内容的提问来源于stack exchange,提问作者user1207524

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:05:26