Sprawdź stan odtwarzania AVPlayer

Czy istnieje sposób, aby dowiedzieć się, czy odtwarzanie AVPlayer zatrzymało się, czy dotarło do końca?

Author: hariszaman, 2011-04-14

8 answers

Aby otrzymać powiadomienie o dotarciu do końca artykułu (przez Apple):

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

A do śledzenia gry Można:

"Śledź zmiany położenia głowicy odtwarzania w obiekcie AVPlayer" za pomocą addPeriodicTimeObserverForInterval:queue:usingBlock: lub addBoundaryTimeObserverForTimes:queue:usingBlock:.

Przykład pochodzi z 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];
}];
 54
Author: Todd Hopkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-13 23:03:33

Możesz powiedzieć, że gra używając:

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

Swift 3 extension:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
 303
Author: maz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-02 11:34:29

W iOS10 jest teraz wbudowana właściwość: timeControlStatus

Na przykład ta funkcja odtwarza lub wstrzymuje avplayera w zależności od jego statusu i odpowiednio aktualizuje przycisk odtwarzania / pauzy.

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

Jeśli chodzi o drugie pytanie, aby wiedzieć, czy avPlayer dotarł do końca, najprostszą rzeczą do zrobienia byłoby skonfigurowanie powiadomienia.

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

Kiedy dotrze do końca, na przykład, możesz cofnąć go do początku wideo i zresetować Przycisk pauzy do gry.

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

Te przykłady są przydatne, jeśli tworzysz własne kontrolki, ale jeśli używasz kontrolki AVPlayerViewController, to kontrolki są wbudowane.

 25
Author: Travis M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-23 15:20:36

Bardziej niezawodną alternatywą dla NSNotification jest dodanie siebie jako obserwatora do właściwości gracza rate.

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

Następnie sprawdź, czy nowa wartość obserwowanej szybkości wynosi zero, co oznacza, że odtwarzanie zostało zatrzymane z jakiegoś powodu, na przykład dotarcie do końca lub opóźnienie z powodu pustego bufora.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"rate"]) {
        float rate = [change[NSKeyValueChangeNewKey] floatValue];
        if (rate == 0.0) {
            // Playback stopped
        } else if (rate == 1.0) {
            // Normal playback
        } else if (rate == -1.0) {
            // Reverse playback
        }
    }
}

W przypadku rate == 0.0, aby dowiedzieć się, co dokładnie spowodowało zatrzymanie odtwarzania, możesz wykonać następujące kontrole:

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
}

I nie zapomnij, aby twój gracz zatrzymał się, gdy dotrze do end:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;

 17
Author: maxkonovalov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-08 14:54:02

Dla :

AVPlayer :

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

Aktualizacja:
player.rate > 0 warunek zmieniony na player.rate != 0, ponieważ jeśli film jest odtwarzany w odwrotnej kolejności, to może być ujemny dzięki Julianowi za wskazanie.
Uwaga: to może wyglądać tak samo jak powyżej(Maz) odpowiedź, ale w Swift '!gracz.error 'dawał mi błąd kompilatora, więc musisz sprawdzić błąd za pomocą' player.error = = nil' in Swift.(ponieważ właściwość error nie jest 'Bool' typ)

AVAudioPlayer:

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

AVQueuePlayer:

if let theAudioQueuePlayer =  appDelegate.audioPlayerQueue {
   if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
       // playing
   }
}
 16
Author: Aks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-24 06:35:02

rate czy Nie jest sposobem sprawdzenia, czy film jest odtwarzany (może zostać zablokowany). Z dokumentacji rate:

Wskazuje pożądaną szybkość odtwarzania; 0.0 oznacza "wstrzymane", 1.0 oznacza chęć odtwarzania z naturalną szybkością bieżącego elementu.

Słowa kluczowe "chęć gry" - szybkość 1.0 nie oznacza, że wideo jest odtwarzane.

Rozwiązaniem od iOS 10.0 jest użycie AVPlayerTimeControlStatus, które można zaobserwować na AVPlayer timeControlStatus własność.

Rozwiązanie przed iOS 10.0 (9.0, 8.0 itd.) jest zrolowanie własnego rozwiązania. szybkość 0.0 oznacza, że film jest wstrzymywany. Gdy rate != 0.0 oznacza to, że wideo jest odtwarzane lub jest zablokowane.

Możesz sprawdzić różnicę obserwując czas gracza poprzez: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

Blok zwraca bieżący czas gracza w CMTime, więc porównanie lastTime (czasu, który został ostatnio odebrany z bloku) i currentTime (czasu, który blok tylko zgłoszone) powie, czy gracz gra lub jest zablokowany. Na przykład, jeśli lastTime == currentTime i rate != 0.0, to gracz stoi w miejscu.

Jak zauważyli inni, sprawdzenie, czy odtwarzanie zostało zakończone, wskazuje AVPlayerItemDidPlayToEndTimeNotification.

 14
Author: kgaidis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-18 15:40:47

Rozszerzenie Swift na podstawie odpowiedzi maz

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}
 9
Author: Mark Bridges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-05 12:23:08

Szybka wersja odpowiedzi maxkonovalova jest taka:

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

I

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

Dziękuję maxkonovalov!

 5
Author: Mr Stanev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-21 19:40:29