iOS使用AVPlayer播放視頻

在iOS開發(fā)中,播放視頻通常有兩種方式,一種是使用MPMoviePlayerController(需要導入MediaPlayer.Framework),還有一種是使用AVPlayer。關(guān)于這兩個類的區(qū)別可以參考http://stackoverflow.com/questions/8146942/avplayer-and-mpmovieplayercontroller-differences,簡而言之就是MPMoviePlayerController使用更簡單,功能不如AVPlayer強大,而AVPlayer使用稍微麻煩點,不過功能更加強大。這篇博客主要介紹下AVPlayer的基本使用,由于博主也是剛剛接觸,所以有問題大家直接指出~

0x01.新建一個ViewController類并添加下面代碼

在開發(fā)中,單純使用AVPlayer類是無法顯示視頻的,要將視頻層添加至AVPlayerLayer中,這樣才能將視頻顯示出來,所以先在ViewController@interface中添加以下屬性

viewController.m

@property (nonatomic,strong) AVPlayer      *avPlayer;
@property (nonatomic,strong) AVPlayerItem  *avPlayerItem;
@property (nonatomic,strong) AVPlayerLayer *avPlayerLayer;

在viewDidLoad中寫下下面代碼。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.avPlayerItem = [AVPlayerItem playerItemWithURL:self.videoUrl];
    //對item添加監(jiān)聽
    [self.avPlayerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [self.avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //[self.playItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
    
    self.avPlayer      = [AVPlayer playerWithPlayerItem:self.avPlayerItem];
    self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];

    AVPlayView *avPlayerView = [[AVPlayView alloc] initWithMoviePlayerLayer:self.avPlayerLayer frame:self.view.bounds];
    avPlayerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:avPlayerView];
    
    //這里可以實現(xiàn)界面代碼。
    //[self initSubViews];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayDidEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
- (void)moviePlayDidEnd
{
    NSLog(@"播放完成");
    [self.avPlayer pause];
    [self.link invalidate];
    [self dismissViewControllerAnimated:YES completion:nil];
}

其中playerView繼承自UIView,不過重寫了set和get方法,用于將player添加至playerView的AVPlayerLayer中,這樣才能順利將視頻顯示出來

0x02.新建一個AVPlayerView:UIView類并添加下面代碼。

在PlayerView.h中聲明一個AVPlayer對象,由于默認的layer是CALayer,而AVPlayer只能添加至AVPlayerLayer中,所以我們改變一下layerClass,這樣PlayerView的默認layer就變了,之后我們可以把在viewController中初始化的AVPlayer對象賦給AVPlayerLayer的player屬性。

AVPlayerView.h

 @property (nonatomic ,strong) AVPlayer *player;

AVPlayerView.m

#import "AVPlayView.h"


@interface AVPlayView()
{
    AVPlayerLayer *_playerlayer;
}
@end

@implementation AVPlayView

-(instancetype)initWithMoviePlayerLayer:(AVPlayerLayer *)playerLayer frame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _playerlayer = playerLayer;
        playerLayer.backgroundColor =  [UIColor blackColor].CGColor;
        _playerlayer.videoGravity   = AVLayerVideoGravityResizeAspect;
        _playerlayer.contentsScale  = [UIScreen mainScreen].scale;
        [self.layer addSublayer:_playerlayer];
    }
    return self;
}

-(void)layoutSublayersOfLayer:(CALayer *)layer{
    [super layoutSublayersOfLayer:layer];
    
    _playerlayer.bounds   = self.layer.bounds;
    _playerlayer.position = self.layer.position;
}

0x03.實現(xiàn)視頻的播放:

第一步在viewDidLoad中執(zhí)行初始化:

先將在線視頻鏈接存放在videoUrl中,然后初始化playerItem,playerItem是管理資源的對象

然后監(jiān)聽playerItemstatusloadedTimeRange屬性,status有三種狀態(tài):

AVPlayerStatusUnknown,
AVPlayerStatusReadyToPlay,
AVPlayerStatusFailed

當status等于AVPlayerStatusReadyToPlay時代表視頻已經(jīng)可以播放了,我們就可以調(diào)用play方法播放了。
loadedTimeRange屬性代表已經(jīng)緩沖的進度,監(jiān)聽此屬性可以在UI中更新緩沖進度,也是很有用的一個屬性。
最后添加一個通知,用于監(jiān)聽視頻是否已經(jīng)播放完畢,然后實現(xiàn)KVO的方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    
    if ([keyPath isEqualToString:@"loadedTimeRanges"]){
        NSTimeInterval loadedTime = [self availableDurationWithplayerItem:playerItem];
        NSTimeInterval totalTime = CMTimeGetSeconds(playerItem.duration);
        
        //if (!self.slider.isSliding) {
            //self.slider.progressPercent = loadedTime/totalTime;
        //}
        
    }else if ([keyPath isEqualToString:@"status"]){
        if (playerItem.status == AVPlayerItemStatusReadyToPlay){
            //NSLog(@"playerItem is ready");
            
            [self.avPlayer play];
            self.slider.enabled = YES;
            self.playButton.enabled = YES;
        } else{
            NSLog(@"load break");
            //self.faildView.hidden = NO;
        }
    }
}

- (NSTimeInterval)availableDurationWithplayerItem:(AVPlayerItem *)playerItem
{
    NSArray *loadedTimeRanges = [playerItem loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域
    NSTimeInterval startSeconds = CMTimeGetSeconds(timeRange.start);
    NSTimeInterval durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result = startSeconds + durationSeconds;// 計算緩沖總進度
    return result;
}

此方法主要對status和loadedTimeRanges屬性做出響應,status狀態(tài)變?yōu)锳VPlayerStatusReadyToPlay時,說明視頻已經(jīng)可以播放了,這時我們可以獲取一些視頻的信息,包含視頻長度等,把播放按鈕設(shè)備enabled,點擊就可以調(diào)用play方法播放視頻了。在AVPlayerStatusReadyToPlay的底部還有個monitoringPlayback方法:

- (void)monitoringPlayback:(AVPlayerItem *)playerItem {
  self.playbackTimeObserver = [self.playerView.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {   
  CGFloat currentSecond = playerItem.currentTime.value/playerItem.currentTime.timescale;
 // 計算當前在第幾秒 
  [self updateVideoSlider:currentSecond]; 
 NSString *timeString = [self convertTime:currentSecond]; 
 self.timeLabel.text = [NSString stringWithFormat:@"%@/%@",timeString,_totalTime]; }]; 
}

monitoringPlayback用于監(jiān)聽每秒的狀態(tài),- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;此方法就是關(guān)鍵,interval參數(shù)為響應的間隔時間,這里設(shè)為每秒都響應,queue是隊列,傳NULL代表在主線程執(zhí)行??梢愿乱粋€UI,比如進度條的當前時間等。

0x04.播放器其他元素。

這里只介紹播放方法,具體暫停功能、播放進度、時間顯示等在這里不做討論。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容