iOS流媒體開發(fā)之一:總結系統(tǒng)提供的接口

尊重知識洛姑,轉發(fā)請注明出處:iOS流媒體開發(fā)之一:總結系統(tǒng)提供的接口
<small> 本文參考了博文部分內容:AVPlayer 本地、網(wǎng)絡視頻播放相關 </small>


最近獨立完成了公司的一個電視直播和電臺直播的流媒體類項目,目前完成了第一版,已經上線,開發(fā)過程中收獲很多匠楚,準備寫一個流媒體系列博客總結和分享我的一些感悟。第一篇很簡單厂财,主要是總結下系統(tǒng)提供的常用的音視頻開發(fā)接口芋簿,屬于可以百度或者Google到一大堆資料的東西,幾個不支持流媒體播放的接口就不說了璃饱,一方面很簡單与斤,另一方面大多數(shù)項目用不到。了解這些技術的小伙伴就忽略吧荚恶,我這里只是簡單的總結下撩穿,沒有太多技術含量和價值。

預告

后續(xù)會分享有關自定義視頻播放器谒撼、M3U8下載食寡、M3U8回看等比較有難度的技術點,當然也不是隨便百度或者Google下就可以找到的東西廓潜,我就把這些技術點獻給簡書吧冻河。這里主要總結M3U8直播類的音視頻技術,至于MP4茉帅、3GP等等這些點播類的播放源都很簡單,無論下載還是播放都很容易實現(xiàn)锭弊,就不浪費簡書的服務器硬盤了堪澎。最近時間很緊,并且有一些技術點還需要繼續(xù)改進和優(yōu)化味滞,爭取盡快整理出比較靠譜的東西給大家樱蛤。


MPMoviePlayerController

  • 簡介
    MPMoviePlayerController既支持本地音視頻播放也支持網(wǎng)絡流媒體播放钮呀,功能已經十分完善了,流媒體項目常用的需求都可以滿足昨凡,比如播放爽醋、暫停,快進便脊、后退蚂四、監(jiān)聽播放器的播放狀態(tài)、截圖等功能哪痰,同時MPMoviePlayerController提供了一個簡單的全屏播放界面遂赠,可以輕松實現(xiàn)簡單的流媒體播放需求,如果需要深度自定義一個視頻播放器晌杰,可以將MPMoviePlayerController的view添加到自定義的控制器中跷睦,然后再講一些自定義的控件添加到相應view即可,代碼如下:
    MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL: myURL];
    [player prepareToPlay];
    [player.view setFrame: myView.bounds];
    [myView addSubview: player.view];
    [player play];

  • 總結
    MPMoviePlayerController為音視頻開發(fā)提供了簡潔易用的接口肋演,小伙伴們自行查閱文檔即可抑诸,這里就不贅述了。需要注意的是在iOS9 以后MPMoviePlayerController被蘋果棄用了爹殊,取而代之的是AVPlayerViewController蜕乡,究其原因,iOS9以后iPad支持了畫中畫功能边灭,即使用畫中畫播放后异希,我們退出APP,視頻會在一個小的窗口繼續(xù)播放绒瘦,用戶可以在使用其他APP的同時觀看視頻称簿,AVPlayerViewController提供了完整的畫中畫技術支持,具體后面再講惰帽。畫中畫如下圖:


    畫中畫.png

AVPlayer

  • 簡介
    如果我們只是開發(fā)只有音頻的流媒體項目憨降,MPMoviePlayerController足夠用了,可以滿足幾乎任何需求该酗,開發(fā)一個簡單的視頻播放器也足夠用授药。但是要深度自定義一個視頻播放器 使用AVPlayer就很方便了, AVPlayer自由度很高呜魄,可以自定義視頻播放器, AVPlayer本身無法顯示視頻悔叽,需要借助AVPlayerLayer顯示,初始化以及播放過程代碼如下:
    #import <AVFoundation/AVFoundation.h>

      @interface ViewController ()
    
      @property (strong, nonatomic) AVPlayer *avPlayer;
    
      @end
    
      @implementation ViewController
    
      - (void)viewDidLoad {
          [super viewDidLoad];
      //這個鏈接是M3U8的爵嗅,你看到此博客的時候此鏈接可能已經失效娇澎,請自行找鏈接測試
     AVPlayerItem *playItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:@"http://cctv1.vtime.cntv.cloudcdn.net/cache/12_/seg0/index.m3u8?AUTH=KDumCPYYPzSTcmtewPt/u78MdD6mwSpceXl98vdwcN8RIWA7hZqDK8s3RWkdW3PymV7TkVLHQ5UJp1gHXtkWGg=="]];
      //初始化AVPlayer
      self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:playItem];
      //設置AVPlayer關聯(lián)
      AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
      //設置視頻模式
      playerLayer.videoGravity = AVLayerVideoGravityResize;
      playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width * 9.0 / 16.0);
      //創(chuàng)建一個UIView與AVPlayerLayer關聯(lián)
      UIView *playerView = [[UIView alloc] initWithFrame:CGRectMake(0, 20, CGRectGetWidth(playerLayer.frame), CGRectGetHeight(playerLayer.frame))];
      playerView.backgroundColor = [UIColor blackColor];
      [playerView.layer addSublayer:playerLayer]; 
      [self.view addSubview:playerView];
      //開始播放(請在真機上運行)
      [self.avPlayer play];
      }
    

