ios avplayer buffering

ios - ¿Cómo puedo comprobar si mi AVPlayer está almacenando en búfer?



buffering (6)

Hmm, la solución aceptada no funcionó para mí y las soluciones periódicas de observación parecen ser de mano dura.

Aquí está mi sugerencia, observador timeControlerStatus en AVPlayer .

// Add observer player.addObserver(self, forKeyPath: #keyPath(AVPlayer.timeControlStatus), options: [.new], context: &playerItemContext) // At some point you''ll need to remove yourself as an observer otherwise // your app will crash self.player?.removeObserver(self, forKeyPath: #keyPath(AVPlayer.timeControlStatus)) // handle keypath callback if keyPath == #keyPath(AVPlayer.timeControlStatus) { guard let player = self.player else { return } if let isPlaybackLikelyToKeepUp = player.currentItem?.isPlaybackLikelyToKeepUp, player.timeControlStatus != .playing && !isPlaybackLikelyToKeepUp { self.playerControls?.loadingStatusChanged(true) } else { self.playerControls?.loadingStatusChanged(false) } }

Quiero detectar si mi AVPlayer está almacenando en búfer para la ubicación actual, de modo que pueda mostrar un cargador o algo así. Pero parece que no puedo encontrar nada en la documentación de AVPlayer.


La respuesta aceptada no me funcionó, utilicé el siguiente código para mostrar el cargador de manera eficiente.

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


Swift 4 observaciones:

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

Los observadores deben ser eliminados una vez que hayamos terminado de observar.

Para eliminar estos tres observadores, simplemente establezca playbackBufferEmptyObserver , playbackLikelyToKeepUpKeyPathObserver y playbackBufferFullObserver en nil .

No es necesario eliminarlos manualmente (esto es específico para observe<Value>(_ keyPath:, options:, changeHandler:) método observe<Value>(_ keyPath:, options:, changeHandler:) .


# Actualizado en Swift 4 y funcionó bien

Ya que he ido con una respuesta aceptada, pero no funcioné en Swift 4 para mí, así que después de cierta investigación encontré esta opinión en Apple Doc . Hay dos formas de determinar los estados de AVPlayer que son,

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

y usar formas es así

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

Y no te olvides de matar el tiempo del observador para guardar de la pérdida de memoria . método para matar la instancia, agregue este método según su necesidad, pero lo he usado en el método viewWillDisappear.

if let observer = self.observer{ self.avPlayer?.removeTimeObserver(observer) observer = nil }


Actualizado para 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) } } })


Puedes observar los valores de tu 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)

entonces

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