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 為雙向預測幀,必須參考前一幀和後一幀才能解碼出圖像.因此,I幀的壓縮比最低,大約為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月份左右就寫完了,後來加了一些烏七八糟的東西,後來項目掛了,轉戰新項目(還是直播).中間寫過幾篇入門文章,本來打算寫成一個系列文章,無奈太忙了,寫的不完整.新年伊始,趁著項目不太忙,趕緊整理了一下,純碼字,如果有任何問題可以直接留言.
附上完整的代碼:https://github.com/iOSSinger/SGLivingPublisher
附上個人博客:http://www.jianshu.com/u/7246ea6d05dd
附上RTMP中文文檔:https://raw.githubusercontent.com/iOSSinger/SGLivingPublisher/master/RTMP.docx
附上學習博客:
雷曉華博士的博客:這個是非常好的視音頻開發技術文章,喜歡視音頻的可以看看http://blog.csdn.net/leixiaohua1020
硬編碼的詳細說明:http://www.jianshu.com/p/a6530fa46a88