1. 程式人生 > >[轉]不用任何第三方,寫一個RTMP直播推流器

[轉]不用任何第三方,寫一個RTMP直播推流器

2016年是移動直播爆發年,不到半年的時間內無數移動直播App掀起了全民直播的熱潮。然而個人覺得直播的門檻相對較高,從推流端到服務端器到播放端,無不需要專業的技術來支撐,僅僅推流端就有不少需要學習的知識。目前大部分直播採用的都是RTMP協議,我這裡寫一個簡單的Demo,幫助大家更好的理解直播推流的過程,主要包括:音視訊採集、音視訊編碼、資料打包、RTMP協議等相關的知識等。專案結構分的很清楚,各個模組也用協議進行了分離,方便大家學習不同的模組。

先闡述下推流的整體流程:

  • 建立tcp連線

  • 建立rtmp連線,以及傳送各種控制指令

  • 獲取原始視訊資料和音訊資料

  • 對原始視訊資料和音訊資料進行壓縮編碼

  • 編碼後的視訊資料和音訊資料進行打包

  • 傳送打包後的音訊和視訊資料

專案各個類的作用

  • SGSimpleSession 是Api介面層,負責對外提供可直接呼叫的介面,同時也是一個數據分發中心,獲取到的原始音視訊資料和編碼後的資料都在這裡被分發到不同的類進行處理.

  • 視訊相關的類

1.SGVideoSource 原始視訊資料獲取類,底層用的是AVFoundation框架來實現。對外提供原始未經編碼的的視訊資料,同時提供影象預覽功能。如果需要新增美顏,攝像頭切換,翻轉,閃光燈等操作,也是在這裡處理的。

原始視訊幀:原始視訊資料其實就是一幀一幀的資料,它們沒有經過壓縮編碼,每一幀包含了影象資訊和時間資訊,我們通過程式碼提取出圖片。

fps:1s中包含的幀數就是幀速(fps),一般fps的範圍是15~30幀,幀速越高畫面越流暢,頻寬消耗量越大。實際直播中,大部分採用15到20就可以了。

解析度:一幀的影象的大小,iOS原生的有352*288,640*480,1280*720等。一般直播採用640 *480,然後裁剪為640 *360.

位元速率:也叫位元率,資料傳輸時單位時間傳送的資料位數。可以理解為位元速率決定一幀影象的顯示精細程度。在一定範圍內,位元速率越大,影象越清晰,消耗頻寬或者檔案體積就越大。超過一定範圍後,清晰度不變.一般640 * 480解析度的,位元速率512kbps就能夠保證清晰度。

2.SGVideoConfig這個視訊配置的類,主要包括壓縮等級,解析度,位元速率等的配置。

3.SGH264Encoder這個類是編碼器,主要功能是對原始的視訊幀進行編碼壓縮處理,這裡採用的是`硬編碼`,編碼輸出格式為H264格式。

