2016年是移動(dòng)直播爆發(fā)年,不到半年的時(shí)間內(nèi)無(wú)數(shù)移動(dòng)直播App掀起了全民直播的熱潮。然而個(gè)人覺得直播的門檻相對(duì)較高,從推流端到服務(wù)端器到播放端,無(wú)不需要專業(yè)的技術(shù)來(lái)支撐,僅僅推流端就有不少需要學(xué)習(xí)的知識(shí).目前大部分直播采用的都是RTMP協(xié)議,我這里寫一個(gè)簡(jiǎn)單的Demo,幫助大家更好的理解直播推流的過(guò)程,主要包括:音視頻采集, 音視頻編碼, 數(shù)據(jù)打包, RTMP協(xié)議等相關(guān)的知識(shí)等.項(xiàng)目結(jié)構(gòu)分的很清楚,各個(gè)模塊也用協(xié)議進(jìn)行了分離,方便大家學(xué)習(xí)不同的模塊.
先闡述下推流的整體流程:
- 建立tcp連接
- 建立rtmp連接,以及發(fā)送各種控制指令
- 獲取原始視頻數(shù)據(jù)和音頻數(shù)據(jù)
- 對(duì)原始視頻數(shù)據(jù)和音頻數(shù)據(jù)進(jìn)行壓縮編碼
- 對(duì)編碼后的視頻數(shù)據(jù)和音頻數(shù)據(jù)進(jìn)行打包
- 發(fā)送打包后的音頻和視頻數(shù)據(jù)
項(xiàng)目各個(gè)類的作用
SGSimpleSession
是Api接口層,負(fù)責(zé)對(duì)外提供可直接調(diào)用的接口,同時(shí)也是一個(gè)數(shù)據(jù)分發(fā)中心,獲取到的原始音視頻數(shù)據(jù)和編碼后的數(shù)據(jù)都在這里被分發(fā)到不同的類進(jìn)行處理.-
視頻相關(guān)的類
-
SGVideoSource
原始視頻數(shù)據(jù)獲取類,底層用的是AVFoundation框架來(lái)實(shí)現(xiàn).對(duì)外提供原始未經(jīng)編碼的的視頻數(shù)據(jù),同時(shí)提供圖像預(yù)覽功能.如果需要添加美顏,攝像頭切換,翻轉(zhuǎn),閃光燈等操作,也是在這里處理的.原始視頻幀
: 原始視頻數(shù)據(jù)其實(shí)就是一幀一幀的數(shù)據(jù),它們沒有經(jīng)過(guò)壓縮編碼,每一幀包含了圖像信息和時(shí)間信息,我們通過(guò)代碼提取出圖片.fps
:1s中包含的幀數(shù)就是幀速(fps),一般fps的范圍是15~30幀,幀速越高畫面越流暢,帶寬消耗量越大.實(shí)際直播中,大部分采用15到20就可以了.分辨率
: 一幀的圖像的大小,iOS原生的有352*288,640*480,1280*720等,一般直播采用640 *480,然后裁剪為640 *360.碼率
: 也叫比特率,數(shù)據(jù)傳輸時(shí)單位時(shí)間傳送的數(shù)據(jù)位數(shù). 可以理解為碼率決定一幀圖像的顯示精細(xì)程度.在一定范圍內(nèi),碼率越大,圖像越清晰,消耗帶寬或者文件體積就越大.超過(guò)一定范圍后,清晰度不變.一般640 * 480分辨率的,碼率512kbps就能夠保證清晰度. SGVideoConfig
這個(gè)視頻配置的類,主要包括壓縮等級(jí),分辨率,碼率等的配置-
SGH264Encoder
這個(gè)類是編碼器,主要功能是對(duì)原始的視頻幀進(jìn)行編碼壓縮處理,這里采用的是硬編碼
,編碼輸出格式為H264格式.編碼
: 編碼是指將原始的幀數(shù)據(jù)編碼壓縮,編碼后數(shù)據(jù)更小,方便在網(wǎng)絡(luò)上傳輸.原始數(shù)據(jù)體積較大,網(wǎng)絡(luò)傳輸十分不方便,因此需要將數(shù)據(jù)壓縮,視頻壓縮算法當(dāng)前比較主流的是H264,這里我們壓縮格式是H264格式.H264有不同的壓縮等級(jí),壓縮等級(jí)不同,壓縮比也不同.常見的壓縮等級(jí)有:baseline
,main
,high
.硬編碼
: 硬編碼是相對(duì)軟編碼而言的,一般軟編碼是通過(guò)cpu來(lái)運(yùn)算,比較消耗cpu性能,耗時(shí)大,但是兼容性好,軟編碼一般采用ffmpeg或者x264.相對(duì)而言,硬編碼使用gpu來(lái)編碼,速度效率很高.這里采用的是iOS自帶的硬解碼,只支持iOS8以后的系統(tǒng).壓縮后的視頻幀
: 壓縮后的視頻有三種幀類型:I ,B ,P幀,I幀也叫關(guān)鍵幀.經(jīng)過(guò)解碼后能夠獨(dú)立展示出一幅圖像,P幀是前向預(yù)測(cè)幀,參考前一幀才能解碼顯示出一幅完整的圖像.B 為雙向預(yù)測(cè)幀,必須參考前一幀和后一幀才能解碼出圖像.因此,I幀的壓縮比最低,大約為0.7,它只能采用幀內(nèi)壓縮,P幀壓縮比次之,大概能達(dá)到0.5,B幀壓縮比則更高,達(dá)到了0.3~0.5,B幀和P幀采用的是幀內(nèi)壓縮和幀間壓縮技術(shù)(也就是運(yùn)動(dòng)估計(jì),原理是相鄰幀的圖像有一部分是一樣的,專業(yè)術(shù)語(yǔ)叫空間冗余).實(shí)際上,視頻壓縮等級(jí)不同,幀種類也不同,比如baseline等級(jí)
壓縮后的視頻只有I幀 和 P幀.main等級(jí)
和high等級(jí)
則三種幀都包含,它們的整體壓縮比要比baseline
要高.但是因?yàn)锽幀需要參考前一幀和后一幀才能顯示,很容易造成卡頓情況,因?yàn)槿f(wàn)一后面的幀沒有獲取到,導(dǎo)致前一幀已也不能顯示,所以在實(shí)際應(yīng)用中(直播app),一般壓縮等級(jí)采用baseline
.gop
: 這個(gè)我試著描述一下:因?yàn)槌薎幀,其它幀都不能獨(dú)立渲染顯示,理論上只需要一個(gè)I幀其它全部是非I幀,這樣壓縮比最高,但是因?yàn)?code>(B幀和P幀)參考其他幀的原因會(huì)有一定的誤差,當(dāng)一段時(shí)間后,累計(jì)誤差會(huì)原來(lái)越大,導(dǎo)致圖像失真.解決辦法就是以一小段為一個(gè)單元,每個(gè)單元第一幀都是I幀;這樣,即使前面某一小段出了問(wèn)題也不會(huì)影響后面的一小段,每一個(gè)小段我們稱作一個(gè)關(guān)gop.每個(gè)gop的第一幀一定是關(guān)鍵幀,因?yàn)槟愕臎]得參考;通常我們?cè)O(shè)置gop的大小為1s到3s,因此關(guān)鍵幀與關(guān)鍵幀之間的間隔就是1s的幀數(shù)(對(duì)應(yīng)gop為1s)到3s的幀數(shù)(對(duì)應(yīng)gop為3s),根據(jù)上面的定義,1s的幀數(shù)為fps,因此關(guān)鍵幀間隔為1*fps 到 3*fps.秒開的優(yōu)化點(diǎn)之一就是減小gop大小,因?yàn)間op第一幀是關(guān)鍵幀,能獨(dú)立渲染出來(lái),用戶進(jìn)入直播間的時(shí)間是隨機(jī)的,為確保用戶盡快拿到關(guān)鍵幀,盡快渲染出圖像;同時(shí)gop越小,關(guān)鍵幀數(shù)量就越多,帶寬消耗量就越大. SGH264Packager
這個(gè)類負(fù)責(zé)對(duì)已經(jīng)編碼好的H264幀數(shù)據(jù)進(jìn)行打包處理,打包成符合RTMP協(xié)議格式的數(shù)據(jù),然后才能發(fā)送.
-
-
音頻相關(guān)類
SGAudioSource
這個(gè)類主要負(fù)責(zé)錄制音頻數(shù)據(jù),輸出原始音頻幀,音頻的格式為PCM格式.SGAudioConfig
這個(gè)類是音頻配置相關(guān)的類,主要包括聲道數(shù),碼率,采樣率的配置.SGAACEncoder
這個(gè)類作用是將原始PCM音頻數(shù)據(jù)進(jìn)行編碼壓縮,編碼結(jié)果為AAC格式的音頻數(shù)據(jù),這里采用的是硬編碼.軟編碼的庫(kù)有faac.SGAACPackager
這個(gè)了類作用是將編碼后的AAC格式數(shù)據(jù)大波按成符合RTMP協(xié)議的數(shù)據(jù).
-
RTMP相關(guān)類
-
SGStreamSession
這個(gè)類主要是用來(lái)建立tcp連接,底層數(shù)據(jù)的讀取和發(fā)送,以及連接狀態(tài)的回調(diào),整個(gè)連接狀態(tài)貫穿整個(gè)項(xiàng)目,十分重要. -
SGRtmpSession
這個(gè)類主要與RTMP相關(guān),主要負(fù)責(zé)與服務(wù)器交互,包括RTMP握手,指令的發(fā)送,對(duì)數(shù)據(jù)的進(jìn)一步封裝,封裝成消息,然后再發(fā)送.指令有很多,說(shuō)點(diǎn)重要的,比如握手完成以后,要重新協(xié)商消息大小(默認(rèn)128字節(jié)),但是128字節(jié)太小,影響效率,一般都稍微改大點(diǎn),比如這里設(shè)置為16kb,如果太大也不好,會(huì)導(dǎo)致帶寬浪費(fèi).這個(gè)類涉及到rtmp相關(guān)的比較多,比較難以理解,網(wǎng)上有開源的實(shí)現(xiàn)librtmp這個(gè)庫(kù),可以用這個(gè)來(lái)替代.
-
以上就是整個(gè)項(xiàng)目的基本結(jié)構(gòu),整個(gè)過(guò)程類似工廠流水線,可以自行對(duì)各個(gè)模塊進(jìn)行替換和研究.demo中注釋也不少,方便理解.是不是感覺信息量有點(diǎn)大?可能有些地方說(shuō)的不嚴(yán)謹(jǐn),還望大家多多指正哈.
這個(gè)項(xiàng)目在去年7月份左右就寫完了,后來(lái)加了一些烏七八糟的東西,后來(lái)項(xiàng)目掛了,轉(zhuǎn)戰(zhàn)新項(xiàng)目(還是直播).中間寫過(guò)幾篇入門文章,本來(lái)打算寫成一個(gè)系列文章,無(wú)奈太忙了,寫的不完整.新年伊始,趁著項(xiàng)目不太忙,趕緊整理了一下,純碼字,如果有任何問(wèn)題可以直接留言.
- 附上完整的代碼:https://github.com/iOSSinger/SGLivingPublisher
- 附上個(gè)人博客:http://www.reibang.com/u/7246ea6d05dd
- 附上RTMP中文文檔:https://raw.githubusercontent.com/iOSSinger/SGLivingPublisher/master/RTMP.docx
附上學(xué)習(xí)博客:
雷曉華博士的博客:這個(gè)是非常好的視音頻開發(fā)技術(shù)文章,喜歡視音頻的可以看看http://blog.csdn.net/leixiaohua1020
硬編碼的詳細(xì)說(shuō)明:http://www.reibang.com/p/a6530fa46a88