检查AVPlayer的播放状态

时间:2011-04-13 21:26:51

标签: ios objective-c iphone avfoundation avplayer

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

11 个答案:

答案 0 :(得分:314)

你可以告诉它正在使用:

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

Swift 3扩展名:

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

答案 1 :(得分:56)

要获取到达项目末尾的通知(通过Apple):

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

要跟踪比赛,你可以:

“跟踪AVPlayer对象中播放头位置的变化”,方法是使用 addPeriodicTimeObserverForInterval:queue:usingBlock: addBoundaryTimeObserverForTimes:queue:usingBlock:

示例来自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];
}];

答案 2 :(得分:34)

在iOS10中,现在有一个内置属性: 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)

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

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

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

答案 3 :(得分:18)

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;

答案 4 :(得分:17)

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 指出,它可能是否定的。
注意:这可能与上面(Maz&#39; s)的答案相同,但在Swift&#39;!player.error&#39;给了我一个编译错误所以你必须使用&#39; player.error == nil&#39;来检查错误。在Swift中。(因为错误属性不是&#39; Bool&#39;类型)

AVAudioPlayer:

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

AVQueuePlayer:

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

答案 5 :(得分:17)

rate 检查视频是否正在播放(它可能会停滞)。来自rate的文档:

  

表示所需的播放速度; 0.0表示&#34;暂停&#34;,1.0表示希望以当前项目的自然速率播放。

关键词&#34;渴望游戏&#34; - 费率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表示确定回放是否已完成。

答案 6 :(得分:9)

根据maz的回答进行Swift扩展

extension AVPlayer {

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

答案 7 :(得分:5)

swink版本的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!

答案 8 :(得分:1)

当前使用swift 5来检查播放器是播放还是暂停的最简单方法是检查 .timeControlStatus 变量。

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

答案 9 :(得分:0)

  

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

答案 10 :(得分:0)

player.timeControlStatus == AVPlayer.TimeControlStatus.playing