AVPlayer的使用+簡單的播放器Demo

學習內容

歡迎關注我的iOS學習總結——每天學一點iOS://github.com/practiceqian/one-day-one-iOS-summary

AVPlayer學習

  1. 幾個播放器相關的類

    • AVPlayer、AVURLAsset、AVPlayerItem、AVPlayerLayer

      //控制播放器的播放、暫停、播放速度
      @property (nonatomic,strong) AVPlayer * player;
      //管理資源對象,提供播放數據源
      @property (nonatomic,strong) AVPlayerItem* playItem;
      //負責顯示影片,如果沒有添加該類,只有聲音沒有畫面
      @property (nonatomic,strong) AVPlayerLayer* playerLayer;
      
  2. 構建一個簡單的播放器

    • //一個UIImageView,構建播放器的顯示區域
      self.playerView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height/3)];
      [self.view addSubview:self.playerView];
      
      //播放資源
      NSURL* playUrl = [NSURL URLWithString:@"//clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
      self.playItem = [AVPlayerItem playerItemWithURL:playUrl];
      //播放器實例
      self.player = [AVPlayer playerWithPlayerItem:self.playItem];
      //顯示區域
      self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
      self.playerLayer.frame = self.playerView.bounds;
      //將顯示區域添加到UIImageView上
      [self.playerView.layer addSublayer:self.playerLayer];
      //開始播放
      [self.player play];
      
    • 效果如圖

      • 可以在UIImageView的容器中看到畫面,但是此時依然不能控制播放的進度等
  3. 使用AVPlayer控制播放行為

    • //播放
      [self.player play];
      //暫停
      [self.player pause];
      //控制播放速度
      self.player.rate = 2.0
      
  4. 使用AVPlayerItem控制播放狀態

    • //三種播放狀態
      typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {
      	AVPlayerItemStatusUnknown = 0,	//未知
      	AVPlayerItemStatusReadyToPlay = 1,	//準備播放
      	AVPlayerItemStatusFailed = 2	//播放失敗
      };
      
      
    • 使用KVO進行監聽播放狀態

      //對status進行監聽
      [self.playItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
      //監聽的回調
      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
          if ([object isKindOfClass:[AVPlayerItem class]]) {
              if ([keyPath isEqualToString:@"status"]) {
                //根據播放的三種狀態進行處理
                  switch (self.playItem.status) {
                      case AVPlayerItemStatusUnknown:
                          NSLog(@"播放狀態未知");
                          break;
                      case AVPlayerItemStatusReadyToPlay:
                          NSLog(@"準備播放");
                          break;
                      case AVPlayerItemStatusFailed:
                          NSLog(@"播放失敗");
                          break;;
                      default:
                          break;
                  }
              }
          }
      }
      
    • 獲取播放時間

      • //CMTime是以分數的形式表示時間,value表示分子,timescale表示分母,flags是位掩碼,表示時間的指定狀態。
        typedef struct{
            CMTimeValue    value;     // 幀數
            CMTimeScale    timescale;  // 幀率(影片每秒有幾幀)
            CMTimeFlags    flags;        
            CMTimeEpoch    epoch;    
        } CMTime;
        
      • //獲取當前的播放時間
        float currentTime = self.playItem.currentTime.value/self.playItem.currentTime.timescale;
        //獲取影片的總時間(一般在準備播放狀態時獲取)
        float totalTime = CMTimeGetSeconds(self.playItem.duration);
        
    • 監聽播放的進度

      • __weak typeof(self) weakSelf = self;
        //CMTimeMake(1,1),一秒鐘監聽一次
        [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:nil usingBlock:^(CMTime time) {
          AVPlayerItem* item = weakSelf.playItem;
          float curTime = item.currentTime.value/item.currentTime.timescale;
          NSLog(@"當前時間:%.0f",curTime);
        }];
        
    • 監聽緩衝的進度

      [self.playItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
      ---------------------------------------------------------------
        if ([keyPath isEqualToString:@"loadedTimeRanges"]){
        NSArray *array = self.playItem.loadedTimeRanges;
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次緩衝時間範圍
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval totalBuffer = startSeconds + durationSeconds;//緩衝總長度
        NSLog(@"當前已緩衝時間:%f",totalBuffer);
      }
      
    • 監聽已快取時間充足/不足

      [self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
      ---------------------------------------------------------------------
      [self.playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
      
    • 最後的demo

Tags: