如何检查我的AVPlayer是否正在缓冲?

vrw*_*wim 27 buffering ios avplayer

我想检测我的AVPlayer是否正在缓冲当前位置,以便我可以显示加载器或其他东西.但我似乎无法在AVPlayer的文档中找到任何内容.

Mar*_*ssa 40

你可以观察你的价值观player.currentItem:

playerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .New, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .New, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackBufferFull", options: .New, context: nil)
Run Code Online (Sandbox Code Playgroud)

然后

override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if object is AVPlayerItem {
        switch keyPath {
            case "playbackBufferEmpty":
               // Show loader

            case "playbackLikelyToKeepUp":
                // Hide loader

            case "playbackBufferFull":
                // Hide loader
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 当 AVPlayer 寻找到某个位置时,它不起作用。 (7认同)
  • 在我的情况下,从未调用过“playbackBufferFull”。你能告诉我原因吗?@马可 (2认同)

ayt*_*tek 17

接受的答案对我不起作用,我使用下面的代码有效地显示加载程序.

斯威夫特3

//properties 
var observer:Any!
var player:AVPlayer!


self.observer = self.player.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 600), queue: DispatchQueue.main) {
    [weak self] time in

    if self?.player.currentItem?.status == AVPlayerItemStatus.readyToPlay {

        if let isPlaybackLikelyToKeepUp = self?.player.currentItem?.isPlaybackLikelyToKeepUp {
            //do what ever you want with isPlaybackLikelyToKeepUp value, for example, show or hide a activity indicator.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

对我来说,上面接受的答案没有用,但是这种方法可以用。您可以使用timeControlStatus,但它仅在iOS 10以上可用。

根据苹果官方文件

一种状态,指示在等待适当的网络条件时是当前正在进行播放,无限期暂停还是暂停播放

将此观察者添加到播放器。

player.addObserver(self, forKeyPath: “timeControlStatus”, options: [.old, .new], context: nil)
Run Code Online (Sandbox Code Playgroud)

然后,观察

func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
Run Code Online (Sandbox Code Playgroud)

在上面的方法中使用下面的代码

override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "timeControlStatus", let change = change, let newValue = change[NSKeyValueChangeKey.newKey] as? Int, let oldValue = change[NSKeyValueChangeKey.oldKey] as? Int {
        let oldStatus = AVPlayer.TimeControlStatus(rawValue: oldValue)
        let newStatus = AVPlayer.TimeControlStatus(rawValue: newValue)
        if newStatus != oldStatus {
            DispatchQueue.main.async {[weak self] in
                if newStatus == .playing || newStatus == .paused {
                    self?.loaderView.isHidden = true
                } else {
                    self?.loaderView.isHidden = false
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这已在上面的iOS 11上使用swift 4进行了测试,并且正在运行。

  • 这是唯一适用于 iOS 13 和 swift 5 的东西 (3认同)

Rei*_*ill 7

在斯威夫特 5.3 中

变量:

private var playerItemBufferEmptyObserver: NSKeyValueObservation?
private var playerItemBufferKeepUpObserver: NSKeyValueObservation?
private var playerItemBufferFullObserver: NSKeyValueObservation?
Run Code Online (Sandbox Code Playgroud)

添加观察者

playerItemBufferEmptyObserver = player.currentItem?.observe(\AVPlayerItem.isPlaybackBufferEmpty, options: [.new]) { [weak self] (_, _) in
    guard let self = self else { return }
    self.showLoadingIndicator(over: self)
}
    
playerItemBufferKeepUpObserver = player.currentItem?.observe(\AVPlayerItem.isPlaybackLikelyToKeepUp, options: [.new]) { [weak self] (_, _) in
    guard let self = self else { return }
    self.dismissLoadingIndicator()
}
    
playerItemBufferFullObserver = player.currentItem?.observe(\AVPlayerItem.isPlaybackBufferFull, options: [.new]) { [weak self] (_, _) in
    guard let self = self else { return }
    self.dismissLoadingIndicator()
}
Run Code Online (Sandbox Code Playgroud)

删除观察者

playerItemBufferEmptyObserver?.invalidate()
playerItemBufferEmptyObserver = nil
    
playerItemBufferKeepUpObserver?.invalidate()
playerItemBufferKeepUpObserver = nil
    
playerItemBufferFullObserver?.invalidate()
playerItemBufferFullObserver = nil
Run Code Online (Sandbox Code Playgroud)


Rom*_*zak 5

Swift 4 观察:

var playerItem: AVPlayerItem?
var playbackLikelyToKeepUpKeyPathObserver: NSKeyValueObservation?
var playbackBufferEmptyObserver: NSKeyValueObservation?
var playbackBufferFullObserver: NSKeyValueObservation?

private func observeBuffering() {
    let playbackBufferEmptyKeyPath = \AVPlayerItem.playbackBufferEmpty
    playbackBufferEmptyObserver = playerItem?.observe(playbackBufferEmptyKeyPath, options: [.new]) { [weak self] (_, _) in
        // show buffering
    }

    let playbackLikelyToKeepUpKeyPath = \AVPlayerItem.playbackLikelyToKeepUp
    playbackLikelyToKeepUpKeyPathObserver = playerItem?.observe(playbackLikelyToKeepUpKeyPath, options: [.new]) { [weak self] (_, _) in
        // hide buffering
    }

    let playbackBufferFullKeyPath = \AVPlayerItem.playbackBufferFull
    playbackBufferFullObserver = playerItem?.observe(playbackBufferFullKeyPath, options: [.new]) { [weak self] (_, _) in
        // hide buffering
    }
}
Run Code Online (Sandbox Code Playgroud)

完成观察后需要移除观察者。

删除这三个观察者刚刚设置playbackBufferEmptyObserverplaybackLikelyToKeepUpKeyPathObserverplaybackBufferFullObservernil

无需手动删除它们(这是特定于observe<Value>(_ keyPath:, options:, changeHandler:)方法的。


Amr*_*ari 5

#已在Swift 4中更新并正常运行

由于我已经接受了可接受的答案,但对我而言却没有迅速完成工作,因此在进行某些研究后,我发现这是苹果医生的想法。确定AVPlayer状态的方法有两种:

  1. addPeriodicTimeObserverForInterval:queue:usingBlock:和
  2. addBoundaryTimeObserverForTimes:queue:usingBlock:

和使用方式是这样的

var observer:Any?
var avplayer : AVPlayer?

func preriodicTimeObsever(){

        if let observer = self.observer{
            //removing time obse
            avplayer?.removeTimeObserver(observer)
            observer = nil
        }

        let intervel : CMTime = CMTimeMake(1, 10)
        observer = avplayer?.addPeriodicTimeObserver(forInterval: intervel, queue: DispatchQueue.main) { [weak self] time in

            guard let `self` = self else { return }

            let sliderValue : Float64 = CMTimeGetSeconds(time)
           //this is the slider value update if you are using UISlider.

            let playbackLikelyToKeepUp = self.avPlayer?.currentItem?.isPlaybackLikelyToKeepUp
            if playbackLikelyToKeepUp == false{

               //Here start the activity indicator inorder to show buffering
            }else{
                //stop the activity indicator 
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

并且不要忘记杀死时间观察者以避免内存泄漏。杀死实例的方法,根据您的需要添加此方法,但是我在viewWillDisappear方法中使用了它。

       if let observer = self.observer{

            self.avPlayer?.removeTimeObserver(observer)
            observer = nil
        }
Run Code Online (Sandbox Code Playgroud)


小智 5

更新为 Swift 4.2

    var player : AVPlayer? = nil

    let videoUrl = URL(string: "https://wolverine.raywenderlich.com/content/ios/tutorials/video_streaming/foxVillage.mp4")
    self.player = AVPlayer(url: videoUrl!)
    self.player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 600), queue: DispatchQueue.main, using: { time in

        if self.player?.currentItem?.status == AVPlayerItem.Status.readyToPlay {

            if let isPlaybackLikelyToKeepUp = self.player?.currentItem?.isPlaybackLikelyToKeepUp {
                //do what ever you want with isPlaybackLikelyToKeepUp value, for example, show or hide a activity indicator.

                //MBProgressHUD.hide(for: self.view, animated: true)
            }
        }
    })
Run Code Online (Sandbox Code Playgroud)