有没有办法知道 AVPlayer
的播放是否停顿或已经结束?
您可以使用以下方法判断是否正在播放:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Swift 3扩展:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
@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,则内置了控件。
要接收在项目结束时的通知(来自Apple):
[[NSNotificationCenter defaultCenter]
addObserver:<self>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];
要跟踪播放进度,您可以使用 addPeriodicTimeObserverForInterval:queue:usingBlock: 或 addBoundaryTimeObserverForTimes:queue: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];
}];
-replaceCurrentItemWithPlayerItem:
更改播放器的项目,但未正确处理通知,则可能会导致问题。对我而言,一种更可靠的方法是使用KVO跟踪AVPlayer
的状态。有关更多详细信息,请参见下面的答案:https://dev59.com/c2035IYBdhLWcg3wC7if#34321993 - maxkonovalovAVPlayerItemFailedToPlayToEndTimeNotification
- ToolmakerSteverate
不是检测视频是否正在播放的方法(它可能会停顿)。从 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
。[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
添加到您的代码中,在这种情况下,由于错误而“结束”播放。 - ToolmakerSteveAVPlayerItemDidPlayToEndTimeNotification
зљ„NSNotificationдёЌеЏЇйќ ењЁе“Єй‡Њпјџ - ToolmakerSteve对于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
,因为视频正在倒播时可以为负数,感谢 Julian 指出。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。 - Julian F. Weinert目前使用 Swift 5,最简单的检查播放器是否正在播放或暂停的方法是检查 .timeControlStatus 变量。
player.timeControlStatus == .paused
player.timeControlStatus == .playing
基于maz的答案的Swift扩展
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
用Objective 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
}
maxkonovalov的答案的Swift版本如下:
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!
nil
!但我需要知道视图何时开始(而不是结束)。有什么办法吗? - Cesare