https://www.cnblogs.com/haibindev/archive/2011/12/29/2305712.html
C++實(shí)現(xiàn)RTMP協(xié)議發(fā)送H.264編碼及AAC編碼的音視頻郊闯,攝像頭直播
C++實(shí)現(xiàn)RTMP協(xié)議發(fā)送H.264編碼及AAC編碼的音視頻
RTMP(Real Time Messaging Protocol)是專(zhuān)門(mén)用來(lái)傳輸音視頻數(shù)據(jù)的流媒體協(xié)議妻献,最初由Macromedia 公司創(chuàng)建,后來(lái)歸Adobe公司所有团赁,是一種私有協(xié)議育拨,主要用來(lái)聯(lián)系Flash Player和RtmpServer,如FMS, Red5, crtmpserver等欢摄。RTMP協(xié)議可用于實(shí)現(xiàn)直播熬丧、點(diǎn)播應(yīng)用,通過(guò)FMLE(Flash Media Live Encoder)推送音視頻數(shù)據(jù)至RtmpServer怀挠,可實(shí)現(xiàn)攝像頭實(shí)時(shí)直播析蝴。不過(guò),畢竟FMLE應(yīng)用范圍有限绿淋,想要把它嵌入到自己的程序中闷畸,還是要自己來(lái)實(shí)現(xiàn)RTMP協(xié)議的推送。本人實(shí)現(xiàn)了一個(gè)RTMPLiveEncoder吞滞,通過(guò)采集攝像頭視頻和麥克風(fēng)音頻佑菩,并進(jìn)行H.264和AAC編碼盾沫,然后發(fā)送到FMS和crtmpserver上,實(shí)現(xiàn)實(shí)時(shí)直播殿漠,可以通過(guò)flash player正常觀看赴精,目前效果良好,延遲時(shí)間在2秒左右绞幌。本文就介紹一下RTMPLiveEncoder的主要思路和關(guān)鍵點(diǎn)蕾哟,以期對(duì)需要這方面技術(shù)的朋友有所幫助。
技術(shù)分析
要實(shí)現(xiàn)RTMPLiveEncoder啊奄,需要以下四種關(guān)鍵技術(shù):
- 采集攝像頭視頻和麥克風(fēng)音頻
- H264編碼和AAC編碼
- 視頻和音頻數(shù)據(jù)封裝為可被流媒體服務(wù)器識(shí)別的可播放流
- RTMP協(xié)議實(shí)現(xiàn)報(bào)文發(fā)送
其中渐苏,前兩項(xiàng)技術(shù)在我之前的文章“采集音頻和攝像頭視頻并實(shí)時(shí)H264編碼和AAC編碼”中已經(jīng)介紹過(guò)了,這里就不再啰嗦了菇夸。
把音視頻數(shù)據(jù)封裝為可播放流琼富,這個(gè)是一個(gè)難點(diǎn)。仔細(xì)研究一下庄新,你會(huì)發(fā)現(xiàn)鞠眉,RTMP Packet中封裝的音視頻數(shù)據(jù)流,其實(shí)和FLV封裝音頻和視頻數(shù)據(jù)的方式是相同的择诈,所以械蹋,我們只需要按照FLV封裝H264和AAC的方式,即可生成可播放流羞芍。
我們?cè)倏匆幌翿TMP協(xié)議哗戈。Adobe曾經(jīng)發(fā)布過(guò)一份文檔《RTMP Specification》,不過(guò)wikipedia指出這份文檔隱藏了很多細(xì)節(jié)荷科,單獨(dú)根據(jù)它是無(wú)法正確實(shí)現(xiàn)RTMP的唯咬。不過(guò),它還是有參考意義的畏浆。其實(shí)Adobe發(fā)布之前胆胰,RTMP協(xié)議就已經(jīng)被破解的差不多了,現(xiàn)在也已經(jīng)有比較完善的實(shí)現(xiàn)刻获,比如:RTMPDump蜀涨,它提供的是C語(yǔ)言的接口,這意味著可以很方便的在其他語(yǔ)言中調(diào)用蝎毡。
程序框架
與我之前寫(xiě)的“采集音頻和攝像頭視頻并實(shí)時(shí)H264編碼和AAC編碼”這篇文章相同厚柳,采用DirectShow技術(shù)來(lái)實(shí)現(xiàn)音視頻采集,音頻編碼和視頻編碼顶掉,在各自線(xiàn)程(AudioEncoderThread和VideoEncoderThread)中循環(huán)進(jìn)行草娜,RTMP的推送另起一個(gè)線(xiàn)程(RtmpThread)。兩個(gè)編碼線(xiàn)程實(shí)時(shí)編碼音視頻數(shù)據(jù)后痒筒,將數(shù)據(jù)交與Rtmp線(xiàn)程,由Rtmp線(xiàn)程循環(huán)封裝為Rtmp Packet,然后發(fā)出去簿透。
線(xiàn)程之間的數(shù)據(jù)交換移袍,通過(guò)一個(gè)隊(duì)列DataBufferQueue來(lái)實(shí)現(xiàn)。AudioEncoderThread和VideoEncoderThread把數(shù)據(jù)指針post到DataBufferQueue之后老充,立即返回葡盗,這樣就可以避免因?yàn)榘l(fā)送Rtmp報(bào)文的而影響到編碼線(xiàn)程的正常執(zhí)行時(shí)間。
![image](https://upload-images.jianshu.io/upload_images/14807846-400c6dc91a09deb0.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
RtmpThread的主要工作就是發(fā)送音頻數(shù)據(jù)流的解碼信息頭和視頻數(shù)據(jù)流的解碼信息頭啡浊,并不斷從DataBufferQueue中取出數(shù)據(jù)觅够,封裝為RTMP Packet,發(fā)送出去巷嚣。流程如下列代碼所示:(process_buf_queue_喘先,即是上圖中的DataBufferQueue)
librtmp
一、編譯librtmp
下載rtmpdump的代碼廷粒,你會(huì)發(fā)現(xiàn)窘拯,它是一個(gè)地道的linux項(xiàng)目,除了一個(gè)簡(jiǎn)單的Makefile坝茎,其他什么都沒(méi)有涤姊。好像librtmp不依賴(lài)于系統(tǒng),我們可以不用費(fèi)太多功夫嗤放,把它在windows上編譯思喊。不過(guò),librtmp依賴(lài)于openssl和zlib次酌,我們需要首先編譯好它們恨课。
1. 編譯openssl1.0.0e
a) 下載并安裝ActivePerl
b) 下載并安裝nasm(http://nasm.sourceforge.net/)
c) 解壓openssl壓縮包
d) 運(yùn)行cmd命令行,切到openssl目錄和措,分別執(zhí)行以下命令
<pre style="margin: 15px 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(81, 98, 114); font-family: "Courier New" !important; font-size: 12px !important;">>perl Configure VC-WIN32 --prefix=c:\some\dir
ms\do_nasm</pre>
e) 運(yùn)行Visual Studio Command Prompt(2010)庄呈,切到openssl目錄,分別執(zhí)行以下命令派阱。
<pre style="margin: 15px 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(81, 98, 114); font-family: "Courier New" !important; font-size: 12px !important;">>nmake -f ms\nt.mak
nmake -f ms\nt.mak install</pre>
f) 編譯完畢后诬留,即可在第一個(gè)命令所指定的目錄下發(fā)現(xiàn)編譯好的sdk。
2. 編譯zlib
a) 解壓zlib壓縮包
b) 運(yùn)行Visual Studio Command Prompt(2010)贫母,切到openssl目錄文兑,分別執(zhí)行以下命令
<pre style="margin: 15px 0px; white-space: pre-wrap; overflow-wrap: break-word; color: rgb(81, 98, 114); font-family: "Courier New" !important; font-size: 12px !important;">>cd contrib\masmx86
bld_ml32.bat</pre>
c) 回到zlib目錄,進(jìn)入contrib\vstudio\vc10目錄腺劣,打開(kāi)vs2010解決方案文件绿贞,
在zlibstat工程屬性中,去掉預(yù)編譯宏 ZLIB_WINAPI
d) 選擇debug或release編譯即可
3. 編譯librtmp
a) 首先打開(kāi)visual studio 2010橘原,新建一個(gè)win32 console工程籍铁,指定為靜態(tài)鏈接庫(kù)
b) 將librtmp的代碼導(dǎo)入工程涡上,把openssl、zlib的頭文件和librtmp放在一起拒名,把編譯好的openssl和zlib的靜態(tài)庫(kù)放在一起
![image](https://upload-images.jianshu.io/upload_images/14807846-5338b3c3ec00743b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image](https://upload-images.jianshu.io/upload_images/14807846-670e5ceddd7c59c5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
c) 在工程設(shè)置中吩愧,添加之前編譯好的openssl和zlib的庫(kù),編譯即可增显。
![image](https://upload-images.jianshu.io/upload_images/14807846-d9882121d6fc4be0.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
二雁佳、librtmp的使用
首先初始化RTMP結(jié)構(gòu)
開(kāi)始之后,就要向RTMP Server發(fā)起握手連接報(bào)文
連接成功同云,就可以開(kāi)始循環(huán)發(fā)送報(bào)文了糖权,這里需要指定時(shí)戳和數(shù)據(jù)類(lèi)型(Audio、Video炸站、Metadata)星澳。這里有一點(diǎn)需要注意的是,在調(diào)用Send之前武契,buf中的數(shù)據(jù)募判,必須是已經(jīng)封裝好的H264或AAC數(shù)據(jù)流。
關(guān)閉
最后是釋放
H264和AAC數(shù)據(jù)流
本文提到過(guò)咒唆,RTMP推送的音視頻流的封裝形式和FLV格式相似届垫,由此可知,向FMS推送H264和AAC直播流全释,需要首先發(fā)送"AVC sequence header"和"AAC sequence header"装处,這兩項(xiàng)數(shù)據(jù)包含的是重要的編碼信息,沒(méi)有它們浸船,解碼器將無(wú)法解碼妄迁。
AVC sequence header就是AVCDecoderConfigurationRecord結(jié)構(gòu),該結(jié)構(gòu)在標(biāo)準(zhǔn)文檔“ISO-14496-15 AVC file format”中有詳細(xì)說(shuō)明李命。
![image](https://upload-images.jianshu.io/upload_images/14807846-1d0e6f0aa9b432ae.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
AAC sequence header存放的是AudioSpecificConfig結(jié)構(gòu)登淘,該結(jié)構(gòu)則在“ISO-14496-3 Audio”中描述。AudioSpecificConfig結(jié)構(gòu)的描述非常復(fù)雜封字,這里我做一下簡(jiǎn)化黔州,事先設(shè)定要將要編碼的音頻格式,其中阔籽,選擇"AAC-LC"為音頻編碼流妻,音頻采樣率為44100,于是AudioSpecificConfig簡(jiǎn)化為下表:
![image](https://upload-images.jianshu.io/upload_images/14807846-37b602840c196c3b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這樣笆制,AVC sequence header和AAC sequence header的內(nèi)容可以基本確定了绅这,更詳細(xì)的信息,大家可以去翻閱相關(guān)文檔在辆。
運(yùn)行效果
RtmpLiveEncoder開(kāi)始運(yùn)行
![image](https://upload-images.jianshu.io/upload_images/14807846-01ac1007bb9081a5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
用FMS自帶的一個(gè)flash播放器播放
![image](https://upload-images.jianshu.io/upload_images/14807846-5189507b7f4a86c1.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)