Ответы:
Чтобы получить уведомление о достижении конца элемента (через 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];
}];
-replaceCurrentItemWithPlayerItem:
, и не обработаете его должным образом. Для меня более надежный способ - отслеживать AVPlayer
статус с помощью KVO. Подробнее см. Мой ответ ниже: stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
Вы можете сказать, что он играет, используя:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Расширение Swift 3:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
), потому что -1.0
оно меньше 0.
В iOS10 для этого теперь есть встроенное свойство: timeControlStatus
Например, эта функция воспроизводит или приостанавливает avPlayer в зависимости от его статуса и соответствующим образом обновляет кнопку воспроизведения / паузы.
@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)
}
}
Что касается вашего второго вопроса, чтобы узнать, достиг ли 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, элементы управления будут встроены.
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
.
Более надежная альтернатива NSNotification
- добавить себя в качестве наблюдателя к rate
собственности игрока .
[self.player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew
context:NULL];
Затем проверьте, равно ли новое значение наблюдаемой скорости нулю, что означает, что воспроизведение остановлено по какой-то причине, например, по достижении конца или остановке из-за пустого буфера.
- (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
}
}
}
На 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;
AVPlayerItemFailedToPlayToEndTimeNotification
. Если эта ошибка произойдет, никогда не дойдет до конца времени. Или, прочитав ответ maz, добавьте в свой код проверку player.error != nil
, и в этом случае воспроизведение "закончилось" из-за ошибки.
AVPlayerItemDidPlayToEndTimeNotification
?
Для 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
потому что, если видео воспроизводится в обратном направлении, оно может быть отрицательным, спасибо Джулиану за указание.
Примечание : это может выглядеть так же, как и ответ выше (Maz), но в 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
}
}
player.rate = -1.0
), потому что -1,0 меньше 0.
Расширение Swift на основе ответа maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
Swift-версия ответа maxkonovalov такова:
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")
}
}
}
}
Спасибо максконовалов!
nil
! Но мне нужно знать, когда просмотр начинается (а не заканчивается). Как это сделать?
Ответ: цель 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