iOS -三種視頻播放器總結(jié)(播放多個小視頻)

前言###

由于什么直播、小視頻火爆之后,我們開發(fā)者也要準(zhǔn)備我們的播放器了,最常用到的肯定是自定義AVPlayer播放器,雖然本文也主要研究的也是AVPlayer,但是你知道嗎?蘋果其實(shí)為我們提供了三種播放器。

播放兩種視頻###

1、播放本地視頻
播放本地視頻其實(shí)就是播放本地的視頻文件路徑,[NSURL fileURLWithPath:videoPath];找到文件路徑并且播放
2、播放網(wǎng)絡(luò)視頻
簡單來講就是我們設(shè)置播放器url地址等參數(shù)后,播放器就會向遠(yuǎn)程url所在服務(wù)器發(fā)送請求(一般請求包括兩個值,一個是offset偏移量,另一個是length長度),然后服務(wù)器就會根據(jù)參數(shù)返回數(shù)據(jù)給播放器。
3、播放器一般支持播放格式
AVPlayer支持WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等
MPMoviePlayerController與MPMoviePlayerViewController支持MOV, MP4, .MPV、3GP等

蘋果的三種播放器播放視頻###

我寫了一個實(shí)例demo,包括
1、MPMoviePlayerController播放視頻
2、MPMoviePlayerViewController播放視頻
3、AVPlayer播放視頻當(dāng)個視頻
4、AVPlayer播放視頻多個視頻
項(xiàng)目下載地址:三種視頻播放器大總結(jié)
項(xiàng)目效果圖

三種播放器大總結(jié).gif
三種播放器大總結(jié).gif

一、MPMoviePlayerController播放視頻,但是iOS3.2之后不建議使用
這個播放器在MediaPlayer中,所以在使用的時候,必須先導(dǎo)入

#import <MediaPlayer/MediaPlayer.h>

MPMoviePlayerController播放器是繼承于NSObject,但是內(nèi)部有個view可以展示視頻內(nèi)容,如果將該視圖添加其他控制器的view上,即可顯示視頻內(nèi)容
播放狀態(tài)需要增加觀察者來監(jiān)聽

