检测AVPlayer播放的时间

时间:2016-07-15 04:10:34

标签: ios avplayer

如何检测AVPlayer何时正在播放?调用play()函数和实际播放视频之间似乎有一点延迟。

4 个答案:

答案 0 :(得分:7)

视频

AVPlayer有一个名为rate (Float)的参数,如果rate大于0.0,则会显示当前播放的视频。

您可以查看rate是否!=0 :(如果玩家倒退,费率可能为负数)

if vidPlayer != nil && vidPlayer.rate != 0 {
  println("playing")
}

AVPlayer class reference

答案 1 :(得分:7)

据我所知,我同意你的看法,调用play()功能和实际播放视频之间会有一点延迟(换句话说,视频的第一帧有时间)已被渲染)。延迟取决于一些标准,如视频类型(视频点播或直播),网络条件......但幸运的是,我们能够知道视频的第一帧渲染时,我的意思是视频实际播放的时间

通过观察当前status的{​​{1}}以及AVPlayerItem时,它应该是已渲染的第一帧。

AVPlayerItemStatusReadyToPlay

顺便说一下,还有另一种解决方案,我们会在[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL]; -(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context { if([self.playerItem status] == AVPlayerStatusReadyToPlay){ NSLog(@"The video actually plays") } } 处看到readyForDisplay状态,它还会指示视频呈现的时间。但是,该解决方案存在Apple文档中提到的缺点

AVPlayerLayer

以下是示例代码

/*!
     @property      readyForDisplay
     @abstract      Boolean indicating that the first video frame has been made ready for display for the current item of the associated AVPlayer.
     @discusssion   Use this property as an indicator of when best to show or animate-in an AVPlayerLayer into view. 
                    An AVPlayerLayer may be displayed, or made visible, while this propoerty is NO, however the layer will not have any 
                    user-visible content until the value becomes YES. 
                    This property remains NO for an AVPlayer currentItem whose AVAsset contains no enabled video tracks.
 */
@property(nonatomic, readonly, getter=isReadyForDisplay) BOOL readyForDisplay;

但是,self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; [self.playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL]; -(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context { if([self.playerLayer isReadyForDisplay]){ NSLog(@"Ready to display"); } } 应该返回YES,但是,作为文档,它不能保证。

我希望这会有所帮助。

答案 2 :(得分:0)

快捷键4

方法1

var rateObserver: NSKeyValueObservation?

self.rateObserver = myPlayer.observe(\.rate, options:  [.new, .old], changeHandler: { (player, change) in
     if player.rate == 1  {
          print("Playing")
      }else{
           print("Stop")
      }
 })

 // Later You Can Remove Observer      
 self.rateObserver?.invalidate()

方法2

myPlayer.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions(rawValue: NSKeyValueObservingOptions.new.rawValue | NSKeyValueObservingOptions.old.rawValue), context: nil)

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
      if keyPath == "rate" { 
          if player.rate == 1  {
              print("Playing")
          }else{
               print("Stop")
          }
      }
 }

答案 3 :(得分:0)

您可能要检测两件事:

  • AVPlayerLayer的{​​{1}}是在接收到第一帧时。
  • isReadyForDisplay的{​​{1}}是视频实际开始播放的时间。

要检查这两种状态,可以使用可观察性。

您将在类中定义三个对象:

AVPlayerItem

播放器实现将如下所示:

readyToPlay

这里,上下文是简单的整数或枚举。

您可以通过覆盖var player: AVPlayer? var playerItem: AVPlayerItem? var playerLayer: AVPlayerLayer? 方法来处理事件。

guard let videoURL = URL(string: "<videoPath>") else {
   return
}
asset = AVAsset(url: videoURL)
guard let asset = asset else {
   return
}
playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: requiredAssetKeys)
guard let playerItem = playerItem else {
   return
}
playerItem.addObserver(self,
                       forKeyPath: #keyPath(AVPlayerItem.status),
                       options: [.old, .new],
                       context: &playerItemContext)
player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.addObserver(self, 
                         forKeyPath: #keyPath(AVPlayerLayer.isReadyForDisplay), 
                         options: [.old, .new], 
                         context: &playerLayerContext)
avpController.player = player 
avpController.view.frame.size.height = playerView.frame.size.height
avpController.view.frame.size.width = playerView.frame.size.width
playerView.addSubview(avpController.view)
avpController.player?.play()

别忘了删除观察者。

observeValue