AVPlayer 在缓冲时显示和隐藏加载指示器

JEL*_*JEL 4 avfoundation ios avplayer swift

(注意:我正在运行 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 8

您可以使用 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 进行了测试,并且正在运行。


Amr*_*dhu 0

使用以下函数设置 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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)