- (MPMoviePlayerController *)player
{
  if(_player == nil)
 {
   // 1.創(chuàng)建播放器
  NSURL *url = [NSURL URLWithString:self.videoPath];
  _player = [[MPMoviePlayerController alloc]initWithContentURL:url]; 
  // 2.給播放器內(nèi)部的View設(shè)置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];
  //監(jiān)聽當(dāng)前視頻播放狀態(tài)
  [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(loadStateDidChange:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
  // 4.設(shè)置控制面板的顯示
  //_player.controlStyle = MPMovieControlStyleFullscreen;
 }
    return _player;
}
  -(void)loadStateDidChange:(NSNotification*)sender
{
switch (self.player.loadState) {
    case MPMovieLoadStatePlayable:
    {
        NSLog(@"加載完成,可以播放");
    }
        break;
    case MPMovieLoadStatePlaythroughOK:
    {
        NSLog(@"緩沖完成,可以連續(xù)播放");
    }
        break;
    case MPMovieLoadStateStalled:
    {
        NSLog(@"緩沖中");
    }
        break;
    case MPMovieLoadStateUnknown:
    {
        NSLog(@"未知狀態(tài)");
    }
        break;
    default:
        break;
  }
}

二、MPMoviePlayerViewController播放視頻,但是iOS3.2之后不建議使用
其實(shí)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播放視頻當(dāng)個視頻(本文重點(diǎn)講解)
由于播放器可能在以后我們經(jīng)常會用到,所以我建議封裝成工具類。
首先我們來看看AVPlayer播放器設(shè)置一些什么鬼?

@property (nonatomic, strong) AVPlayerItem *currentPlayerItem; //當(dāng)前正在播放視頻的Item
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *currentPlayerLayer; //當(dāng)前圖像層

AVPlayerItem:播放器的播放model,管理資源的對象,這個東東很重要,不僅可以可以獲得到播放狀態(tài)status,還可以看到緩沖進(jìn)度loadedTimeRange、playbackBufferEmpty、playbackLikelyToKeepUp
等屬性。
AVPlayer:播放器自身的播放工具類,可以播放play、暫停pause等
AVPlayerLayer:播放器播放的View,預(yù)覽層,把這個View增加到播放頁面顯示區(qū)域,就可以看到播放的畫面

第一步:
導(dǎo)入AVPlayer播放器框架

#import <AVFoundation/AVFoundation.h>

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

 //加載視頻的方式
if([url.absoluteString hasPrefix:@"http"])
{
    //網(wǎng)絡(luò)加載數(shù)據(jù)
    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;但是是只讀的,如果我們想要知道播放器的狀態(tài),那么就利用KVO監(jiān)聽狀態(tài)、同時監(jiān)聽播放器的緩沖進(jìn)度playbackBufferEmpty、是否加載完成(注意監(jiān)聽者可以在初始化的時候就增加)playbackLikelyToKeepUp

  #define  LZBVideoPlayerStatus  @"status"
  #define  LZBVideoPlayerPlaybackBufferEmpty  @"playbackBufferEmpty"
  #define  LZBVideoPlayerStatusplaybackLikelyToKeepUp  @"playbackLikelyToKeepUp"
 //增加播放器播放監(jiān)聽
- (void)addPlayerObserver
{
//播放狀態(tài)監(jiān)聽
[_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];
}
 //移除播放器播放監(jiān)聽
- (void)removePlayerObserver
{
[_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerStatus];
[_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerPlaybackBufferEmpty];
[_currentPlayerItem removeObserver:self forKeyPath:LZBVideoPlayerStatusplaybackLikelyToKeepUp];
}

第四步
監(jiān)聽播放器的狀態(tài)
- (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];
}
}
//監(jiān)聽status
- (void)processObserveValueStatusWithItem:(AVPlayerItem *)playerItem
{
AVPlayerItemStatus status = playerItem.status;
switch (status) {
case AVPlayerItemStatusUnknown:{
}
break;
//監(jiān)聽到準(zhǔn)備播放
case AVPlayerItemStatusReadyToPlay:{
[self.player play]; //開始準(zhǔn)備播放
[self.showSuperView.layer insertSublayer:self.currentPlayerLayer atIndex:0]; //把預(yù)覽層增加到父類顯示區(qū)域
}
break;
case AVPlayerItemStatusFailed:{
}
break;
}
}

第五步
監(jiān)聽什么時候緩沖完成。主要邏輯:監(jiān)聽是否正在緩沖processObserveBuffering,如果正在緩沖,那么調(diào)用bufferingForSeconds,暫停播放、等過了2s之后再去播放一次并且檢查時候緩沖完成,如果緩沖完成就播放,如果沒有就繼續(xù)等2s,這樣循環(huán)到緩存完成。(只是適合播放小視頻)

 //緩沖進(jìn)度
- (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];
    }
});
}

第六步
在播放過程中還可以獲取播放時長和已經(jīng)播放的時間

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

第七步
播放過程中還要考慮,app的狀態(tài),并且監(jiān)聽內(nèi)存等

 //增加app運(yùn)行狀態(tài)監(jiān)聽
-(void)addObserverOnce{
if (!self.isAddObserver) {
    // 添加監(jiān)聽,只能增加一次
    [[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;
 }

小細(xì)節(jié):本文demo中還增加了視頻加載過程的默認(rèn)默認(rèn)背景圖等。
AVPlayer播放多個視頻留到下一篇文章,未完待續(xù)。。。。
下一站
AVPlayer播放多個小視頻切換

詳情代碼請直接下載demo查看:
項(xiàng)目下載地址:三種視頻播放器大總結(jié)

最后贈言###

如果覺得文章對您有幫助,不要忘記star哦!??,star 是對程序猿最大的鼓勵!

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

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

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