iOS直播開播端概述
前言
- 好長時間沒寫文章,可能排版不是很美觀。
- 此係列文章是我對自己最近所學技術的總結和沉澱,設計到的一些技術點和實現方案並不一定是最好,如有不同意見可以在評論區留言共同探討以及學習。
- 此係列文章內容大都是根據我的理解進行描述,可能大白話比較多。
- 下面直接進入正題。
我所理解的開播
在我的理解中,開播的整個過程在技術實現上可以理解為2條(音訊 & 視訊)流水線。
這2條流水線可以劃分為相同的5個階段,即:採集、業務處理、渲染、編碼、推流
,其中 業務處理
階段即是我們實現App開播業務邏輯的階段,這個階段的複雜度跟業務的複雜度相關。
下面對視訊和音訊的這5個階段分別進行講解。
視訊
基礎知識概念
視訊流水線上面流動到各個階段的“物品”是什麼?
``
並不是一段視訊,而是一幀一幀的影象。至於影象也只是一個抽象概念,在各階段可能會有各種不同的表現形式,如:
* 圖片:UIImage,CIImage,CGImage 等。
* 畫素資料:CVBuffer/CVImageBuffer/CVPixelBuffer,檢視系統原始碼可以發現這3種其實是同一種類型,只是通過
typedef`重新命名了而已,所以遇到了不要慌。
* 紋理:GLTexture(OpenGLES),MTLTexture(Metal)。
以上3種影象表現形式之間都可以相互轉化,具體的轉化方法可以百度。
OpenGLES / Metal 是什麼?
OpenGLES 和 Metal都是用來驅動GPU做影象處理的框架。
OpenGLES是Apple對OpenGL進行封裝,使其能夠在iOS系統使用。
Metal是Apple針對現代化GPU裝置設計的新版影象處理框架,並且採用面向物件的思想進行封裝。建議使用Metal。
當然,這兩者在使用上非常相似,你只要會其中一個,那麼另一個對你來說也就不難了。
但你至少得會一個😂
如果都不會,我建議直接學Metal,具體怎麼學?傳送門 研究研究,研究明白就學會了。
```
採集
此階段要做的就是每隔一段時間輸出一個影象(一般是CVPixelBuffer)交給下一階段處理。
一般來說,常用的視訊採集型別有以下幾種:
* 攝像頭:開啟攝像頭採集視訊幀,可以使用系統庫AVFoundation的AVCaptureSession實現此功能。
* 靜態圖片:由App設定一張圖片(UIImage等),在此採集類中將UIImage轉化成CVPixelBuffer並以自定義的頻率輸出。
* 視訊:由App設定一個視訊檔案(mp4等),可以使用系統庫AVFoundation解碼並讀取視訊的每一幀CVPixelBuffer輸出即可。
業務處理
此階段和其他階段不同,它不是像採集這樣具體的功能,而是多個子階段
的組合,而這些子階段
則是根據具體的App業務實現的。
以我們這個直播軟體的業務來說,子階段
主要包括:
* 美顏:接收當前主播的影象紋理,輸出新增美顏效果後的影象紋理。
* PK合流:接收當前主播的影象紋理 和 對方主播的影象紋理,通過OpenGLES/Metal將兩個紋理合併成一個紋理並輸出。
* 趣味連麥:接收當前主播的影象紋理 和 指定趣味資源圖片的影象紋理,通過OpenGLES/Metal將兩個紋理合併成一個紋理並輸出。
當主播處於非PK態的業務場景時,這一階段就只需要 美顏 處理即可;
當主播處於PK態的業務場景時,這一階段就需要 美顏+PK合流 組合起來;
當主播處於趣味連麥PK態的業務場景時,這一階段就需要 美顏+趣味連麥+PK合流 組合到一起。
註解: 1. 美顏階段細分的話又可以分為其他幾個子階段,比如人臉識別、磨皮、妝容、掛件等幾個階段,但因為我們這個直播軟體美顏是接入的第三方SDK,這裡就不再具體分析美顏的子階段了。後面另起文章專門講解美顏的實現吧。 2. PK合流和趣味連麥的實現基本一致,不同的只是片選著色器的程式碼中定義的紋理合並規則不同。(PK合流是將畫面分別繪製在輸出紋理的左右兩邊,趣味連麥合流是將畫面繪製在上下兩層) 3. PK合流中 對方主播的影象紋理,我們是通過接入的第三方視訊通話SDK中的回撥 獲取到的。
渲染
此階段要做的就是接收一個影象紋理,通過OpenGLES/Metal將紋理繪製到CAEAGLLayer/MTKView上。
很簡單,就幾十行程式碼,找個demo抄一下或者自己寫都行。
編碼
編碼說直白點就是將視訊幀壓縮,至於H.264和H.265等等就是一種壓縮演算法。
- 為什麼一定要編碼?
稍微計算一下 假設採集階段採集的視訊幀大小是`720 * 1280`,CVPixelBuffer的畫素格式是BGRA,幀率是30。 則每秒鐘需要傳送的資料量至少是`720 * 1280 * 4 * 30`位元組,約等於105M,使用者的手機網速必須達到105M/s才能正常直播,顯然這是非常不合理的。
- 如何實現視訊編碼?
可以使用iOS系統庫VideoToolBox編碼,設定好幀間隔,位元速率,視訊大小,壓縮演算法等引數,然後傳視訊幀進去就好了。 (機械,嘎嘎,機械,我只是一個沒有感情的API呼叫機器)
這裡只介紹了編碼是什麼,以及使用什麼工具去實現它,至於具體的壓縮原理以後再另起一篇文章細說吧,如果讀者好奇,可以自行去查詢相關資料,網上一大堆。
推流
這個階段就是流水線的終點了。在主播開播的時候就要和服務端建立長連結通道,當收到編碼壓縮後的視訊幀時,將視訊幀的二進位制資料通過長連線通道傳送給服務端。
長連線有多種協議型別,我們目前採用的是RTMP協議推流,當然還有其他種類,具體使用什麼協議由你們和自己的服務端商定。
如何實現?
一般這種通用的長連線協議,都是有人封裝好了程式碼庫的。要不,,,從github上找找?
音訊
音訊流水線和視訊流水線在階段上差不多,沒有視訊處理起來那麼麻煩,但是需要了解一些音訊資料結構相關的知識。
採集
此階段通過麥克風錄製聲音並將聲音儲存為二進位制資料輸出交給下一階段處理。
如何實現?
使用系統庫AVFoundation 或 AudioUnit。
業務處理
此階段可以根據不同的業務對音訊資料做一些處理
1. 音效:蘿莉音、大叔音、機械音等。可以通過一些演算法對二進位制資料修改,進而就可以達到改變音色的效果。(也有一些第三方的程式碼庫)
- 混音:將多路音訊資料混合成一路音訊資料並輸出,PK業務中會使用。 ``` 這裡有兩種混音方案:
- 系統庫:系統提供了音訊混合的API,學習怎麼呼叫即可。
- 演算法:音訊混合演算法 ```
渲染
音訊的渲染實際上就是音訊的播放
實現方案:還是呼叫系統API,沒什麼可說的。
編碼
和視訊一樣,編碼實質上就是用了壓縮資料量的,雖然音訊資料量沒視訊那麼大,但是能少一點是一點 實現方案:還是呼叫系統API,沒什麼可說的。
推流
和視訊的推流一樣,將編碼後的二進位制資料通過長連線傳送給服務端
- 音視訊推流的時候最好做一下時間戳對齊,以防止畫面和聲音對不上的情況出現。
- 網路環境不好的時候。可以降低編碼的位元速率,使畫面變模糊,網路環境好時再恢復;也可以選擇性的丟棄掉一些幀。
總結
本篇文章簡要的介紹了開播端技術實現上的階段和概念,並針對每個階段提供了一些實現的方案。
整理一下,我們可以發現,開播最難的地方其實是業務處理
階段。因為其他的階段,功能實現完後面基本上不會有什麼變更了,而且這些階段的實現方案大部分都是基於系統庫api就可以實現,不用去找第三方的程式碼庫。
說業務處理
階段難,但其實它也不是很難,根據不同的業務場景去拼接子階段
就好了。
最後
碼字不易,本文地址:https://juejin.cn/post/7180739989821456443