編碼:編碼是指將原始的幀資料編碼壓縮,編碼後資料更小,方便在網路上傳輸。原始資料體積較大,網路傳輸十分不方便,因此需要將資料壓縮,視訊壓縮演算法當前比較主流的是H264,這裡我們壓縮格式是H264格式。H264有不同的壓縮等級,壓縮等級不同,壓縮比也不同.常見的壓縮等級有:baseline ` , `main` 和`high`.

硬編碼:硬編碼是相對軟編碼而言的,一般軟編碼是通過cpu來運算,比較消耗cpu效能,耗時大,但是相容性好,軟編碼一般採用ffmpeg或者x264。相對而言,硬編碼使用gpu來編碼,速度效率很高。這裡採用的是iOS自帶的硬解碼,只支援iOS8以後的系統。

壓縮後的視訊幀:壓縮後的視訊有三種幀型別:I ,B ,P幀,I幀也叫關鍵幀。經過解碼後能夠獨立展示出一幅影象,P幀是前向預測幀,參考前一幀才能解碼顯示出一幅完整的影象。B 為雙向預測幀,必須參考前一幀和後一幀才能解碼出影象,因此幀的壓縮比最低,大約為0.7,它只能採用幀內壓縮,P幀壓縮比次之,大概能達到0.5,B幀壓縮比則更高,達到了0.3~0.5。B幀和P幀採用的是幀內壓縮和幀間壓縮技術(也就是運動估計,原理是相鄰幀的影象有一部分是一樣的,專業術語叫空間冗餘)。實際上,視訊壓縮等級不同,幀種類也不同,比如`baseline等級`壓縮後的視訊只有I幀 和 P幀。`main等級` 和 `high等級` 則三種幀都包含,它們的整體壓縮比要比`baseline`要高。但是因為B幀需要參考前一幀和後一幀才能顯示,很容易造成卡頓情況,因為萬一後面的幀沒有獲取到,導致前一幀已也不能顯示,所以在實際應用中(直播app),一般壓縮等級採用`baseline`.

gop:這個我試著描述一下:因為除了I幀,其它幀都不能獨立渲染顯示,理論上只需要一個I幀,其它全部是非I幀,,這樣壓縮比最高,但是因為`(B幀和P幀)參考其他幀`的原因會有一定的誤差,當一段時間後,累計誤差會原來越大,導致影象失真。解決辦法就是以一小段為一個單元,每個單元第一幀都是I幀,這樣即使前面某一小段出了問題也不會影響後面的一小段,每一個小段我們稱作一個關gop。每個gop的第一幀一定是關鍵幀,因為你的沒得參考;通常我們設定gop的大小為1s到3s,因此關鍵幀與關鍵幀之間的間隔就是1s的幀數(對應gop為1s)到3s的幀數(對應gop為3s),根據上面的定義,1s的幀數為fps,因此關鍵幀間隔為1*fps 到 3*fps。秒開的優化點之一就是減小gop大小,因為gop第一幀是關鍵幀,能獨立渲染出來,使用者進入直播間的時間是隨機的,為確保使用者儘快拿到關鍵幀,儘快渲染出影象;同時gop越小,關鍵幀數量就越多,頻寬消耗量就越大。

4.SGH264Packager 這個類負責對已經編碼好的H264幀資料進行打包處理,打包成符合RTMP協議格式的資料,然後才能傳送.

  • 音訊相關類

SGAudioSource 這個類主要負責錄製音訊資料,輸出原始音訊幀,音訊的格式為PCM格式。

SGAudioConfig 這個類是音訊配置相關的類,主要包括聲道數,位元速率,取樣率的配置。

SGAACEncoder 這個類作用是將原始PCM音訊資料進行編碼壓縮,編碼結果為AAC格式的音訊資料,這裡採用的是硬編碼,軟編碼的庫有faac.

SGAACPackager 這個了類作用是將編碼後的AAC格式資料大波按成符合RTMP協議的資料。

  • RTMP相關類

`SGStreamSession`這個類主要是用來建立tcp連線,底層資料的讀取和傳送,以及連線狀態的回撥,整個連線狀態貫穿整個專案,十分重要。

`SGRtmpSession`這個類主要與RTMP相關,主要負責與伺服器互動,包括RTMP握手,指令的傳送,對資料的進一步封裝,封裝成訊息,然後再發送.指令有很多,說點重要的,比如握手完成以後,要重新協商訊息大小(預設128位元組),但是128位元組太小,影響效率,一般都稍微改大點,比如這裡設定為16kb,如果太大也不好,會導致頻寬浪費。這個類涉及到rtmp相關的比較多,比較難以理解,網上有開源的實現librtmp這個庫,可以用這個來替代。

以上就是整個專案的基本結構,整個過程類似工廠流水線,可以自行對各個模組進行替換和研究。demo中註釋也不少,方便理解。是不是感覺資訊量有點大?可能有些地方說的不嚴謹,還望大家多多指正哈。

這個專案在去年7月份左右就寫完了,後來加了一些烏七八糟的東西,後來專案掛了,轉戰新專案(還是直播)。中間寫過幾篇入門文章,本來打算寫成一個系列文章,無奈太忙了,寫的不完整。新年伊始,趁著專案不太忙,趕緊整理了一下,純碼字,如果有任何問題可以直接留言。

附上學習部落格: