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

关于AVPlayerItem初始化时传入duration至automaticallyLoadedAssetKeys的疑问

关于AVPlayerItem初始化时传入duration到automaticallyLoadedAssetKeys的合理性与有效性保障

好问题!其实把duration传入automaticallyLoadedAssetKeys不仅是恰当的,反而是推荐的实践——我来给你拆解清楚为什么,以及怎么确保你拿到的duration是有效的。

为什么传入duration是恰当的?

首先得明确automaticallyLoadedAssetKeys的核心作用:它告诉AVPlayerItem,在自身状态变为ready to play之前,必须先预加载你指定的AVAsset属性键。

你看到文档里说duration在资源加载完成前会返回kCMTimeIndefinite,这是没有预加载duration时的情况:如果你没把duration加入这个数组,直接访问playerItem.duration,底层AVAsset可能还没完成时长的加载,就会返回这个“不确定”的时间值。

但如果你把duration加入automaticallyLoadedAssetKeys,AVPlayerItem会在标记为ready状态前,自动完成duration的异步加载。这时候当你拿到ready状态的信号时,duration已经是有效的、准确的时长值了,不会再出现kCMTimeIndefinite。

如何确保duration的有效性?

要确保拿到有效的duration,关键是等待AVPlayerItem进入readyToPlay状态后再访问duration,结合预加载的配置,具体步骤如下:

  1. 初始化时正确传入duration键
    以Swift为例:

    let videoAsset = AVURLAsset(url: yourVideoURL)
    // 将"duration"加入自动加载的键数组
    let playerItem = AVPlayerItem(asset: videoAsset, automaticallyLoadedAssetKeys: ["duration"])
    

    Objective-C版本:

    AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:yourVideoURL];
    AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:videoAsset automaticallyLoadedAssetKeys:@[@"duration"]];
    
  2. 监听AVPlayerItem的status状态
    只有当playerItem的status变为.readyToPlay时,你指定的所有automaticallyLoadedAssetKeys才会加载完成,这时候访问duration就是安全有效的。

    用Swift Combine的方式监听(iOS 13+):

    var cancellables = Set<AnyCancellable>()
    
    playerItem.publisher(for: \.status)
        .receive(on: DispatchQueue.main)
        .sink { [weak self] status in
            guard let self = self else { return }
            switch status {
            case .readyToPlay:
                // 此时duration已加载完成,可安全访问
                let validDuration = self.playerItem.duration
                if CMTIME_IS_VALID(validDuration) {
                    // 处理有效时长,比如转为秒:CMTimeGetSeconds(validDuration)
                }
            case .failed(let error):
                print("加载失败:\(error.localizedDescription)")
            case .unknown:
                // 仍在加载中,等待即可
                break
            @unknown default:
                break
            }
        }
        .store(in: &cancellables)
    

    如果用传统KVO监听(兼容更早系统):

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard keyPath == "status", let item = object as? AVPlayerItem else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
    
        switch item.status {
        case .readyToPlay:
            let validDuration = item.duration
            // 处理有效时长
        case .failed(let error):
            print("加载失败:\(error.localizedDescription)")
        default:
            break
        }
    }
    
    // 记得添加监听
    playerItem.addObserver(self, forKeyPath: "status", options: [.new], context: nil)
    // 销毁时移除监听
    deinit {
        playerItem.removeObserver(self, forKeyPath: "status")
    }
    
  3. 额外补充:手动加载的备选方案
    如果因为某些原因你不想用automaticallyLoadedAssetKeys,也可以直接通过AVAsset手动加载duration:

    videoAsset.loadValuesAsynchronously(forKeys: ["duration"]) {
        DispatchQueue.main.async {
            var error: NSError?
            let status = videoAsset.statusOfValue(forKey: "duration", error: &error)
            switch status {
            case .loaded:
                let validDuration = videoAsset.duration
                // 处理时长
            case .failed(let err):
                print("加载失败:\(err.localizedDescription)")
            default:
                break
            }
        }
    }
    

    但这种方式需要你自己管理加载流程,不如让AVPlayerItem自动处理更贴合播放器的生命周期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:58:29