iOS 視頻播放 - AVPlayer

iOS實現視頻播放,原生代碼播放視頻更多的使用AVPlayer和AVPlayerViewController進行播放。
其中,

  • AVPlayer不能單獨進行播放,僅使用AVPLayer的話,還需要將其添加到AVPlayerLayer上進行播放,不含播放控制控件,需要自定義添加;
  • AVPlayerViewController也是在AVPlayer的基礎上集成的播放控件。包含完整的播放,暫停,進度拖動等控制控件。

所需庫

  • 使用AVPlayer和AVPlayerViewController需要添加庫文件:AVKit.framework
  • 獲取時間(CMTimeGetSeconds)等等需要添加庫文件:CoreMedia.framework

引用頭文件

#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>

實現播放(代碼)

1. AVPlayer

僅使用AVPlayer和AVPlayerLayer創建播放

//生成播放url
本地
NSString* localFilePath=[[NSBundle mainBundle]pathForResource:@"aaa" ofType:@"mp4"];
NSURL *videoUrl = [NSURL fileURLWithPath:localFilePath];
//網絡
NSString *webVideoPath = @"http://122.144.137.20:81/2018/12/video/d63797a1912a4f529d8cffab862d8747.mp4";
NSURL *videoUrl = [NSURL URLWithString:webVideoPath];

//創建播放單元
AVPlayerItem* item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:videoUrl]];	//通過url生成
//創建播放器
AVPlayer* player = [AVPlayer playerWithPlayerItem:item];		//使用播放單元生成相應的播放器
或者
AVPlayer* player = [AVPlayer playerWithURL:videoUrl];			//直接使用播放URL生成
//切換播放內容時
[player replaceCurrentItemWithPlayerItem:item];
//創建播放層,將playerLayer添加到view上即可播放
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.myPlayer];

2. AVPlayerViewController
AVPlayerViewController 在生成播放器player的基礎上,進行下一步調用:

AVPlayerViewController* playerVC = [[AVPlayerViewController alloc] init];
//設置播放器
playerVC.player = player;	
//設置播放範圍			
playerVC.view.frame = CGRectMake(0, 0, 700, 300);

/** 設置所播放視頻的適配顯示範圍 
 *  AVLayerVideoGravityResizeAspectFill :  顯示尺寸適配,保證適配內容不變形的情況下鋪滿顯示區域,畫面可能會有截斷
 *  AVLayerVideoGravityResizeAspect : 保證視頻不變形,畫面全部顯示,可能不能鋪滿顯示區域
 *  AVLayerVideoGravityResize : 保證視頻鋪滿顯示區域,畫面全部顯示,但視頻內容可能會有變形
 */
playerVC.videoGravity = AVLayerVideoGravityResizeAspectFill;
//顯示播放開始,播放進度條等控件
playerVC.showsPlaybackControls = YES;

通過[self presentViewController:playerVC animated:YES completion:nil];進行調用

播放相關監聽

  • status屬性
    播放單元playerItem可以通過添加status屬性的監聽來獲取視頻加載的狀態。
/** 觀察status屬性, 一共有三種屬性
 * AVPlayerStatusReadyToPlay : 可以播放
 * AVPlayerItemStatusFailed : 加載失敗
 * AVPlayerItemStatusUnknown : 未知錯誤
 */
[self.playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil]; 
  • loadedTimeRanges屬性
    播放單元playerItem還可以添加loadedTimeRanges屬性。
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

以上兩種屬性均在如下代碼中返回監聽結果:(這裏的代碼直接引用了簡書作者的代碼)

作者:梧雨北辰
鏈接:https://www.jianshu.com/p/b304694af77a

 - (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        //獲取playerItem的status屬性最新的狀態
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        switch (status) {
            case AVPlayerStatusReadyToPlay:{
                //獲取視頻長度
                CMTime duration = playerItem.duration; 
                //更新顯示:視頻總時長(自定義方法顯示時間的格式)
                self.totalNeedPlayTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(duration)];
                //開啓滑塊的滑動功能
                self.sliderView.enabled = YES;
                //關閉加載Loading提示
                [self showaAtivityInDicatorView:NO];
                //開始播放視頻
                [self.player play];
                break;
            }
            case AVPlayerStatusFailed:{//視頻加載失敗,點擊重新加載
                [self showaAtivityInDicatorView:NO];//關閉Loading視圖
                self.playerInfoButton.hidden = NO; //顯示錯誤提示按鈕,點擊後重新加載視頻
                [self.playerInfoButton setTitle:@"資源加載失敗,點擊繼續嘗試加載" forState: UIControlStateNormal];
                break;
            }
            case AVPlayerStatusUnknown:{
                NSLog(@"加載遇到未知問題:AVPlayerStatusUnknown");
                break;
            }
            default:
                break;
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        //獲取視頻緩衝進度數組,這些緩衝的數組可能不是連續的
        NSArray *loadedTimeRanges = playerItem.loadedTimeRanges;
        //獲取最新的緩衝區間
        CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
        //緩衝區間的開始的時間
        NSTimeInterval loadStartSeconds = CMTimeGetSeconds(timeRange.start);
        //緩衝區間的時長
        NSTimeInterval loadDurationSeconds = CMTimeGetSeconds(timeRange.duration);
        //當前視頻緩衝時間總長度
        NSTimeInterval currentLoadTotalTime = loadStartSeconds + loadDurationSeconds;
        //NSLog(@"開始緩衝:%f,緩衝時長:%f,總時間:%f", loadStartSeconds, loadDurationSeconds, currentLoadTotalTime);
        //更新顯示:當前緩衝總時長
        _currentLoadTimeLabel.text = [self formatTimeWithTimeInterVal:currentLoadTotalTime];
        //更新顯示:視頻的總時長
        _totalNeedLoadTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(self.player.currentItem.duration)];
        //更新顯示:緩衝進度條的值
        _progressView.progress = currentLoadTotalTime/CMTimeGetSeconds(self.player.currentItem.duration);
    }
}
  • 監聽播放進度
    播放器player可以添加時間觀察來管理播放進度
__weak __typeof(self) weakSelf = self;
[self.playerVC.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
       //當前播放的時間
       NSTimeInterval currentTime = CMTimeGetSeconds(time);
       //視頻的總時間
       NSTimeInterval totalTime = CMTimeGetSeconds(weakSelf.playerVC.player.currentItem.duration);

       if (currentTime == totalTime) {
          //[weakSelf dismissViewControllerAnimated:YES completion:nil];	//播放完成退出播放界面
        }
}];

以上爲目前使用iOS視頻播放功能的整理。

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