首页 文章

检查AVPlayer的播放状态

提问于
浏览 735
96

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

8 回答

  • 306

    一个更可靠的替代 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;

  • 54

    基于maz的答案的Swift扩展

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

    你可以告诉它正在使用:

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

    Swift 3扩展:

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

    对于 Swift

    AVPlayer:

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

    Update
    player.rate > 0 条件已更改为 player.rate != 0 ,因为如果视频正在反向播放,则由于Julian指出,它可能是负面的 .
    Note :这可能与上面相同(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'类型)

    AVAudioPlayer:

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

    AVQueuePlayer:

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

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

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

    跟踪比赛你可以:

    "track changes in the position of the playhead in an AVPlayer object"使用 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];
    }];
    
  • 15

    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!

  • 9

    在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)
    

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

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

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

  • 5

    rateNOT 检查视频是否正在播放的方式(它可能会停止) . 来自 rate 的文档:

    表示所需的播放速率; 0.0表示“暂停”,1.0表示希望以当前项目的自然速率进行游戏 .

    关键词"desire to play" - a rate of 1.0 does not mean the video is playing.

    iOS 10.0以来的解决方案是使用 AVPlayerTimeControlStatus ,可以在 AVPlayer timeControlStatus 属性上观察到 .

    iOS 10.0(9.0,8.0等)之前的解决方案是推出自己的解决方案 . A rate of 0.0 means that the video is paused. When rate != 0.0 it means that the video is either playing or is stalled.

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

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

    如其他人所述, AVPlayerItemDidPlayToEndTimeNotification 表示确定回放是否已完成 .

相关问题