112

有没有办法知道AVPlayer播放是否已停止或已结束?

4

11 回答 11

345

你可以告诉它正在使用:

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

斯威夫特 3 扩展:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
于 2012-02-15T06:05:58.107 回答
61

在 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,则控件是内置的。

于 2016-12-13T15:43:23.110 回答
58

要获得到达项目末尾的通知(通过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];
}];
于 2011-04-13T23:03:33.160 回答
23

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 == currentTimerate != 0.0,则玩家已停止。

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

于 2017-04-27T20:59:13.440 回答
18

对于斯威夫特

影音播放器

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
   }
}
于 2014-11-15T07:32:48.147 回答
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;

于 2015-12-16T20:59:09.123 回答
9

基于maz答案的Swift扩展

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}
于 2016-07-05T12:23:08.083 回答
7

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

player.timeControlStatus == .paused
player.timeControlStatus == .playing
于 2019-04-30T06:35:16.333 回答
6

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")
            }
        }
    }
}

谢谢马克斯科诺瓦洛夫!

于 2016-03-21T19:40:29.953 回答
2

答案是目标 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
}
于 2019-08-07T09:19:32.033 回答
2
player.timeControlStatus == AVPlayer.TimeControlStatus.playing
于 2019-09-28T19:23:53.947 回答