iOS使用AVPlayer播放视频

作者: 云天大侠_general | 来源:发表于2017-03-19 11:33 被阅读1655次

    在iOS开发中,播放视频通常有两种方式,一种是使用MPMoviePlayerController(需要导入MediaPlayer.Framework),还有一种是使用AVPlayer。关于这两个类的区别可以参考http://stackoverflow.com/questions/8146942/avplayer-and-mpmovieplayercontroller-differences,简而言之就是MPMoviePlayerController使用更简单,功能不如AVPlayer强大,而AVPlayer使用稍微麻烦点,不过功能更加强大。这篇博客主要介绍下AVPlayer的基本使用,由于博主也是刚刚接触,所以有问题大家直接指出~

    0x01.新建一个ViewController类并添加下面代码

    在开发中,单纯使用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添加监听
        [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];
        
        //这里可以实现界面代码。
        //[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.实现视频的播放:

    第一步在viewDidLoad中执行初始化:

    先将在线视频链接存放在videoUrl中,然后初始化playerItem,playerItem是管理资源的对象

    然后监听playerItemstatusloadedTimeRange属性,status有三种状态:

    AVPlayerStatusUnknown,
    AVPlayerStatusReadyToPlay,
    AVPlayerStatusFailed
    

    当status等于AVPlayerStatusReadyToPlay时代表视频已经可以播放了,我们就可以调用play方法播放了。
    loadedTimeRange属性代表已经缓冲的进度,监听此属性可以在UI中更新缓冲进度,也是很有用的一个属性。
    最后添加一个通知,用于监听视频是否已经播放完毕,然后实现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];// 获取缓冲区域
        NSTimeInterval startSeconds = CMTimeGetSeconds(timeRange.start);
        NSTimeInterval durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度
        return result;
    }
    

    此方法主要对status和loadedTimeRanges属性做出响应,status状态变为AVPlayerStatusReadyToPlay时,说明视频已经可以播放了,这时我们可以获取一些视频的信息,包含视频长度等,把播放按钮设备enabled,点击就可以调用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用于监听每秒的状态,- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;此方法就是关键,interval参数为响应的间隔时间,这里设为每秒都响应,queue是队列,传NULL代表在主线程执行。可以更新一个UI,比如进度条的当前时间等。

    0x04.播放器其他元素。

    这里只介绍播放方法,具体暂停功能、播放进度、时间显示等在这里不做讨论。

    相关文章

      网友评论

        本文标题:iOS使用AVPlayer播放视频

        本文链接:https://www.haomeiwen.com/subject/vgrknttx.html