iOS直播技術總結

#直播總結

##1.概述

關于直播的技術文章不少,成體系的不多。我們將用這篇文章,更系統化地介紹當下大熱的視頻直播各環節的關鍵技術,幫助視頻直播創業者們更全面、深入地了解視頻直播技術,更好地技術選型。

###1.1 一個完整的直播APP原理

`直播原理` : 把主播錄制的視頻,推流送到服務器,服務器經過處理(鑒黃等),通過CDN分發給觀眾看。

`直播環節` : 推流端(采集、美顏、編碼、推流),服務端處理(轉碼、錄制、截圖、鑒黃)、播放器(拉流、解碼、渲染)、互動系統(聊天室、禮物系統、贊)

###1.2 一個完整直播APP實現流程

`1.采集、2.濾鏡處理、3.編碼、4.推流、5.CDN分發、6.拉流、7.解碼、8.播放、9.聊天互動`

![](直播app流程.png)

###1.3 一個完整直播APP架構

`1.采集端、服務端、播放端`

![](liveApp.png)

###1.4 一個完整直播APP技術點

![](直播app技術點.jpeg)

下面我們會選擇一部分技術進行講解。

`提示`:[總結不好 圖看不清 請點這里](http://www.lxweimin.com/p/bd42bacbe4cc)

##2. 視頻采集

###2.1 基本知識介紹

`AVFundation` : 音視頻數據采集需要用AVFundation框架

`AVCaptureDevice` : 硬件設備,包括麥克風、攝像頭、通過該對象可以設置物理設備的一些屬性。例如相機焦距,白平衡等

`AVCaptureDeviceInput` : 硬件輸入對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,用于管理硬件輸入數據

`AVCaptureOutput` : 硬件輸出對象,用于接收各類輸出數據,通常使用對應的子類AVCaptureAudioDataOutput(聲音數據輸出對象), AVCaptureVideoDataOutput(視頻輸出對象)

`AVCaptureConnection` : 當把一個輸入和輸出添加到AVCaptureSession后。AVCaptureSession就會在輸出、輸出設備之間建立連接,而且通過AVCaptureOutput可以獲得這個對象

`AVCaptureVideoPreviewLayer` : 相機拍攝預覽圖層,能實時查看相機效果。創建該對象需要指定對應的AVCaptureSession對象,因為AVCaptureSession包含輸出數據,有視頻數據才能顯示。

`AVCaptureSession` : 協調輸入與輸出之間傳遞數據

###2.2 捕獲音視頻步驟

包含關系:

![](AVCaptureSession.png)

步驟:

>1.? 創建AVCaptureDevice(video或者audio)

>2.? 根據AVCaptureDevice創建AVCaptureDeviceInput。

>3.? 創建AVCaptureSession

>4.? 把創建的AVCaptureDeviceInput加入AVCaptureSession

>5.? 添加視頻預覽圖層AVCaptureVideoPreviewLayer

>6.? 創建AVCaptureAudioDataOutput,并加入AVCaptureSession

>7.? 啟動會話

官方步驟(可以忽略):

> 1. 創建AVCaptureSession對象

> 2. 獲取AVCaptureDevice錄像設備(攝像頭),錄音設備(麥克風)。只用于配置

> 3. 根據音頻/視頻硬件設備(AVCaptureDevice)創建音頻/視頻硬件輸入數據對象(AVCaptureDeviceInput),專門管理數據輸入。

> 4. 創建視頻輸出數據管理對象(AVCaptureVideoDataOutput),并且設置樣品緩存代理(setSampleBufferDelegate)就可以通過它拿到采集到的視頻數據

> 5. 創建音頻輸出數據管理對象(AVCaptureAudioDataOutput),并且設置樣品緩存代理(setSampleBufferDelegate)就可以通過它拿到采集到的音頻數據

> 6. 將數據輸入對象AVCaptureDeviceInput、數據輸出對象AVCaptureOutput添加到媒體會話管理對象AVCaptureSession中,就會自動讓音頻輸入與輸出和視頻輸入與輸出產生連接.

> 7. 創建視頻預覽圖層AVCaptureVideoPreviewLayer并指定媒體會話,添加圖層到顯示容器layer中

> 8. 啟動AVCaptureSession,只有開啟,才會開始輸入到輸出數據流傳輸

其中`AVCaptureAudioDataOutput`、`AVCaptureVideoDataOutput`包含兩個代理方法,可以一直監聽捕獲屬性。

```

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

{

if (self.videoConnection == connection)

{

NSLog(@"采集到視頻");

}

else if(self.audioConnection == connection)

{

NSLog(@"采集到音頻");

}

}

// 丟失幀會調用這里

- (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 6_0)

{

NSLog(@"丟失幀");

}

```

不清楚可以看 : [官方文檔](https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html)

###2.3 捕捉圖片

`AVCaptureStillImageOutput`可以將捕獲到的Video轉換為圖片。

> 1. 創建device

> 2. 根據device創建deviceInput

> 3. 添加deviceInput進session

> 4. 添加預覽圖層

> 5. 添加deviceOutput進session

> 6. 調用AVCaptureConnection生成圖片

###2.4 捕捉視頻

`AVCaptureMovieFileOutput` 可以將捕捉到的視頻輸出到磁盤。可以設置錄制最長時限或錄制到特定大小,還可以配置成保留最小可用磁盤空間。

> 1. 創建device

> 2. 根據device創建deviceInput

> 3. 添加deviceInput進session

> 4. 添加預覽圖層

> 5. 添加deviceOutput進session

> 6. 調用AVCaptureMovieFileOutput把視頻寫入文件

`AVCaptureMovieFileOutput`包含有幾個代理方法。分別是`視頻開始錄制`,`視頻暫停`,`視頻恢復`, `視頻將要錄制完成`, `視頻錄制完成`。

#2.5 采集音頻視頻按幀輸出流程解析

> 1.找到物理設備攝像頭_inputCamera、麥克風_microphone,創建攝像頭輸入videoInput和麥克風輸入audioInput;

>

> 2.設置videoInput和audioInput為_captureSession的輸入,同時設置videoOutput和audioOutput為_captureSession的輸出,并且設置videoOutput和audioOutput的輸出delegate;

>

> 3._captureSession調用startRunning,開始捕獲信號;

>

> 4.音頻數據到達,把數據轉發給之前設置的audioEncodingTarget,并通過調用assetWriterAudioInput的appendSampleBuffer方法寫入音頻數據;

>

> 5.視頻數據到達,視頻數據傳入響應鏈,經過處理后通過assetWriterPixelBufferInput的appendSampleBuffer方法寫入視頻數據;

>

> 6.選擇保存后,文件通過ALAssertLibrary寫入手機照片庫。

流程圖:

![](捕獲流程.png)

###2.6 Demo在這里

代碼 : [捕獲音視頻Demo](https://github.com/tiantianlan/LiveExplanation/tree/master/%E6%8D%95%E8%8E%B7%E9%9F%B3%E8%A7%86%E5%B1%8F)

##3. GPUImage

`前面好像沒看懂,可以看這里嗎?`

可以,GPUImage對AVFundation進行了一層封裝,就算你不會前面的也沒關系。

###3.1 基本概念

`GPU` 手機或者電腦用于處理圖像渲染的硬件

`OpenGL ES` 一套圖形與硬件接口,用于把處理好的圖片顯示到屏幕上。

`GPUImage` 是一個基于OpenGL ES 2.0圖像和視頻處理的開源iOS框架,提供各種各樣的圖像處理濾鏡,并且支持照相機和攝像機的實時濾鏡,內置120多種濾鏡效果,并且能夠自定義圖像濾鏡。

`GPUImage` 是一個基于OpenGL ES 2.0圖像和視頻處理的開源iOS框架,提供各種各樣的圖像處理濾鏡,并且支持照相機和攝像機的實時濾鏡,內置120多種濾鏡效果,并且能夠自定義圖像濾鏡。

`濾鏡處理的原理` 就是把靜態圖片或者視頻的每一幀進行圖形變換再顯示出來。它的本質就是像素點的坐標和顏色變化

###3.1 利用GPUImage處理直播過程中美顏流程

`采集視頻 => 獲取每一幀圖片 => 濾鏡處理 => GPUImageView展示`

![](美顏流程.png)

###3.2 處理畫面原理

GPUImage采用鏈式方式來處理畫面,通過addTarget:方法為鏈條添加每個環節的對象,處理完一個target,就會把上一個環節處理好的圖像數據傳遞下一個target去處理,稱為GPUImage處理鏈。

一般的target可以分為兩類:

`中間環節`的target,一般是指各種filter,是GPUImageFilter或者是子類

`最終環節`的target,GPUImageView 用于顯示到屏幕上或者GPUImageMovieWriter寫成視頻文件。

主要分為三個環節:

`source(視頻,圖片源) => filter(濾鏡) => final target(處理后的視頻、圖片)`

###3.3 美顏原理

`磨皮(GPUImageBilateralFilter)`:本質就是讓像素點模糊,可以使用高斯模糊,但是可能導致邊緣會不清晰,用雙邊濾波(Bilateral Filter) ,有針對性的模糊像素點,能保證邊緣不被模糊。

`美白(GPUImageBrightnessFilter)`:本質就是提高亮度。

###3.4 GPUImage源對象

GPUImage的數據源只能是4類:

`GPUImageVideoCamera` ios攝像頭的實時美顏。GPUImageVideoCamera是GPUImageOutput的子類,提供來自攝像頭的圖像數據作為源數據,一般是響應鏈的源頭。

`GPUImageStillCamera` 相機拍照

`GPUImagePicture` 處理靜止圖像

`GPUImageMovie` 電影

###3.5 用法

>1. 創建過濾器

>2. 創建源對象

>3. 把過濾器添加到源對象

>4. 生成target

靜態圖片處理:

```

UIImage *inputImage = [UIImage imageNamed:@"105"];

// 創建過濾器

GPUImageBrightnessFilter *filter = [[GPUImageBrightnessFilter alloc] init];

filter.brightness = 0.5;

[filter forceProcessingAtSize:inputImage.size];

[filter useNextFrameForImageCapture]; // 告訴系統從后來捕獲過濾器

// 處理靜止的圖像

GPUImagePicture *stillPic = [[GPUImagePicture alloc] initWithImage:inputImage];

[stillPic addTarget:filter]; //添加過濾器

[stillPic processImage]; // 執行渲染

UIImage *newImage = [filter imageFromCurrentFramebuffer];

UIImageView *imageView = [[UIImageView alloc] initWithImage:newImage];

[imageView sizeToFit];

[self.view addSubview:imageView];

imageView.center = CGPointMake(CGRectGetWidth(self.view.frame)/2, CGRectGetHeight(self.view.frame)/2);

```

實時美顏處理:

```

// 創建視頻源

GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPresetHigh cameraPosition:AVCaptureDevicePositionBack];

// 設置方向

videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;

// 創建預覽View

GPUImageView *videoPreview = [[GPUImageView alloc] initWithFrame:self.view.bounds];

[self.view insertSubview:videoPreview atIndex:0];

// 添加預覽圖層到源

GPUImageBeautifyFilter *fiter = [[GPUImageBeautifyFilter alloc] init];

[_videoCamera addTarget:fiter];

[fiter addTarget:self.videoPreview];

// 開始采集視頻

[videoCamera startCameraCapture];

```

到這里,僅僅是屏幕顯示的內容有濾鏡效果,而作為直播應用,還需要輸出帶有美顏效果的視頻流。

我們需要使用`GPUImageMovieWriter`類,才能處理視頻流。

核心思路:

通過GPUImageVideoCamera采集視頻和音頻信息,音頻信息直接發送給`GPUImageMovieWriter`,視頻信息傳入響應鏈作為源頭,渲染后的視頻再寫入`GPUImageMovieWriter`,同時通過`GPUImageView`顯示在屏幕上。只需要`addTarget`就可以添加`GPUImageMovieWriter`;

![](GPUImageMovieWriter.png)

###3.6 實例代碼在這里

[美顏的使用](https://github.com/tiantianlan/LiveExplanation/tree/master/GPUImage)

##4. 音視頻編碼,解碼

這一章太難了,以后再寫。

### VideoToolBox

### AudioToolBox

##5. 流媒體服務器

國內外有很多好用的流媒體服務區。這里為了方便搭建我們采用`nginx+RTMP`搭建流媒體服務器。

###5.1 MAC環境搭建

[MACOS上搭建nginx+rtmp環境](https://github.com/tiantianlan/LiveExplanation/blob/master/MACOS%E4%B8%8A%E6%90%AD%E5%BB%BAnginx%2Brtmp%E7%8E%AF%E5%A2%83.md)

###5.2 Centos環境搭建

[Centos下搭建的nginx + RTMP環境](https://github.com/tiantianlan/LiveExplanation/blob/master/Centos%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md)

###5.3 服務端常用技術

`CDN` 直播數據上傳到服務器后,觀看直播的人比較多,服務器是承受不了的,會將數據分發到CDN,觀眾直接去CDN獲取數據。減少服務器的負載。

`負載均衡` 由多臺服務器組成一個服務器集群,每次請求的時候,會根據服務器負載選擇處理請求的服務器。

##6. 推流

###6.1 推流協議的選擇

[HLS和RTMP](https://github.com/tiantianlan/LiveExplanation/blob/master/%E7%9B%B4%E6%92%AD%E5%8D%8F%E8%AE%AE%E7%9A%84%E9%80%89%E6%8B%A9.md)

###6.2 推流原理

在iOS設備上進行各推流的話,是通過AVCaptureSession這么一個捕捉會話,指定兩個AVCaptureDevice 也就是iOS的攝像頭和麥克風,獲取個原始視頻和音頻,然后需要進行個H.264的視頻編碼和AAC的音頻編碼,再將編碼后的數據整合成一個音視頻包,通過rmtp推送到nginx服務器

###6.3 librtmp

這個參考資料很少。不過大部分都采用的這個。

因為涉及太多C/C++這里不討論。

參考:[https://my.oschina.net/jerikc/blog/501948](https://my.oschina.net/jerikc/blog/501948)

##7. 音視頻播放

###7.1 播放框架的選擇

iOS的播放框架主要有以下三種:

>1. AVPlayer 可以播放本地、遠程視頻,可以自定義UI進行控制

>2. AVPlayerViewController 自帶播放控制UI,不能自定義UI

>3. MPMoviePlayerController,MPMoviePlayerViewController (iOS9后棄用)

如果只是簡單的播放視頻,選擇`AVPlayerViewController`,如果想自定義播放器,選擇`AVPlayer`。

###7.2 AVPlayer

AVPlayer是一個用來播放基于時間的流媒體控制對象。支持播放從本地、分布下載或通過HTTP Live Streaming協議得到的流媒體。

AVPlayer只管理一個單獨資源的播放,不過框架還提供了AVPlayer的一個子類AVQueuePlayer,可以用來管理一個資源隊列。當你需要在一個序列中播放多個條目或者為音頻、視頻資源設置播放循環時可以使用該子類。

AVPlayer視頻播放使用步驟:

>1. 創建視頻資源地址URL,可以是網絡URL

>2. 通過URL創建視頻內容對象`AVPlayerItem`,一個視頻對應一個`AVPlayerItem`

>3. 創建`AVPlayer`視頻播放對象,需要一個`AVPlayerItem`進行初始化

>4. 創建`AVPlayerLayer`播放圖層對象,添加到現實視圖上去

>5. 添加KVO監聽。 監聽到AVPlayerItemStatusReadyToPlay的時候調用play方法

[AVPlayer的使用](https://github.com/tiantianlan/LiveExplanation/tree/master/AVPlayer)

###7.3 AVPlayerViewController

`AVPlayerViewController`屬于`AV Kit`,它是`UIViewController的子類`,用于展示并控制AVPlayer實例的播放。

`AVPlayerViewController `類使用步驟

>1. 創建URL

>2. 創建AVPlayerViewController,并根據URL設置player屬性

>3. 調用play方法

[AVPlayerViewController的使用](https://github.com/tiantianlan/LiveExplanation/tree/master/AVKit)

Xcode8模擬器可能有問題,打開播放不了。

###8.開源框架

前面所講都有第三方框架支持。采集、美顏、推流有`LFLiveKit`, 拉流播放有`IJKMediaFramework`。

[`LFLiveKit`](https://github.com/LaiFengiOS/LFLiveKit) : LFLiveKit是iOS版開源RTMP流SDK。他支持后臺錄制、美顏功能、支持h264、AAC硬編碼,動態改變速率,RTMP傳輸等

[`IJKMediaFramework`](https://github.com/Bilibili/ijkplayer) : ijkplayer是B站開源的一款視頻直播框架,它是基于ffmpeg。 如果從github下載是需要編譯。參考地址:[http://www.lxweimin.com/p/1f06b27b3ac0](http://www.lxweimin.com/p/1f06b27b3ac0)

個人實驗只需要配置Nginx+RTMP服務

這里我采用這兩個第三方框架寫了一個直播,包含在線觀看直播,和直播推流,支持在線美顏,前后攝像頭切換等你需要:

>1. 搭建`Nginx+RTMP環境`:[MAC](https://github.com/tiantianlan/LiveExplanation/blob/master/MACOS%E4%B8%8A%E6%90%AD%E5%BB%BAnginx%2Brtmp%E7%8E%AF%E5%A2%83.md) 或者? [Centos](https://github.com/tiantianlan/LiveExplanation/blob/master/Centos%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md)

>2. 下載項目真機運行。[https://github.com/tiantianlan/miaoboDemo](https://github.com/tiantianlan/miaoboDemo)

登陸界面

![](miaobo1.png)

主頁

![](miaobo2.png)

直播頁面

![](miaobo3.png)

參考文章:

>1. [知乎 如何搭建一個完整的直播系統](https://www.zhihu.com/question/42162310)

>2. [袁崢技術博客](http://www.lxweimin.com/users/b09c3959ab3b/latest_articles)

>3. [GPUImage 基于GPU加速的圖形和視頻處理庫](http://www.ios122.com/2015/08/gpuimage/)

>

>4. [iOS中為直播APP集成美顏功能](http://news.h5.com.cn/ios/49696.html)

>

>5. [iOS視頻直播~推流、拉流原理](http://www.lxweimin.com/p/e516a5b31480)

>

>6. [關于視頻直播技術,你想要知道的都在這里了](http://www.lxweimin.com/p/ddb640ac4fec)

>

>7. [macOS上搭建Nginx+rtmp服務器](https://www.xsd.me/mac_nginx_rtmp_server.html)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容