检查 AVPlayer 的播放状态

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

118138 次浏览

To get notification for reaching the end of an item (via Apple):

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

为了追踪播放,你可以:

使用 队列: usingBlock:队列: usingBlock:“跟踪 AVPlayer 对象中播放头位置的变化”。

苹果的例子是:

// 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];
}];

You can tell it's playing using:

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

迅捷3扩展:

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

对于 斯威夫特:

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 中!Error’给了我一个编译器错误,所以你必须在 Swift 中使用‘ player.error = = nil’来检查错误。(因为错误属性不是‘ 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
}
}

一个更可靠的替代 NSNotification是添加自己作为观察员的球员的 rate属性。

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

Then check if the new value for observed rate is zero, which means that playback has stopped for some reason, like reaching the end or stalling because of empty buffer.

- (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;

麦克科诺瓦洛夫的回答是:

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!

根据 maz 的答案快速扩展

extension AVPlayer {


var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}

在 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没有检查视频是否是 玩耍的方法(它可能会停止):

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

关键词“欲望玩”-1.0的速率并不意味着视频正在播放。

The solution since iOS 10.0 is to use AVPlayerTimeControlStatus which can be observed on AVPlayer timeControlStatus property.

在 iOS 10.0(9.0,8.0等)之前的解决方案是推出您自己的解决方案

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

块返回当前玩家的时间在 CMTime,所以比较 lastTime(时间是最后一次收到块)和 currentTime(时间块刚刚报告)将告诉球员是否正在玩或停滞。例如,如果 lastTime == currentTimerate != 0.0,那么球员已经停滞。

正如其他人所指出的那样,AVPlayerItemDidPlayToEndTimeNotification指出播放是否已经结束。

目前快速5最简单的方法来检查如果球员正在播放或暂停是检查 .timeControlStatus变量。

player.timeControlStatus == .paused
player.timeControlStatus == .playing

答案目标 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