检查AVPlayer的播放状态

Egi*_*gil 102 iphone objective-c avfoundation ios avplayer

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

maz*_*maz 325

你可以告诉它正在使用:

AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
    // player is playing
}
Run Code Online (Sandbox Code Playgroud)

Swift 3扩展:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不一定,它不处理由于文件中的错误导致播放器停止的情况.我发现了一些困难的方法...... (29认同)
  • 请注意,答案已更新,以防止@Dermot方案.所以这个实际上有效. (22认同)
  • 正如Dermot所说,如果你试图在飞机模式下玩某些东西,AVPlayer速率仍然设置为1.0,因为它意味着打算玩. (7认同)
  • AVPlayer有一个错误属性,只是检查它不是nil以及检查速率不是0 :) (4认同)
  • 播放视频镜头时不会起作用(` - [AVPlayer setRate:-1.0]`),因为`-1.0`小于0. (2认同)

Tod*_*son 58

要获得到达项目结尾的通知(通过Apple):

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

跟踪比赛你可以:

"通过使用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];
}];
Run Code Online (Sandbox Code Playgroud)

  • 还需要通知错误?`AVPlayerItemFailedToPlayToEndTimeNotification` (2认同)

Tra*_* M. 39

在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)
    }
}
Run Code Online (Sandbox Code Playgroud)

至于你的第二个问题,要知道avPlayer是否到达终点,最简单的方法是设置通知.

NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
Run Code Online (Sandbox Code Playgroud)

例如,当它结束时,您可以将其倒回到视频的开头并将"暂停"按钮重置为"播放".

@objc func didPlayToEnd() {
    aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
    btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}
Run Code Online (Sandbox Code Playgroud)

如果您正在创建自己的控件,这些示例很有用,但如果您使用AVPlayerViewController,则内置控件.

  • @objc func didPlayToEnd() 用于 Swift 4.2 (2认同)

kga*_*dis 20

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

该块返回当前播放器的时间CMTime,因此比较lastTime(从块上次收到currentTime的时间)和(刚刚报告的块的时间)将判断播放器是在播放还是停止播放.例如,如果lastTime == currentTimerate != 0.0,则播放器已经停止.

正如其他人所指出的那样,确定回放是否已经完成AVPlayerItemDidPlayToEndTimeNotification.


max*_*lov 18

一个更可靠的替代方案NSNotification是将自己添加为玩家rate财产的观察者.

[self.player addObserver:self
              forKeyPath:@"rate"
                 options:NSKeyValueObservingOptionNew
                 context:NULL];
Run Code Online (Sandbox Code Playgroud)

然后检查观察到的速率的新值是否为零,这意味着由于某种原因播放已停止,例如由于空缓冲区而到达结束或停止.

- (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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例如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
}
Run Code Online (Sandbox Code Playgroud)

并且不要忘记让玩家到达终点时停止:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;


Aks*_*Aks 17

对于Swift:

AVPlayer:

let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
   println("playing")
}
Run Code Online (Sandbox Code Playgroud)

更新:
player.rate > 0条件已更改为player.rate != 0因为如果视频正在反向播放,则感谢Julian指出,这可能是负面的.
注意:这可能与上面(Maz的)答案相同,但是在Swift'中!player.error'给了我一个编译错误,所以你必须在Swift中使用'player.error == nil'检查错误.(因为错误属性不是'Bool'类型)

AVAudioPlayer:

if let theAudioPlayer =  appDelegate.audioPlayer {
   if (theAudioPlayer.playing) {
       // playing
   }
}
Run Code Online (Sandbox Code Playgroud)

AVQueuePlayer:

if let theAudioQueuePlayer =  appDelegate.audioPlayerQueue {
   if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
       // playing
   }
}
Run Code Online (Sandbox Code Playgroud)

  • AVPlayer != AVAudioPlayer (3认同)
  • 注意事项:上面提到的所有答案都出现在这个问题的前两年. (2认同)

Mar*_*ges 9

Swift扩展基于maz的答案

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}
Run Code Online (Sandbox Code Playgroud)


aze*_*emi 7

目前使用 swift 5 检查播放器是否正在播放或暂停的最简单方法是检查.timeControlStatus变量。

player.timeControlStatus == .paused
player.timeControlStatus == .playing
Run Code Online (Sandbox Code Playgroud)


iOS*_*fee 7

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
}
Run Code Online (Sandbox Code Playgroud)


Mr *_*nev 5

Swink版本的maxkonovalov的答案是这样的:

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)
Run Code Online (Sandbox Code Playgroud)

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")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢maxkonovalov!


小智 5

player.timeControlStatus == AVPlayer.TimeControlStatus.playing
Run Code Online (Sandbox Code Playgroud)

  • 提供的答案可能是正确的,但**它可能会受益于解释**。仅代码答案不被视为“好”答案。以下是[如何写出好的答案?](https://stackoverflow.com/help/how-to-answer) 的一些指南。来自[评论](https://stackoverflow.com/review)。 (2认同)