Odpowiedzi:
Aby otrzymać powiadomienie o osiągnięciu końca elementu (przez Apple ):
[[NSNotificationCenter defaultCenter]
addObserver:<self>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];
Aby śledzić odtwarzanie, możesz:
„śledzenia zmian w położeniu wskaźnika odtwarzania na przedmiocie AVPlayer” stosując addPeriodicTimeObserverForInterval: kolejki: usingBlock: lub addBoundaryTimeObserverForTimes: kolejki: usingBlock: .
Przykład pochodzi od 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];
}];
-replaceCurrentItemWithPlayerItem:
, i nie obsłużysz go poprawnie. Bardziej niezawodnym sposobem jest dla mnie śledzenie AVPlayer
statusu za pomocą KVO. Zobacz moją odpowiedź poniżej, aby uzyskać więcej informacji: stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
Możesz powiedzieć, że gra za pomocą:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Rozszerzenie Swift 3:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
), ponieważ -1.0
jest mniejsze niż 0.
W iOS10 dostępna jest teraz wbudowana właściwość: timeControlStatus
Na przykład ta funkcja odtwarza lub wstrzymuje avPlayer na podstawie jego statusu i odpowiednio aktualizuje przycisk odtwarzania / pauzy.
@IBAction func btnPlayPauseTap(_ 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 dobiegł końca, najłatwiej byłoby skonfigurować powiadomienie.
NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
Na przykład, gdy dojdzie do końca, możesz przewinąć go do początku wideo i zresetować przycisk Wstrzymaj do odtwarzania.
@objc 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 AVPlayerViewController, kontrolki są wbudowane.
rate
NIE jest sposobem na sprawdzenie, czy wideo jest odtwarzane (może się zawiesić). Z dokumentacji rate
:
Wskazuje żądaną szybkość odtwarzania; 0,0 oznacza „wstrzymano”, 1,0 oznacza chęć grania w naturalnym tempie bieżącej pozycji.
Słowa kluczowe „chęć zabawy” - stawka 1.0
nie oznacza, że wideo jest odtwarzane.
Rozwiązaniem od iOS 10.0 jest użycie, AVPlayerTimeControlStatus
które można obserwować na AVPlayer
timeControlStatus
właściwości.
Rozwiązaniem wcześniejszym niż iOS 10.0 (9.0, 8.0 itd.) Jest wprowadzenie własnego rozwiązania. Stawka 0.0
oznacza, że wideo jest wstrzymane. Gdy rate != 0.0
oznacza to, że wideo jest odtwarzane lub utknęło.
Możesz poznać różnicę, obserwując czas gracza poprzez: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any
Blok zwraca aktualny czas gracza CMTime
, więc porównanie lastTime
(czasu, który został ostatnio odebrany z bloku) i currentTime
(czasu, w którym właśnie został zgłoszony blok) pokaże, czy gracz gra, czy jest zatrzymany. Na przykład, jeśli lastTime == currentTime
i rate != 0.0
, to gracz utknął w martwym punkcie.
Jak zauważyli inni, ustalenie, czy odtwarzanie zostało zakończone, jest oznaczone ikoną AVPlayerItemDidPlayToEndTimeNotification
.
Bardziej niezawodną alternatywą NSNotification
jest dodanie siebie jako obserwatora do rate
własności gracza .
[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 do końca lub zatrzymania 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
}
}
}
Na rate == 0.0
przykład, aby wiedzieć, co dokładnie spowodowało zatrzymanie odtwarzania, możesz wykonać następujące czynności:
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 zatrzymać odtwarzacza, gdy dotrze do końca:
self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;
AVPlayerItemFailedToPlayToEndTimeNotification
. Jeśli wystąpi ten błąd, nigdy nie dotrze do czasu zakończenia. Lub czytając odpowiedź maz, dodaj do swojego kodu czek player.error != nil
, w którym to przypadku odtwarzanie „zakończyło się” z powodu błędu.
AVPlayerItemDidPlayToEndTimeNotification
?
Dla Swift :
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
stan zmieniony na, player.rate != 0
ponieważ jeśli wideo jest odtwarzane w odwrotnej kolejności, może to być negatywne dzięki Julianowi za wskazanie.
Uwaga : To może wyglądać tak samo, jak powyższa odpowiedź (Maz), ale w języku Swift '! Player.error' dawał mi błąd kompilatora, więc musisz sprawdzić błąd za pomocą 'player.error == nil' w Swift. (Ponieważ właściwość błędu nie jest typu „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
}
}
player.rate = -1.0
), ponieważ -1.0 jest mniejsze niż 0.
Szybkie rozszerzenie na podstawie odpowiedzi maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
Szybka wersja odpowiedzi maxkonovalova jest następująca:
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!
nil
! Ale muszę wiedzieć, kiedy widok się zaczyna (a nie kończy). Jakiś sposób to zrobić?
Odpowiedź brzmi: Cel C.
if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
//player is playing
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusPaused) {
//player is pause
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate) {
//player is waiting to play
}
player.timeControlStatus == AVPlayer.TimeControlStatus.playing