使用 HLS 视频时,仅在 iOS 13 上有 AVPlayerViewController 和 AVPlayer 的视频播放问题

chr*_*lig 9 ios avplayer avplayerlayer avplayerviewcontroller ios13

我有一个播放视频的应用程序。这是与iOS 11,12和iOS 13.在iOS上11和12兼容,视频播放可以正常运行的使用无论是预期的AVPlayerViewController,甚至只是AVPlayerLayer

但是,在 iOS 13 上,我开始收到报告,称很多用户在更新 iOS 时突然无法加载视频(或仅加载音频或仅加载第一帧)。我很难复制它,但有些人提到它主要发生在网络连接不良的情况下,并且使用 Network Link Conditioner 果然我能够复制它。

它特别影响 HLS 视频(例如,Reddit 使用的花哨的直播兼容视频)。它继续与 MP4 一起正常工作。这是一个失败的示例 URL:https : //v.redd.it/gl3chx2kd4v31/HLSPlaylist.m3u8

这是触发它的网络链接调节器配置文件:https : //i.imgur.com/XWsKUeM.jpg

这是触发它的示例项目,同时显示 AVPlayerViewController 和 AVPlayer(点击下载,Google 很奇怪):https : //drive.google.com/file/d/1RS5DvUypdOLFCYJe1Pt2Ig0fQljZDLs2/view

这是使用 AVPlayerViewController 展示它的示例代码:

let assetURL = URL(string: "https://v.redd.it/gl3chx2kd4v31/HLSPlaylist.m3u8")!

// The following MP4 URL *does* work, for instance
// let assetURL = URL(string: "https://giant.gfycat.com/DependentFreshKissingbug.mp4")!

let player = AVPlayer(url: assetURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player

self.present(playerViewController, animated: true) {
    playerViewController.player!.play()
}
Run Code Online (Sandbox Code Playgroud)

如果我在 iOS 12 设备上尝试使用完全相同的代码,则它可以完美运行。

有没有人对如何解决它有任何建议?如果您从头开始,有时您可以使视频正常播放,但不够可靠,因此似乎无法从中构建解决方案。视频内容绝对不是我在 iOS 开发中的强项,所以我开始有点摸不着头脑,任何帮助将不胜感激。

注意:我很清楚这是(很可能)一个 iOS 错误,我将提交一个雷达,但我现在仍然需要处理它。

Lun*_*s42 1

您需要了解playerItems 的状态才能知道它何时可以开始播放。然后在playerItem状态更改为准备播放调用你的player.play。

playerItem.addObserver(self,
                           forKeyPath: #keyPath(AVPlayerItem.status),
                           options: [.old, .new],
                           context: &playerItemContext)


override func observeValue(forKeyPath keyPath: String?,
                           of object: Any?,
                           change: [NSKeyValueChangeKey : Any]?,
                           context: UnsafeMutableRawPointer?) {

    // Only handle observations for the playerItemContext
    guard context == &playerItemContext else {
        super.observeValue(forKeyPath: keyPath,
                           of: object,
                           change: change,
                           context: context)
        return
    }

    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItemStatus
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        // Switch over status value
        switch status {
        case .readyToPlay:
            // Player item is ready to play.
        case .failed:
            // Player item failed. See error.
        case .unknown:
            // Player item is not yet ready.
        }
    }
}


Run Code Online (Sandbox Code Playgroud)