真機運行圖如下:


AVPlayer播放M3U8效果.png
  • 總結
    上面我們已經可以把展示我們視頻的view隨意處置了,可以為視頻播放增加常用的改變視頻比例睹晒、手勢改變音量趟庄、亮度等常用的功能括细。
    注意
    1、獲取AVPlayer的緩沖進度
    通過監(jiān)聽loadedTimeRanges戚啥、status可以獲取緩沖進度和播放進度
    代碼如下:
    首先添加監(jiān)聽
    [playItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    [playItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    監(jiān)聽回調
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {

      AVPlayerItem *playerItem = (AVPlayerItem *)object;
      if ([keyPath isEqualToString:@"loadedTimeRanges"]){
      //獲取緩沖進度
      NSArray *loadedTimeRanges = [playerItem loadedTimeRanges];
      // 獲取緩沖區(qū)域
      CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
      //開始的時間
      NSTimeInterval startSeconds = CMTimeGetSeconds(timeRange.start);
      //表示已經緩沖的時間
      NSTimeInterval durationSeconds = CMTimeGetSeconds(timeRange.duration);
      // 計算緩沖總時間
      NSTimeInterval result = startSeconds + durationSeconds;
      NSLog(@"開始:%f,持續(xù):%f,總時間:%f", startSeconds, durationSeconds, result);
      NSLog(@"視頻的加載進度是:%%%f", durationSeconds / self.total * 100);
          }else if ([keyPath isEqualToString:@"status"]){
      //獲取播放狀態(tài)
      if (playerItem.status == AVPlayerItemStatusReadyToPlay){
          NSLog(@"準備播放");
          //獲取視頻的總播放時長
          [self.avPlayer play];
          self.total = CMTimeGetSeconds(self.avPlayer.currentItem.duration);
              } else{
          NSLog(@"播放失敗");
          }
        }
       }
    

控制臺輸出結果
開始:0.000000,持續(xù):0.325000,總時間:0.325000 視頻的加載進度是:%inf 準備播放 開始:0.000000,持續(xù):18.203000,總時間:18.203000 視頻的加載進度是:%12.227365 開始:0.000000,持續(xù):35.108000,總時間:35.108000 視頻的加載進度是:%23.582833 開始:0.000000,持續(xù):43.119000,總時間:43.119000 視頻的加載進度是:%28.964002 開始:0.000000,持續(xù):46.068000,總時間:46.068000 視頻的加載進度是:%30.944912 開始:0.000000,持續(xù):62.160000,總時間:62.160000 視頻的加載進度是:%41.754270 開始:0.000000,持續(xù):73.283000,總時間:73.283000 視頻的加載進度是:%49.225840 開始:0.000000,持續(xù):80.064000,總時間:80.064000 視頻的加載進度是:%53.780790 開始:0.000000,持續(xù):94.298000,總時間:94.298000 視頻的加載進度是:%63.342088 開始:0.000000,持續(xù):101.682000,總時間:101.682000 視頻的加載進度是:%68.302087 開始:0.000000,持續(xù):106.977000,總時間:106.977000 視頻的加載進度是:%71.858858 開始:0.000000,持續(xù):117.775000,總時間:117.775000 視頻的加載進度是:%79.112117 開始:0.000000,持續(xù):132.172000,總時間:132.172000 視頻的加載進度是:%88.782906 開始:0.000000,持續(xù):148.871000,總時間:148.871000 視頻的加載進度是:%100.000000
從控制臺輸出的結果可以很清楚的看到視頻加載的進度奋单,這里有幾點需要注意
1、只有播放狀態(tài)變成AVPlayerItemStatusReadyToPlay時才可以獲取視頻播放的總時間猫十,提前獲取無效; 2览濒、我們判斷緩沖進度是靠比較視頻總時長self.total和已經緩沖的總時間durationSeconds作比較,如果二者相等即達到100%視頻則加載完成炫彩,這里需要注意匾七,有時這2個值在浮點數(shù)下不一定相同,有可能出現(xiàn)99.990836%這樣的情況江兢,但是視頻實際上已經加載完成昨忆,如果我們硬性的憑借100%判斷會出現(xiàn)有的視頻永遠加載不完的假象,因此在判斷的時候應該設置一個誤差值杉允,比如緩沖進度>99.95%就認為是加載完成了邑贴,具體數(shù)值可以根據(jù)項目自行設定一個合理的誤差; 3叔磷、這里顯示的所有數(shù)據(jù)拢驾,比如視頻的總時長、進度都是點播類播放源改基,非M3U8繁疤,M3U8是直播無法獲取總時長數(shù)據(jù),開始時間和緩沖時間等數(shù)據(jù)也沒有參考價值秕狰,項目中的直播視頻也不會涉及到這些稠腊。

2、獲取AVPlayer當前的播放進度

    CMTime ctime = self.avPlayer.currentTime;
    CGFloat currentTimeSec = ctime.value / ctime.timescale;

有了當前的播放進度鸣哀,視頻的進度條功能就可以完成架忌,很簡單,這里就不贅述了我衬。

3叹放、關于AVPlayer播放卡頓時如何獲取此時的狀態(tài)也是我遇到的難題,因為AVPlayer并沒有給出這種狀態(tài)挠羔,有人說根據(jù)AVPlayer的rate是1還是0判斷井仰,經測試這個方法不靠譜,即使卡頓時rate有時還是1破加,文章開頭連接的博文給出了一種解決辦法俱恶,可以參考下,這里大家有什么好的方法歡迎留言,感激不盡速那。

    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(upadte)];
    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

實現(xiàn)update方法

- (void)upadte
{
NSTimeInterval current = CMTimeGetSeconds(self.avPlayer.currentTime);

if (current!=self.lastTime) {
    //沒有卡頓
    NSLog(@"沒有卡頓");
}else{
    //卡頓了
    NSLog(@"卡頓了");
}
self.lastTime = current;
}

AVPlayerViewController

  • 簡介
    AVPlayerViewController是iOS9以后推出的新接口,這個接口在我看來主要就是為了iPad的畫中畫尿背,通過AVPlayerViewControllerDelegate實現(xiàn)端仰,沒有太多可以講的,AVPlayerViewController的使用與AVPlayer基本一樣田藐,這里給簡單的使用實例看下就可以了荔烧,其余的用法參考AVPlayer。
    AVPlayerViewController示例

尾巴

這里只總結了MPMoviePlayerController汽久、AVPlayer鹤竭、AVPlayerViewController3個開發(fā)流媒體常用的接口,在開發(fā)中如何選擇呢景醇,我總結了一些經驗臀稚,僅供參考。
1三痰、如果是純音頻的流媒體項目吧寺,并且最低支持的版本在iOS9以下,使用MPMoviePlayerController最合適散劫,音頻不需要考慮MPMoviePlayerController本身自定義的界面稚机,只需要播放聲音,界面我們自己布局就可以了获搏,并且獲取播放的各種狀態(tài)也要比其余兩種方便赖条。
2、有視頻需求的流媒體項目常熙,如果只是簡單的視頻需求可以使用MPMoviePlayerController纬乍,如果要深度自定義視頻播放器,建議使用AVPlayerViewController症概,用法和AVPlayer基本是一樣的蕾额,但是AVPlayerViewController的好處是可以在后續(xù)方便的實現(xiàn)畫中畫功能,后續(xù)蘋果在更新時接口時也會為AVPlayerViewController提供更多有用方便的方法和屬性彼城,方便開發(fā)者使用诅蝶。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市募壕,隨后出現(xiàn)的幾起案子调炬,更是在濱河造成了極大的恐慌,老刑警劉巖舱馅,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缰泡,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機棘钞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門缠借,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宜猜,你說我怎么就攤上這事泼返。” “怎么了姨拥?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵绅喉,是天一觀的道長。 經常有香客問我叫乌,道長柴罐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任憨奸,我火速辦了婚禮革屠,結果婚禮上,老公的妹妹穿的比我還像新娘膀藐。我一直安慰自己屠阻,他們只是感情好,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布额各。 她就那樣靜靜地躺著国觉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虾啦。 梳的紋絲不亂的頭發(fā)上麻诀,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音傲醉,去河邊找鬼蝇闭。 笑死,一個胖子當著我的面吹牛硬毕,可吹牛的內容都是我干的呻引。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吐咳,長吁一口氣:“原來是場噩夢啊……” “哼逻悠!你這毒婦竟也來了?” 一聲冷哼從身側響起韭脊,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤童谒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沪羔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饥伊,經...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了琅豆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愉豺。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖茫因,靈堂內的尸體忽然破棺而出粒氧,到底是詐尸還是另有隱情,我是刑警寧澤节腐,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站摘盆,受9級特大地震影響翼雀,放射性物質發(fā)生泄漏。R本人自食惡果不足惜孩擂,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一狼渊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧类垦,春花似錦狈邑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至砰琢,卻和暖如春蘸嘶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陪汽。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工训唱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挚冤。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓况增,卻偏偏與公主長得像,于是被迫代替她去往敵國和親训挡。 傳聞我的和親對象是個殘疾皇子澳骤,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內容