ios 检查 AVPlayer 的播放状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5655864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:34:21  来源:igfitidea点击:

Check play state of AVPlayer

iosobjective-ciphoneavfoundationavplayer

提问by Egil

Is there a way to know whether an AVPlayerplayback has stalled or reached the end?

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

采纳答案by Todd Hopkinson

To get notification for reaching the end of an item (via Apple):

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

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

And to track playing you can:

要跟踪播放,您可以:

"track changes in the position of the playhead in an AVPlayer object" by using addPeriodicTimeObserverForInterval:queue:usingBlock:or addBoundaryTimeObserverForTimes:queue:usingBlock:.

通过使用addPeriodicTimeObserverForInterval:queue:usingBlock:addBoundaryTimeObserverForTimes:queue:usingBlock: 来“跟踪 AVPlayer 对象中播放头位置的变化” 。

Example is from 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];
}];

回答by maz

You can tell it's playing using:

您可以使用以下命令判断它正在播放:

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

Swift 3 extension:

斯威夫特 3 扩展:

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

回答by Travis M.

In iOS10, there's a built in property for this now: timeControlStatus

在 iOS10 中,现在有一个内置属性:timeControlStatus

For example, this function plays or pauses the avPlayer based on it's status and updates the play/pause button appropriately.

例如,此函数根据 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)
    }
}

As for your second question, to know if the avPlayer reached the end, the easiest thing to do would be to set up a notification.

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

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

When it gets to the end, for example, you can have it rewind to the beginning of the video and reset the Pause button to Play.

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

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

These examples are useful if you're creating your own controls, but if you use a AVPlayerViewController, then the controls come built in.

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

回答by kgaidis

rateis NOTthe way to check whether a video is playing(it could stalled). From documentation of rate:

rate不是要检查视频是否是这样(这可能停滞不前)。从文档rate

Indicates the desired rate of playback; 0.0 means "paused", 1.0 indicates a desire to play at the natural rate of the current item.

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

Key words "desire to play" - a rate of 1.0does not mean the video is playing.

关键词“播放欲望”——速率为1.0并不意味着视频正在播放。

The solution since iOS 10.0 is to use AVPlayerTimeControlStatuswhich can be observed on AVPlayertimeControlStatusproperty.

自 iOS 10.0 以来的解决方案是使用AVPlayerTimeControlStatus可以在AVPlayertimeControlStatus属性上观察到的。

The solution prior to iOS 10.0 (9.0, 8.0 etc.) is to roll your own solution. A rate of 0.0means that the video is paused. When rate != 0.0it means that the video is either playing oris stalled.

iOS 10.0(9.0、8.0 等)之前的解决方案是推出您自己的解决方案。速率0.0表示视频已暂停。当rate != 0.0这意味着视频正在播放停止时。

You can find out the difference by observing player time via: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

您可以通过以下方式观察玩家时间来找出差异: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

The block returns the current player time in CMTime, so a comparison of lastTime(the time that was last received from the block) and currentTime(the time that the block just reported) will tell whether the player is playing or is stalled. For example, if lastTime == currentTimeand rate != 0.0, then the player has stalled.

块在 中返回当前玩家时间CMTime,因此比较lastTime(上次从块接收currentTime的时间)和(块刚刚报告的时间)将判断玩家是在玩游戏还是停顿。例如,如果lastTime == currentTimerate != 0.0,则播放器已停止。

As noted by others, figuring out whether playback has finished is indicated by AVPlayerItemDidPlayToEndTimeNotification.

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

回答by maxkonovalov

A more reliable alternative to NSNotificationis to add yourself as observer to player's rateproperty.

一个更可靠的替代方法NSNotification是将自己作为观察者添加到玩家的rate财产中。

[self.player addObserver:self
              forKeyPath:@"rate"
                 options:NSKeyValueObservingOptionNew
                 context:NULL];

Then check if the new value for observed rate is zero, which means that playback has stopped for some reason, like reaching the end or stalling because of empty buffer.

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

- (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
        }
    }
}

For rate == 0.0case, to know what exactly caused the playback to stop, you can do the following checks:

例如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
}

And don't forget to make your player stop when it reaches the end:

并且不要忘记让您的播放器在播放结束时停止:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;

回答by Aks

For Swift:

对于斯威夫特

AVPlayer:

AV播放器

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

Update:
player.rate > 0condition changed to player.rate != 0because if video is playing in reverse it can be negative thanks to Julianfor pointing out.
Note: This might look same as above(Maz's) answer but in Swift '!player.error' was giving me a compiler error so you have to check for error using 'player.error == nil' in Swift.(because error property is not of 'Bool' type)

更新
player.rate > 0条件更改为,player.rate != 0因为如果视频反向播放,由于Julian的指出,它可能是负面的。
注意:这可能与上面(Maz 的)答案相同,但在 Swift 中,'!player.error' 给了我一个编译器错误,因此您必须在 Swift 中使用 'player.error == nil' 检查错误。(因为错误属性不是“布尔”类型)

AVAudioPlayer:

AV音频播放器:

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

AVQueuePlayer:

AV队列播放器:

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

回答by Mark Bridges

Swift extension based on the answer by maz

基于 maz 的答案的 Swift 扩展

extension AVPlayer {

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

回答by Mr Stanev

The Swift version of maxkonovalov's answer is this:

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

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)

and

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

Thank you maxkonovalov!

谢谢马克科诺瓦洛夫!

回答by azemi

Currently with swift 5 the easiest way to check if the player is playing or paused is to check the .timeControlStatusvariable.

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

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

回答by iOS Lifee

Answer is Objective C

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