Проверьте состояние воспроизведения AVPlayer - PullRequest
100 голосов
/ 14 апреля 2011

Есть ли способ узнать, остановилось ли воспроизведение AVPlayer или достигло конца?

Ответы [ 9 ]

316 голосов
/ 15 февраля 2012

Вы можете сказать, что он играет, используя:

AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
    // player is playing
}

Расширение Swift 3:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
56 голосов
/ 14 апреля 2011

Чтобы получить уведомление о достижении конца элемента (через Apple ):

[[NSNotificationCenter defaultCenter] 
      addObserver:<self>
      selector:@selector(<#The selector name#>)
      name:AVPlayerItemDidPlayToEndTimeNotification 
      object:<#A player item#>];

А для отслеживания воспроизведения вы можете:

"отслеживать изменения вположение точки воспроизведения в объекте AVPlayer "с помощью addPeriodicTimeObserverForInterval: queue: usingBlock: или addBoundaryTimeObserverForTimes: queue: usingBlock: .

Пример от Apple:

// Assume a property: @property (retain) id playerObserver;

Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1);
NSArray *times = [NSArray arrayWithObjects:[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird], nil];

self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
    // Passing NULL for the queue specifies the main queue.

    NSString *timeDescription = (NSString *)CMTimeCopyDescription(NULL, [self.player currentTime]);
    NSLog(@"Passed a boundary at %@", timeDescription);
    [timeDescription release];
}];
35 голосов
/ 13 декабря 2016

В iOS10 для этого есть встроенное свойство: timeControlStatus

Например, эта функция воспроизводит или приостанавливает avPlayer в зависимости от его состояния и соответствующим образом обновляет кнопку воспроизведения / паузы.

@IBAction func btnPlayTap(_ sender: Any) {
    if aPlayer.timeControlStatus == .playing {
        aPlayer.pause()
        btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
    } else if aPlayer.timeControlStatus == .paused {
        aPlayer.play()
        btnPlay.setImage(UIImage(named: "control-pause"), for: .normal)
    }
}

Что касается вашего второго вопроса, чтобы узнать, достиг ли конец avPlayer, проще всего было бы настроить уведомление.

NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)

Когда он получитнапример, до конца вы можете перемотать его в начало видео и сбросить кнопку «Пауза» на «Воспроизведение».

@objc func didPlayToEnd() {
    aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
    btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}

Эти примеры полезны, если вы создаете свои собственные элементы управления, но еслиВы используете AVPlayerViewController, тогда элементы управления встроены.

18 голосов
/ 27 апреля 2017

rate - это НЕ способ проверить, воспроизводится ли видео (оно может остановиться).Из документации rate:

Указывает желаемую скорость воспроизведения;0.0 означает «пауза», 1.0 означает желание играть с естественной скоростью текущего предмета.

Ключевые слова «желание играть» - ставка 1.0 не означаетвидео воспроизводится.

Решение, поскольку в iOS 10.0 используется AVPlayerTimeControlStatus, которое можно наблюдать в свойстве AVPlayer timeControlStatus.

Решение, предшествующее iOS 10.0 (9.0, 8.0 и т. Д.), Заключается в создании собственного решения. Скорость 0.0 означает, что видео приостановлено.Когда rate != 0.0 означает, что видео воспроизводится или остановлено.

Вы можете узнать разницу, наблюдая за временем игрока с помощью: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

Блок возвращает текущее время игрока в CMTime, поэтому сравнение lastTime (время, которое последний раз было получено из блока) и currentTime (время, которое блок только что сообщил) покажет, является ли игрокиграет или застопорился.Например, если lastTime == currentTime и rate != 0.0, то проигрыватель остановился.

Как отмечали другие, выяснение того, закончилось ли воспроизведение, обозначается AVPlayerItemDidPlayToEndTimeNotification.

18 голосов
/ 16 декабря 2015

Более надежной альтернативой NSNotification является добавление себя в качестве наблюдателя к свойству rate игрока.

[self.player addObserver:self
              forKeyPath:@"rate"
                 options:NSKeyValueObservingOptionNew
                 context:NULL];

Затем проверьте, является ли новое значение для наблюдаемой скорости равным нулю, что означает, что воспроизведение остановилось по какой-то причине, например по достижении конца или остановке из-за пустого буфера.* В случае rate == 0.0, чтобы узнать, что именно привело к остановке воспроизведения, вы можете выполнить следующие проверки:

if (self.player.error != nil) {
    // Playback failed
}
if (CMTimeGetSeconds(self.player.currentTime) >=
    CMTimeGetSeconds(self.player.currentItem.duration)) {
    // Playback reached end
} else if (!self.player.currentItem.playbackLikelyToKeepUp) {
    // Not ready to play, wait until enough data is loaded
}

И не забудьте остановить проигрыватель, когда он достигнет конца:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;

17 голосов
/ 15 ноября 2014

Для Swift :

AVPlayer :

let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
   println("playing")
}

Обновление :
player.rate > 0 условиеизменено на player.rate != 0, потому что если видео воспроизводится в обратном направлении, оно может быть отрицательным, спасибо Julian за указание.
Примечание : Это может выглядеть так же, как и в предыдущем ответе (Maz's), но в Swift '! Player.error' сообщал мне об ошибке компилятора, поэтому вы должны проверить на наличие ошибки, используя 'player.error ==nil 'в Swift. (потому что свойство error не относится к типу Bool)

AVAudioPlayer:

if let theAudioPlayer =  appDelegate.audioPlayer {
   if (theAudioPlayer.playing) {
       // playing
   }
}

AVQueuePlayer:

if let theAudioQueuePlayer =  appDelegate.audioPlayerQueue {
   if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
       // playing
   }
}
9 голосов
/ 05 июля 2016

Быстрое расширение на основе ответа от maz

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}
5 голосов
/ 21 марта 2016

Версия Swift Максконовалова такова:

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)

и

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath == "rate" {
        if let rate = change?[NSKeyValueChangeNewKey] as? Float {
            if rate == 0.0 {
                print("playback stopped")
            }
            if rate == 1.0 {
                print("normal playback")
            }
            if rate == -1.0 {
                print("reverse playback")
            }
        }
    }
}

Спасибо, Максконовалов!

2 голосов
/ 30 апреля 2019

В настоящее время с помощью swift 5 самый простой способ проверить, играет ли игрок или приостановлен, - это проверить переменную .timeControlStatus .

player.timeControlStatus == .paused
player.timeControlStatus == .playing
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...