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

时间:2019-10-28 02:39:33

标签: ios avplayer ios13 avplayerviewcontroller avplayerlayer

我有一个播放视频的应用程序。它与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()
}

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

有人对如何解决它有任何建议吗?如果您有时有时重新开始,则可以正常播放视频,但不够可靠,因此似乎无法解决该问题。视频内容绝对不是我在iOS开发中的强项,所以我开始有点挠头,对您的任何帮助将非常感激。

注意:我很清楚这是(可能是)一个iOS错误,我将提交Radar,但我现在仍然必须对其进行处理。

1 个答案:

答案 0 :(得分: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.
        }
    }
}