有没有办法知道AVPlayer
播放是否已停止或已结束?
11 回答
你可以告诉它正在使用:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
斯威夫特 3 扩展:
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,则控件是内置的。
要获得到达项目末尾的通知(通过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];
}];
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
块返回当前玩家时间 in CMTime
,因此lastTime
(最后从块接收的时间)和currentTime
(块刚刚报告的时间)的比较将判断玩家是在玩还是被停止。例如,如果lastTime == currentTime
和rate != 0.0
,则玩家已停止。
正如其他人所指出的,确定播放是否已完成由 指示AVPlayerItemDidPlayToEndTimeNotification
。
对于斯威夫特:
影音播放器:
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指出,它可能是负面的。
注意:这可能看起来与上面(Maz 的)答案相同,但在 Swift 中'!player.error'给了我一个编译器错误,所以你必须在 Swift 中使用'player.error == nil'来检查错误。(因为错误属性不是“布尔”类型)
AV音频播放器:
if let theAudioPlayer = appDelegate.audioPlayer {
if (theAudioPlayer.playing) {
// playing
}
}
AV队列播放器:
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];
然后检查观察速率的新值是否为零,这意味着播放已因某种原因停止,例如到达结尾或由于空缓冲区而停止。
- (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;
基于maz答案的Swift扩展
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
目前使用 swift 5 检查播放器是否正在播放或暂停的最简单方法是检查.timeControlStatus变量。
player.timeControlStatus == .paused
player.timeControlStatus == .playing
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")
}
}
}
}
谢谢马克斯科诺瓦洛夫!
答案是目标 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