iOS小視頻的基本使用

IOS 無限循環小視頻播放

無限循環播放我們的小視頻,我們有三中選擇:

1.MPMoviePlayerController
2.AVPlayer
3.AVAssetReader+AVAssetReaderTrackOutput

但是我們這個預覽層是自定義的喔,所以MPMoviePlayerController只能馬上給篩選掉了,所以用,那麼我們就要用到 AVPlayer 了,雖然上 AVPlayer 最多隻能創建16個,性能上不及用 AVAssetReader+AVAssetReaderTrackOutput 方法好,但是對於這麼個視頻小播放也是足夠的了。(PS:接下來博主會寫一篇關於如何用AVAssetReader+AVAssetReaderTrackOutput來實現播放視頻)

AVPlayer

AVPlayer本身並不能顯示視頻,而且它也不像MPMoviePlayerController有一個view屬性。如果AVPlayer要顯示必須創建一個播放器層AVPlayerLayer用於展示,播放器層繼承於CALayer, 
有了AVPlayerLayer之添加到控制器視圖的layer中即可。要使用AVPlayer首先了解一下幾個常用的類:

AVAsset:主要用於獲取多媒體信息,是一個抽象類,不能直接使用。
AVURLAssetAVAsset的子類,可以根據一個URL路徑創建一個包含媒體信息的AVURLAsset對象。
AVPlayerItem:一個媒體資源管理對象,管理者視頻的一些基本信息和狀態,一個AVPlayerItem對應着一個視頻資源。

我們先來熟悉一下 AVPlayer 的這些類
那麼運用AVPlayer播放視頻的步驟如下:
1.創建 AVPlayerItem ,用來實例化AVPlayer並監控視頻的狀態

- (AVPlayer *)player
{
if (!_player ) {
    AVPlayerItem *playerItem = [self getPlayItem];
    _player = [[AVPlayer alloc]initWithPlayerItem:playerItem];
    // 可以利用 AVPlayerItem 對這個視頻的狀態進行監控

}
return _player;
}

- (AVPlayerItem *)getPlayItem
{
    NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath=[cachePath stringByAppendingPathComponent:MOVIEPATH];
    NSURL *saveUrl=[NSURL fileURLWithPath:savePath];

    // 通過文件 URL 來實例化 AVPlayerItem
    AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:saveUrl];

    return playerItem;
}

2.通過AVPlayer 創建預覽層(AVPlayerLayer)並添加到可視的圖層上播放

    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
     playerLayer.frame = _viewContrain.bounds;
     playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//視頻填充模式
     [_viewContrain.layer addSublayer:playerLayer];
     [self.player play];

3.通過 KVO 來監聽視頻的屬性,查看是否播放完成,播放長度爲多小,緩衝了多少等等

/** * 給播放器添加進度更新 */
-(void)addProgressObserver{ 
  AVPlayerItem *playerItem=self.player.currentItem; 
  UIProgressView *progress=self.progress; //這裏設置每秒執行一次 
  [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
    float current=CMTimeGetSeconds(time); 
    float total=CMTimeGetSeconds([playerItem duration]);
   NSLog(@"當前已經播放%.2fs.",current); 
  if (current) { 
        [progress setProgress:(current/total) animated:YES];
     } 
  }];
}

#pragma mark - KVO
  /** * 給AVPlayerItem添加監控 * 
      * @param playerItem AVPlayerItem對象 */
-(void)addObserverToPlayerItem:(AVPlayerItem *)playerItem{
//監控狀態屬性,注意AVPlayer也有一個status屬性,通過監控它的status也可以獲得播放狀態
[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
//監控網絡加載情況屬性
[playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}

-(void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem{
[playerItem removeObserver:self forKeyPath:@"status"];
[playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}

/** * 通過KVO監控播放器狀態 *
     * @param keyPath 監控屬性 
     * @param object 監視器 
     * @param change 狀態改變 
     * @param context 上下文 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    AVPlayerItem *playerItem=object;
    if ([keyPath isEqualToString:@"status"]) {
    AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
    if(status==AVPlayerStatusReadyToPlay){
            NSLog(@"正在播放...,視頻總長度:%.2f",CMTimeGetSeconds(playerItem.duration));
        }
    }
    else if([keyPath isEqualToString:@"loadedTimeRanges"])
    {
        NSArray *array=playerItem.loadedTimeRanges;
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次緩衝時間範圍
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval totalBuffer = startSeconds + durationSeconds;//緩衝總長度
        NSLog(@"共緩衝:%.2f",totalBuffer);
    }
}

到此,我們就把 AVPlayer 視頻播放的方法創建完畢了。

那麼我們在視頻錄製完成的時候調用播放視頻的方法了

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"---- 錄製結束 ----");
}
- (void)completeHandle
{
    // 完成後不斷播放
    [_captureVideoPreviewLayer removeFromSuperlayer];

    // 播放視頻
    // 1.創建播放層
    // 這裏爲什麼要調用延遲1.0秒呢,我們說過用 AVCaptureMovieFileOutput 來錄製視頻,是邊錄邊寫的,即使是錄製完成了,真實的是視頻還在寫,大概時間是延遲1.2秒左右。
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            // 在此方法調用創建 AVPlayer 播放視頻的第二部
            2.通過AVPlayer 創建預覽層(AVPlayerLayer)並添加到可視的圖層上播放
            [self addNotification];
      });
  }

添加視頻播放完後的監控來循環播放視頻 

 /**
 *  添加播放器通知
 */
-(void)addNotification{
    //給AVPlayerItem添加播放完成通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}

-(void)removeNotification{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
/**
 *  播放完成通知
 *
 *  @param notification 通知對象
 */
-(void)playbackFinished:(NSNotification *)notification{
    NSLog(@"視頻播放完成.");


    // 播放完成後重複播放
    // 跳到最新的時間點開始播放
    [_player seekToTime:CMTimeMake(0, 1)];
    [_player play];
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章