Antworten:
So erhalten Sie eine Benachrichtigung zum Erreichen des Endes eines Artikels (über Apple ):
[[NSNotificationCenter defaultCenter]
addObserver:<self>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];
Und um das Spielen zu verfolgen, können Sie:
"Verfolgen Sie Änderungen an der Position des Abspielkopfs in einem AVPlayer-Objekt" mithilfe von addPeriodicTimeObserverForInterval: queue: usingBlock: oder addBoundaryTimeObserverForTimes: queue: usingBlock : .
Beispiel ist von 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:
, und ihn nicht richtig handhaben. Eine zuverlässigere Möglichkeit für mich ist es AVPlayer
, den Status mithilfe von KVO zu verfolgen . Siehe meine Antwort unten für weitere Details: stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
Sie können sagen, dass es spielt mit:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Swift 3-Erweiterung:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
), da -1.0
es kleiner als 0 ist.
In iOS10 gibt es dafür jetzt eine integrierte Eigenschaft: timeControlStatus
Diese Funktion spielt beispielsweise den avPlayer basierend auf seinem Status ab oder hält ihn an und aktualisiert die Wiedergabe- / Pause-Taste entsprechend.
@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)
}
}
Was Ihre zweite Frage betrifft, um zu wissen, ob der avPlayer das Ende erreicht hat, ist es am einfachsten, eine Benachrichtigung einzurichten.
NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
Wenn es zum Beispiel zu Ende ist, können Sie es zum Anfang des Videos zurückspulen lassen und die Pause-Taste auf Wiedergabe zurücksetzen.
@objc func didPlayToEnd() {
aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}
Diese Beispiele sind nützlich, wenn Sie Ihre eigenen Steuerelemente erstellen. Wenn Sie jedoch einen AVPlayerViewController verwenden, sind die Steuerelemente integriert.
rate
Auf diese Weise können Sie NICHT überprüfen, ob ein Video abgespielt wird (es könnte ins Stocken geraten). Aus der Dokumentation von rate
:
Zeigt die gewünschte Wiedergabegeschwindigkeit an; 0.0 bedeutet "pausiert", 1.0 zeigt den Wunsch an, mit der natürlichen Rate des aktuellen Gegenstands zu spielen.
Schlüsselwörter "Wunsch zu spielen" - eine Rate von 1.0
bedeutet nicht, dass das Video abgespielt wird.
Die Lösung seit iOS 10.0 ist die Verwendung, AVPlayerTimeControlStatus
die auf dem AVPlayer
timeControlStatus
Grundstück beobachtet werden kann .
Die Lösung vor iOS 10.0 (9.0, 8.0 usw.) besteht darin, eine eigene Lösung zu erstellen. Eine Rate von 0.0
bedeutet, dass das Video angehalten wird. Wenn rate != 0.0
dies bedeutet, dass das Video entweder abgespielt wird oder blockiert ist.
Sie können den Unterschied herausfinden, indem Sie die Spielerzeit beobachten über: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any
Der Block gibt die aktuelle Spielerzeit in zurück CMTime
, sodass ein Vergleich von lastTime
(der Zeit, die zuletzt vom Block empfangen wurde) und currentTime
(der Zeit, die der Block gerade gemeldet hat) zeigt, ob der Spieler spielt oder blockiert ist. Wenn zum Beispiel lastTime == currentTime
und rate != 0.0
, dann ist der Spieler ins Stocken geraten.
Wie von anderen angemerkt, wird durch angezeigt, ob die Wiedergabe beendet ist AVPlayerItemDidPlayToEndTimeNotification
.
Eine zuverlässigere Alternative dazu NSNotification
besteht darin, sich als Beobachter zum rate
Eigentum des Spielers hinzuzufügen .
[self.player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew
context:NULL];
Überprüfen Sie dann, ob der neue Wert für die beobachtete Rate Null ist. Dies bedeutet, dass die Wiedergabe aus irgendeinem Grund gestoppt wurde, z. B. zum Erreichen des Endes oder zum Stillstand aufgrund eines leeren Puffers.
- (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
}
}
}
Um rate == 0.0
genau zu wissen, warum die Wiedergabe gestoppt wurde, können Sie die folgenden Überprüfungen durchführen:
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
}
Und vergessen Sie nicht, Ihren Spieler anzuhalten, wenn er das Ende erreicht:
self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;
AVPlayerItemFailedToPlayToEndTimeNotification
. Wenn dieser Fehler auftritt, wird die Endzeit nie erreicht. Oder lesen Sie die Antwort von maz und fügen Sie Ihrem Code eine Prüfung hinzu player.error != nil
. In diesem Fall wurde die Wiedergabe aufgrund eines Fehlers "beendet".
AVPlayerItemDidPlayToEndTimeNotification
?
Für Swift :
AVPlayer :
let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
println("playing")
}
Update :
player.rate > 0
Bedingung geändert in, player.rate != 0
da wenn Video in umgekehrter Reihenfolge abgespielt wird, es dank Julian für den Hinweis negativ sein kann.
Hinweis : Dies könnte wie die obige Antwort von (Maz) aussehen, aber in Swift gab '! Player.error' einen Compilerfehler aus, sodass Sie in Swift mit 'player.error == nil' nach Fehlern suchen müssen (wegen der Fehlereigenschaft) ist nicht vom Typ '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
), da -1,0 kleiner als 0 ist.
Schnelle Erweiterung basierend auf der Antwort von Maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
Die Swift-Version von maxkonovalovs Antwort lautet:
player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)
und
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")
}
}
}
}
Vielen Dank, dass Sie maxkonovalov!
nil
! Aber ich muss wissen, wann die Ansicht beginnt (nicht endet). Wie geht das?
Antwort ist Ziel 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