【问题标题】:AVPlayer show and hide loading indicator when bufferingAVPlayer 在缓冲时显示和隐藏加载指示器
【发布时间】:2017-08-02 06:30:57
【问题描述】:

(注意:我正在运行 iOS 9 并且正在进行 HTTP 直播)

我有一个AVPlayer,想在播放器缓冲时显示一个加载指示器。当播放器开始使用慢速连接播放时,KVO 会调用这些属性: isPlaybackBufferEmpty

isPlaybackLikelyToKeepUp

isPlaybackBufferFull

问题是,当缓冲完成时,这些相同的属性不会再次被调用(当我说完成时,我的意思是视频可以再次播放。)我的目标是在正确的时间隐藏加载指示器,但是这些不要再被叫了。

我在网上搜索,发现了这个雷达:http://www.openradar.me/25931165 不确定它是否 100% 相关

有什么想法吗?

// MARK: - Key-Value Observing Method

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == #keyPath(AVPlayerItem.status) {

        switch playerItem.status {
        case .unknown:
            break

        case .readyToPlay:
            player.play()

        case .failed:
            postPlaybackDidFailWithErrorNotification(error: error)
        }
    }
    else if keyPath == #keyPath(AVPlayer.currentItem.isPlaybackBufferEmpty) {
        guard let currentItem = player.currentItem else {
            return
        }

        if currentItem.isPlaybackBufferEmpty {
            print("isPlaybackBufferEmpty = YES")
        } else {
            print("isPlaybackBufferEmpty = NO")
        }
    }
    else if keyPath == #keyPath(AVPlayer.currentItem.isPlaybackLikelyToKeepUp) {
        guard let currentItem = player.currentItem else {
            return
        }

        if currentItem.isPlaybackLikelyToKeepUp {
            print("isPlaybackLikelyToKeepUp = YES")
            //player.play()
        } else {
            print("isPlaybackLikelyToKeepUp = NO")
        }

    }
    else if keyPath == #keyPath(AVPlayer.currentItem.isPlaybackBufferFull) {
        guard let currentItem = player.currentItem else {
            return
        }

        if currentItem.isPlaybackBufferFull {
            print("isPlaybackBufferFull = YES")
            //player.play()
        } else {
            print("isPlaybackBufferFull = NO")
        }
    }
else if keyPath == #keyPath(AVPlayer.currentItem) {
    // Cleanup if needed.
    if player.currentItem == nil {
        video = nil
        playerItem = nil
    }        
}
else if keyPath == #keyPath(AVPlayer.rate) {
    updateMetadata()
    NotificationCenter.default.post(name: AssetPlaybackManager.NotificationName.playerRateDidChangeNotification, object: nil)
}
else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

【问题讨论】:

标签: ios swift avfoundation avplayer


【解决方案1】:

您可以使用 timeControlStatus,但它仅适用于 iOS 10 以上。

根据苹果官方文档

指示当前是否正在播放的状态, 无限期暂停,或在等待适当的时候暂停 网络状况

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

player.addObserver(self, forKeyPath: “timeControlStatus”, options: [.old, .new], context: nil)

然后,观察变化

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

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

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
                }
            }
        }
    }
}

这是在 iOS 11 上使用 swift 4 测试的,它正在工作。

【讨论】:

    【解决方案2】:

    使用下面的函数来设置AVPlayer的缓冲进度和状态:

    func addObserver() {
        let intervel : CMTime = CMTimeMake(value: 10, timescale: 10)
        observer = player?.addPeriodicTimeObserver(forInterval: intervel, queue: DispatchQueue.main) { [weak self] time in
    
            guard let `self` = self,
                let playerItem = self.player?.currentItem else { return }
    
            let currentTime : Float64 = CMTimeGetSeconds(time)
            let totalDuration = CMTimeGetSeconds(playerItem.asset.duration)
    
            //this is the slider value update if you are using UISlider.
            let sliderValue = (currentTime/totalDuration)
    
            if currentTime >= totalDuration {
                if let observer = self.observer{
                    //removing time observer
                    self.player?.removeTimeObserver(observer)
                    self.observer = nil
                }
            }
    
            let playbackLikelyToKeepUp = self.player?.currentItem?.isPlaybackLikelyToKeepUp
            if playbackLikelyToKeepUp == false{
                print(self.player?.rate)
                    print("IsBuffering")
                    self.lock()
            } else {
                //stop the activity indicator
                print("Buffering completed")
                self.unlock()
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多