查看AVPlayer的播放状态

问题描述:

有没有办法知道AVPlayer播放是否停止播放或到达末尾?查看AVPlayer的播放状态

为了得到通知到达一个项目的结束(通过Apple):

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

,并跟踪播放,您可以:

“在播放头的位置跟踪变化在AVPlayer对象“通过使用addPeriodicTimeObserverForInterval:队列:usingBlock:addBoundaryTimeObserverForTimes:队列:usingBlock:

例子与苹果:

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

您可以使用布尔标志来检查播放状态。 – moonman239 2015-06-19 23:01:59

+0

通知可能会导致问题,例如,如果使用'-replaceCurrentItemWithPlayerItem:'更改玩家的项目,并且不正确处理它。对我而言,更可靠的方法是使用KVO跟踪“AVPlayer”的状态。有关更多详细信息,请参阅下面的答案:http://stackoverflow.com/a/34321993/3160561 – maxkonovalov 2015-12-16 21:04:43

+1

还需要通知错误? 'AVPlayerItemFailedToPlayToEndTimeNotification' – ToolmakerSteve 2016-02-05 17:32:18

你可以告诉它的演奏使用:

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

斯威夫特3扩展:

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

完美地工作!大! – rockstarberlin 2012-11-14 04:30:00

+25

不一定,它不处理由于文件错误导致播放器停顿的情况。我发现了一些困难的方法...... – Dermot 2013-05-07 12:53:11

+5

正如Dermot所说,如果您尝试在飞行模式下播放某些内容,则AVPlayer速率仍然设置为1.0,因为它意味着要玩。 – phi 2013-05-31 13:13:58

对于斯威夫特

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's)的答案相同,但是在Swift'!player.error'给我一个编译器错误,所以你必须在Swift中使用'player.error == nil'来检查错误。 (因为错误属性不是 '布尔' 型)

AVAudioPlayer:

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

AVQueuePlayer:

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

AVPlayer!= AVAudioPlayer – quemeful 2015-01-27 12:44:19

+2

注意事项:所有上述问题在前两年出现在答案中。 – 2015-02-18 03:23:16

+1

@Yar我也知道upvoted上面的答案,但这是迅速和在斯威夫特'!player.error'不适合我只允许bool类型,所以我添加了答案oops upvoted你的评论错误地给予回复使用这个堆栈溢出应用程序:) – Aks 2015-02-18 03:43:19

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;

+0

我认为还需要通知失败达到结束 - 'AVPlayerItemFailedToPlayToEndTimeNotification'。如果发生这种错误,将永远不会达到结束时间。或者阅读maz的回答,在你的代码中添加一个'player.error!= nil'的检查,在这种情况下,播放由于错误而“结束”。 – ToolmakerSteve 2016-02-05 17:15:37

+0

顺便说一句,你发现什么“使用NSNotification”AVPlayerItemDidPlayToEndTimeNotification“不可靠”? – ToolmakerSteve 2016-02-05 17:31:05

+0

ToolmakerSteve,感谢您的留言,在我的回答中添加了错误检查。 对于不可靠的通知 - 我在收集视图中实现重复和可重复使用的播放器视图时遇到了这个问题,而KVO使事情更加清晰,因为它允许将更多的本地信息保留在本地,而不会有不同玩家的通知互相干扰。 – maxkonovalov 2016-02-08 16:05:38

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!通过MAZ

extension AVPlayer { 

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

您好Stanev先生,谢谢您的回答。这对我不起作用(又名不在控制台中打印任何东西?) – Cesare 2017-08-21 12:51:06

+0

没关系,它确实有效 - 我的播放器是'无'!但是我需要知道视图何时开始(而不是结束)。任何方式来做到这一点? – Cesare 2017-08-21 12:53:26

斯威夫特延伸,有一个内置的属性现在这样:timeControlStatus

例如,该功能播放或avPlayer基于暂停它是状态并适当地更新播放/暂停按钮。

@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达到了目的,这样做将是建立一个通知最容易的事情。

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

当它结束时,例如,您可以让它倒回到视频的开头,并将暂停按钮重置为播放。如果您要创建自己的控件

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

这些例子是有用的,但如果你使用一个AVPlayerViewController,那么控制进来内置的。

基础上,答案在iOS10

+0

易于使用的iOS 10+ – technerd 2017-05-30 08:56:34

+0

像更新的回答为iOS10 – 2017-09-08 09:48:26

rate的方法来检查是否视频是(它可能会停滞)。来自rate的文档:

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

关键词“欲打” - 1.0率并不意味着视频播放。

从iOS 10.0开始的解决方案是使用AVPlayerTimeControlStatus,它可以在AVPlayertimeControlStatus属性上观察到。

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 == currentTimerate != 0.0,那么播放器已经停顿。

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