【问题标题】:HLS Live stream video doesn't play on first loadHLS 直播视频在首次加载时不播放
【发布时间】:2023-07-27 14:26:01
【问题描述】:

我正在尝试在 iOS 中进行直播,所以步骤如下 -

  1. 初始化播放器

    player                 = AVPlayer()
    player.rate            = 1.0
    player.actionAtItemEnd = AVPlayerActionAtItemEnd.none
    
  2. 设置播放器层

    playerLayer                 = AVPlayerLayer(player: player)
    playerLayer.frame           = self.bounds
    playerLayer.backgroundColor = UIColor.clear.cgColor
    playerLayer.videoGravity    = AVLayerVideoGravity.resizeAspectFill
    
    if let sublayers = self.layer.sublayers {
    
        for layer in sublayers {
            layer.removeFromSuperlayer()
        }
    }
    
    self.layer.addSublayer(playerLayer)
    
  3. 设置播放器项目

    let avAsset = AVURLAsset(url: streamingUrl)
    playerItem = AVPlayerItem(asset: avAsset)
    
  4. 替换播放器中的currentItem并播放

    self.player?.replaceCurrentItem(with: self.playerItem)
    self.player?.play()
    

如果我在流式传输开始后加载播放器,我的视频播放非常好,但如果我在从后端开始实时流式传输之前加载播放器,然后在一段时间后开始流式传输,它不播放视频。

我尝试将观察者添加到 playerItem 的状态属性,但在上述条件下也不会改变,只有在流式传输开始后加载播放器并且一切正常时才会改变。所以我的问题是为什么我的 playerItem 没有得到状态更改?我错过了什么吗?请帮忙。提前致谢。

【问题讨论】:

  • 检查url是否可播放AVAsset(url: URL).isPlayable,在你的情况下,你可以播放if avAsset.isPlayable { playerItem = AVPlayerItem(asset: avAsset); ... }
  • 其他情况怎么办?如果无法播放,如何处理?

标签: ios swift avplayer live-streaming hlsl


【解决方案1】:

使用AVAsset(url: URL).isPlayable检查网址是否可以播放,在你可以播放之前

if avAsset.isPlayable {
    playerItem = AVPlayerItem(asset: avAsset)
    ...
}

为了更好的方法,使用观察者

class ViewController: UIViewController {

    private var observerContext = 0
    private let player = AVPlayer()
    private var readyForPlayback = false

    private var playerItem: AVPlayerItem? {
        willSet {
            playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), context: &observerContext)
        }

        didSet {
            playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.initial, .new], context: &observerContext)
        }
    }

    private var asset: AVAsset? {
        willSet {
            readyForPlayback = false
            asset?.removeObserver(self, forKeyPath: #keyPath(AVURLAsset.isPlayable), context: &observerContext)
        }

        didSet {
            guard asset == nil else {
                asset!.addObserver(self, forKeyPath: #keyPath(AVURLAsset.isPlayable), options: [.initial, .new], context: &observerContext)
                return
            }

            playerItem = nil
            player.replaceCurrentItem(with: nil)
        }
    }

    // MARK: KVO
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard context == &observerContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }

        guard let keyPath = keyPath else { return }

        switch keyPath {
        case #keyPath(AVURLAsset.isPlayable):
            guard asset?.isPlayable == true else { return }
            playerItem = AVPlayerItem(asset: asset!)
            player.replaceCurrentItem(with: playerItem)
        case #keyPath(AVPlayerItem.status):
            guard let status = playerItem?.status else { return }

            if status == .readyToPlay {
                guard !readyForPlayback else { return }
                readyForPlayback = true
                player.play()
            } else if status == .failed {
                readyForPlayback = false
                if let error = playerItem?.error {
                    print("Error: \(error)")
                }
            }
        default:
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
}

用法

self.asset = AVAsset

停止播放

self.asset = nil

【讨论】:

  • 感谢您的回答,但我有一个疑问。使用此逻辑,只要 AvAsset 可播放,playerItem 就应将其状态更改为 readyToPlay。早些时候,我在 playerItem 状态上添加了观察者,该状态不起作用,任何可能的原因
  • AVAsset.isPlayable 本身第一次返回 true 但视频无法播放
  • 是调用case #keyPath(AVPlayerItem.status)的KVO是什么状态,可以调试打印statuserrorerrorplayerItem
  • 如果我在流媒体开始之前加载播放器,最初不会被调用。并且一旦流媒体开始,KVO 开始调用如果如果移动我在后台移动应用程序并来到前台,我再次强行说 AvPlayer 再次播放
  • @AjayKumar 你找到解决办法了吗?我有同样的问题
最近更新 更多