检查AVPlayer的播放状态

有没有办法知道AVPlayer播放是否已经停止或到达最后?

要获得通知(通过苹果 )到达一个项目的结尾:

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

并跟踪播放,你可以:

“通过使用addPeriodicTimeObserverForInterval:queue:usingBlock:addBoundaryTimeObserverForTimes:queue:usingBlock: ”跟踪AVPlayer对象中播放头位置的变化“。

例子来自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]; }]; 

你可以用它来告诉它正在播放:

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

斯威夫特3延伸:

 extension AVPlayer { var isPlaying: Bool { return rate != 0 && error == nil } } 

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;

对于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因为如果video正在反向播放,可能是负面的感谢Julian指出。
注意 :这可能与上面(Maz's)的答案相同,但在Swift中,“player.error”给我一个编译器错误,所以你必须在Swift中使用'player.error == nil'来检查错误(因为error属性不是'布尔'型)

AVAudioPlayer:

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

AVQueuePlayer:

 if let theAudioQueuePlayer = appDelegate.audioPlayerQueue { if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) { // playing } } 

在iOS10中,现在有一个内置的属性: timeControlStatus

例如,此function根据播放状态播放或暂停播放器,并适当地更新播放/暂停button。

 @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是否到达最后,最简单的事情就是build立一个通知。

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

例如,当它到达最后时,您可以将其倒回到video的开头,并将暂停button重置为播放。

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

这些示例在创build自己的控件时非常有用,但是如果使用AVPlayerViewController,则内置控件。

快速扩展基于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") } } } } 

谢谢maxkonovalov!

rate 不是检查video是否正在播放的方式 (可能会停顿)。 从rate文件:

指示所需的播放速度; 0.0表示“暂停”,1.0表示希望以当前项目的自然速度播放。

关键词“玩的欲望” – 1.0的速度并不意味着video正在播放。

iOS 10.0中的解决scheme是使用AVPlayerTimeControlStatus ,它可以在AVPlayer timeControlStatus属性上观察到。

iOS 10.0(9.0,8.0等)之前的解决scheme是推出自己的解决scheme。 0.0意味着video暂停。 rate != 0.0 ,表示video正在播放停顿。

你可以通过观察玩家的时间来find差异: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

该块返回CMTime的当前玩家时间,因此比较lastTime (上一次从该块获得的时间)和currentTime (该块刚刚报告的时间)将会告诉玩家是否在玩或停止。 例如,如果lastTime == currentTimerate != 0.0 ,则播放器已经停顿。

正如其他人所指出的,确定播放是否完成由AVPlayerItemDidPlayToEndTimeNotification指示。