Подтвердить что ты не робот

Как проверить, работает ли мой AVPlayer?

Я хочу определить, является ли мой AVPlayer буферизацией для текущего местоположения, чтобы я мог показать загрузчика или что-то в этом роде. Но я не могу найти ничего в документации для AVPlayer.

4b9b3361

Ответ 1

Вы можете увидеть значения вашего 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)

затем

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

Ответ 2

Принятый ответ не сработал у меня, я использовал приведенный ниже код, чтобы эффективно показывать загрузчик.

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

Ответ 3

Свифт 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
    }
}

Наблюдатели должны быть удалены после того, как мы закончим наблюдение.

Чтобы удалить этих трех наблюдателей, просто установите playbackBufferEmptyObserver, playbackLikelyToKeepUpKeyPathObserver и playbackBufferFullObserver в nil.

Не нужно удалять их вручную (это характерно для метода observe<Value>(_ keyPath:, options:, changeHandler:).

Ответ 4

# Обновлен в Swift 4 и работал нормально

После того, как я прошел с принятым ответом, но не работал в swift 4 для меня, так что после определенного исследования я нашел эту мысль из Apple Doc. Существует два способа определения состояний AVPlayer:

  1. addPeriodicTimeObserverForInterval: queue: usingBlock: и
  2. addBoundaryTimeObserverForTimes: очереди: 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 
            }
        }
    }

И не забудьте убить время наблюдателя, чтобы уберечь от утечки памяти. метод для убийства экземпляра, добавьте этот метод в соответствии с вашими потребностями, но я использовал его в методе viewWillDisappear.

       if let observer = self.observer{

            self.avPlayer?.removeTimeObserver(observer)
            observer = nil
        }

Ответ 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)
            }
        }
    })

Ответ 6

Хм, принятое решение у меня не сработало, а решения периодического наблюдателя кажутся жестокими.

Вот мое предложение, наблюдатель timeControlerStatus на 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)
    }
}

Ответ 7

Вот простой метод, который работает с Swift 5.

Это добавит loadingIndicator, когда ваш игрок остановлен

NotificationCenter.default.addObserver(self, selector:
#selector(playerStalled(_:)), name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: self.player?.currentItem)

@objc func playerStalled(_ notification: Notification){
    self.loadingIndicator.isHidden = false
    self.playPauseButton.isHidden = true
}

Это покажет индикатор загрузчика, когда буфер пуст:

if let isPlayBackBufferEmpty = self.player?.currentItem?.isPlaybackBufferEmpty{
    if isPlayBackBufferEmpty{
        self.loadingIndicator.isHidden = false
        self.playPauseButton.isHidden = true
    }
}

Это будет скрывать загрузчик, когда игрок готов к игре:

if self.playerItem?.status == AVPlayerItem.Status.readyToPlay{
    if let isPlaybackLikelyToKeepUp = self.player?.currentItem?.isPlaybackLikelyToKeepUp {
        if isPlaybackLikelyToKeepUp{
            self.loadingIndicator.isHidden = true
            self.playPauseButton.isHidden = false
        }
    }
}

Ответ 8

Я также застрял с этой проблемой в течение нескольких месяцев, и сегодня я нашел эту статью, и моя проблема была решена. Я использовал Swift 4 и iOS 12 в качестве базового SDK.

Состояние буферизации AVPlayer и показ/скрытие событий загрузчика

Это работает в Swift 4 и iOS 12 Base SDK. Это также будет работать, когда мы стремимся к определенной позиции.

Ответ 9

Для меня принятый выше ответ не работал, но этот метод работает. Вы можете использовать timeControlStatus, но он доступен только выше iOS 10.

Согласно официальной документации Apple

Состояние, указывающее, выполняется ли воспроизведение в данный момент, приостановлено на неопределенное время или приостановлено в ожидании соответствующих условий сети

Добавьте этого наблюдателя к игроку.

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

Затем обратите внимание на изменения в

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

method.Use ниже кода внутри выше метода

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 и работает.