使用 automaticallyLoadedAssetKeys 和 "duration" 初始化 AVPlayerItem

Initializing an AVPlayerItem with automaticallyLoadedAssetKeys and "duration"

我正在初始化一个 AVPlayerItem,它需要一个参数 automaticallyLoadedAssetKeys,它指示在它被标记为 "ready to play" 之前需要加载哪些 AVAsset 键.

我见过有人将 duration 属性 作为这些键之一传递的示例。

但是在 AVPlayerItem 的文档中,它谈到了 duration 属性,以及如何确保它有效。

The value of this property will be reported as kCMTimeIndefinite until the duration of the underlying asset has been loaded. There are two ways to ensure that the value of duration is accessed only after it becomes available:

Wait until the status of the player item is readyToPlay

另一种方式是注册一个KVO,也可以。但是这第一条评论向我表明我不需要要求自动加载duration,因为它应该已经。(?)

如果这是真的,我不明白为什么有人会传入 duration 作为自动加载的标志,因为看起来就是这样。我在这里遗漏了什么吗?

有些人这样做是因为存在 iOS 个错误(包括 iOS 12.1.4 中的错误)有时会导致 AVPlayerItem.duration 为 nan,即使状态为 readyToPlay。示例 here and here.

但是,我的经验是在 automaticallyLoadedAssetKeys 中指定 "duration" 并不能解决问题 - 尽管 Apple 的 AVPlayerItem 文档:

The value of each key in automaticallyLoadedAssetKeys will automatically be loaded by the underlying AVAsset before the player item achieves the status AVPlayerItem.Status.readyToPlay; i.e. when the item is ready to play, the value returned by invoking the asset property’s statusOfValue(forKey:error:) method will be one of the terminal status values

我可以得到 AVPlayerItem.Status.readyToPlay,其中 statusOfValue(forKey: "duration") 返回 .loaded,持续时间为 nan。

我发现每次都有效的唯一解决方案是同时对 AVPlayerItem.status(对于 .readyToPlay)和 AVPlayerItem.duration(对于有效数字)进行 KVO,并且当其中一个触发时,检查两者:

    if item.status != AVPlayerItem.Status.readyToPlay || !item.duration.isUsableNumber() {
        return // not ready yet (for addBoundaryTimeObserver, seek to end, etc.)
    }

哪里 isUsableNunber() 只是:

 func isUsableNumber() -> Bool {
    return isValid && isNumeric && !isIndefinite && !isNegativeInfinity && !isPositiveInfinity
}

抱歉,我知道这有点陈旧。但我最近找到了问题的答案。

所以,我意识到我对文档感到困惑,它可能一直都在文档中,如果我仔细看,我会注意到的。

AVPlayerItem(asset: asset) 默认加载 duration 属性。就像调用 AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: ["duration"])

它实际上在文档中说了这个,但我完全错过了。