美文网首页iOS 坑的集中营
三种视频播放器总结(播放多个小视频)

三种视频播放器总结(播放多个小视频)

作者: 摸着石头过河_崖边树 | 来源:发表于2017-05-04 21:45 被阅读617次

    前言###

    由于什么直播、小视频火爆之后,我们开发者也要准备我们的播放器了,最常用到的肯定是自定义AVPlayer播放器,虽然本文也主要研究的也是AVPlayer,但是你知道吗?苹果其实为我们提供了三种播放器。

    播放两种视频###

    1、播放本地视频
    播放本地视频其实就是播放本地的视频文件路径,[NSURL fileURLWithPath:videoPath];找到文件路径并且播放
    2、播放网络视频
    简单来讲就是我们设置播放器url地址等参数后,播放器就会向远程url所在服务器发送请求(一般请求包括两个值,一个是offset偏移量,另一个是length长度),然后服务器就会根据参数返回数据给播放器。
    3、播放器一般支持播放格式
    AVPlayer支持WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等
    MPMoviePlayerController与MPMoviePlayerViewController支持MOV, MP4, .MPV、3GP等

    苹果的三种播放器播放视频###

    我写了一个实例demo,包括
    1、MPMoviePlayerController播放视频
    2、MPMoviePlayerViewController播放视频
    3、AVPlayer播放视频当个视频
    4、AVPlayer播放视频多个视频
    项目下载地址:三种视频播放器大总结
    项目效果图

    三种播放器大总结.gif三种播放器大总结.gif
    一、MPMoviePlayerController播放视频,但是iOS3.2之后不建议使用
    这个播放器在MediaPlayer中,所以在使用的时候,必须先导入
    #import <MediaPlayer/MediaPlayer.h>
    

    MPMoviePlayerController播放器是继承于NSObject,但是内部有个view可以展示视频内容,如果将该视图添加其他控制器的view上,即可显示视频内容
    播放状态需要增加观察者来监听

    - (MPMoviePlayerController *)player
    
    {
      if(_player == nil)
     {
       // 1.创建播放器
      NSURL *url = [NSURL URLWithString:self.videoPath];
      _player = [[MPMoviePlayerController alloc]initWithContentURL:url]; 
      // 2.给播放器内部的View设置frame
      _player.view.frame = CGRectMake(0, 64, self.view.bounds.size.width, self.view.bounds.size.width * 9 / 16);
      // 3.添加到控制器View中
      [self.view addSubview:_player.view];
      //监听当前视频播放状态
      [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(loadStateDidChange:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
      // 4.设置控制面板的显示
      //_player.controlStyle = MPMovieControlStyleFullscreen;
     }
        return _player;
    }
      -(void)loadStateDidChange:(NSNotification*)sender
    {
    switch (self.player.loadState) {
        case MPMovieLoadStatePlayable:
        {
            NSLog(@"加载完成,可以播放");
        }
            break;
        case MPMovieLoadStatePlaythroughOK:
        {
            NSLog(@"缓冲完成,可以连续播放");
        }
            break;
        case MPMovieLoadStateStalled:
        {
            NSLog(@"缓冲中");
        }
            break;
        case MPMovieLoadStateUnknown:
        {
            NSLog(@"未知状态");
        }
            break;
        default:
            break;
      }
    }
    

    二、MPMoviePlayerViewController播放视频,但是iOS3.2之后不建议使用
    其实MPMoviePlayerViewController播放视频与MPMoviePlayerController播放一样,只是MPMoviePlayerViewController只能全屏播放视频
    并且MPMoviePlayerViewController包含MPMoviePlayerController属性

    - (instancetype)initWithContentURL:(NSURL *)contentURL NS_DESIGNATED_INITIALIZER;
    
     @property (nonatomic, readonly) MPMoviePlayerController *moviePlayer;
    

    并且弹出方式也是modal方式
    -(void)presentMoviePlayerViewControllerAnimated:(MPMoviePlayerViewController *)moviePlayerViewController
    -(void)dismissMoviePlayerViewControllerAnimated

    3、AVPlayer播放视频当个视频(本文重点讲解)
    由于播放器可能在以后我们经常会用到,所以我建议封装成工具类。
    首先我们来看看AVPlayer播放器设置一些什么鬼?

    @property (nonatomic, strong) AVPlayerItem *currentPlayerItem; //当前正在播放视频的Item
    
    @property (nonatomic, strong) AVPlayer *player;
    @property (nonatomic, strong) AVPlayerLayer *currentPlayerLayer; //当前图像层
    

    AVPlayerItem:播放器的播放model,管理资源的对象,这个东东很重要,不仅可以可以获得到播放状态status,还可以看到缓冲进度loadedTimeRange、playbackBufferEmpty、playbackLikelyToKeepUp
    等属性。
    AVPlayer:播放器自身的播放工具类,可以播放play、暂停pause等
    AVPlayerLayer:播放器播放的View,预览层,把这个View增加到播放页面显示区域,就可以看到播放的画面

    第一步:
    导入AVPlayer播放器框架

    #import <AVFoundation/AVFoundation.h>
    

    第二步
    使用url初始化播放器AVPlayerItem、AVPlayer、AVPlayerLayer

     //加载视频的方式
    
    if([url.absoluteString hasPrefix:@"http"])
    {
        //网络加载数据
        AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:[NSURL URLWithString:[url.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
        self.currentPlayerItem = playerItem;
    }
    else
    {
       //本地视频
        self.currentPlayerItem = [AVPlayerItem playerItemWithURL:url];
    }
    self.player = [AVPlayer playerWithPlayerItem:self.currentPlayerItem];
    self.currentPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    self.currentPlayerLayer.frame = CGRectMake(0, 0, superView.bounds.size.width, superView.bounds.size.height);
    

    第三步
    初始化完成,那么什么时候播放视频呢,查看AVPlayerItem的属性@property (nonatomic, readonly) AVPlayerItemStatus status;但是是只读的,如果我们想要知道播放器的状态,那么就利用KVO监听状态、同时监听播放器的缓冲进度playbackBufferEmpty、是否加载完成(注意监听者可以在初始化的时候就增加)playbackLikelyToKeepUp

      #define  LZBVideoPlayerStatus  @"status"
    
      #define  LZBVideoPlayerPlaybackBufferEmpty  @"playbackBufferEmpty"
      #define  LZBVideoPlayerStatusplaybackLikelyToKeepUp  @"playbackLikelyToKeepUp"
     //增加播放器播放监听
    - (void)addPlayerObserver
    {
    //播放状态监听
    [_currentPlayerItem addObserver:self forKeyPath:LZBVideoPlayerStatus options:NSKeyValueObservingOptionNew context:nil];
    [_currentPlayerItem addObserver:self forKeyPath:LZBVideoPlayerPlaybackBufferEmpty options:NSKeyValueObservingOptionNew context:nil];
    [_currentPlayerItem addObserver:self forKeyPath:LZBVideoPlayerStatusplaybackLikelyToKeepUp options:NSKeyValueObservingOptionNew context:nil];
    }
     //移除播放器播放监听
    - (void)removePlayerObserver
    {
    [_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerStatus];
    [_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerPlaybackBufferEmpty];
    [_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerStatusplaybackLikelyToKeepUp];
    }
    

    第四步
    监听播放器的状态
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
    {
    if([keyPath isEqualToString:LZBVideoPlayerStatus])
    {
    [self processObserveValueStatusWithItem:(AVPlayerItem *)object];
    }
    else if ([keyPath isEqualToString:LZBVideoPlayerPlaybackBufferEmpty])
    {
    [self processObserveBuffering];
    }
    else if([keyPath isEqualToString:LZBVideoPlayerStatusplaybackLikelyToKeepUp])
    {
    [self processObserveBuffered];
    }
    }
    //监听status
    - (void)processObserveValueStatusWithItem:(AVPlayerItem *)playerItem
    {
    AVPlayerItemStatus status = playerItem.status;
    switch (status) {
    case AVPlayerItemStatusUnknown:{
    }
    break;
    //监听到准备播放
    case AVPlayerItemStatusReadyToPlay:{
    [self.player play]; //开始准备播放
    [self.showSuperView.layer insertSublayer:self.currentPlayerLayer atIndex:0]; //把预览层增加到父类显示区域
    }
    break;
    case AVPlayerItemStatusFailed:{
    }
    break;
    }
    }

    第五步
    监听什么时候缓冲完成。主要逻辑:监听是否正在缓冲processObserveBuffering,如果正在缓冲,那么调用bufferingForSeconds,暂停播放、等过了2s之后再去播放一次并且检查时候缓冲完成,如果缓冲完成就播放,如果没有就继续等2s,这样循环到缓存完成。(只是适合播放小视频)

     //缓冲进度
    
    - (void)processObserveBuffering
     {
      if(self.currentPlayerItem.playbackBufferEmpty)
      {
      [self startLoadingViewInSuperView:self.showSuperView];
      self.isBuffering = YES;
      [self bufferingForSeconds];
     }
      }
    //缓冲完成
     - (void)processObserveBuffered
     {
    if (self.currentPlayerItem.playbackLikelyToKeepUp){
        [self stopLoading];
        [self startPlayerTimeProgress];
        self.coverImageView.hidden = YES;
        self.isBuffering = NO;
       }
     }
      -(void)bufferingForSeconds{
    if (self.isBuffering == NO) return;
    [self.player pause];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.player play];
        if (!self.currentPlayerItem.isPlaybackLikelyToKeepUp) {
            [self bufferingForSeconds];
        }
    });
    }
    

    第六步
    在播放过程中还可以获取播放时长和已经播放的时间

     float totalDuration = CMTimeGetSeconds(self.currentPlayerItem.duration);
    
      float currentTime = CMTimeGetSeconds(self.currentPlayerItem.currentTime);
       NSInteger  residueTime =(NSInteger)(totalDuration - currentTime);
    

    第七步
    播放过程中还要考虑,app的状态,并且监听内存等

     //增加app运行状态监听
    
    -(void)addObserverOnce{
    if (!self.isAddObserver) {
        // 添加监听,只能增加一次
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationWillResignActiveNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterPlayGround) name:UIApplicationDidBecomeActiveNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidPlayToEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    }
    self.isAddObserver = YES;
     }
    

    小细节:本文demo中还增加了视频加载过程的默认默认背景图等。
    AVPlayer播放多个视频留到下一篇文章,未完待续。。。。
    下一站
    AVPlayer播放多个小视频切换

    详情代码请直接下载demo查看:
    项目下载地址:三种视频播放器大总结

    最后赠言###

    如果觉得文章对您有帮助,不要忘记star哦!😝,star 是对程序猿最大的鼓励!

    相关文章

      网友评论

        本文标题:三种视频播放器总结(播放多个小视频)

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