FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法
From:?http://www.cnweblog.com/fly2700/archive/2012/02/23/319718.html
RFC3984是H.264的baseline碼流在RTP方式下傳輸?shù)囊?guī)范,這里只討論FU-A分包方式,以及從RTP包里面得到H.264數(shù)據(jù)和AAC數(shù)據(jù)的方法。
1、單個NAL包單元
12字節(jié)的RTP頭后面的就是音視頻數(shù)據(jù),比較簡單。一個封裝單個NAL單元包到RTP的NAL單元流的RTP序號必須符合NAL單元的解碼順序。
2、FU-A的分片格式
數(shù)據(jù)比較大的H264視頻包,被RTP分片發(fā)送。12字節(jié)的RTP頭后面跟隨的就是FU-A分片:
FU indicator有以下格式:
????? +---------------+
????? |0|1|2|3|4|5|6|7|
????? +-+-+-+-+-+-+-+-+
????? |F|NRI|? Type?? |
????? +---------------+
?? FU指示字節(jié)的類型域 Type=28表示FU-A。。NRI域的值必須根據(jù)分片NAL單元的NRI域的值設(shè)置。
?
?? FU header的格式如下:
????? +---------------+
????? |0|1|2|3|4|5|6|7|
????? +-+-+-+-+-+-+-+-+
????? |S|E|R|? Type?? |
????? +---------------+
?? S: 1 bit
?? 當(dāng)設(shè)置成1,開始位指示分片NAL單元的開始。當(dāng)跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設(shè)為0。
?? E: 1 bit
?? 當(dāng)設(shè)置成1, 結(jié)束位指示分片NAL單元的結(jié)束,即, 荷載的最后字節(jié)也是分片NAL單元的最后一個字節(jié)。當(dāng)跟隨的FU荷載不是分片NAL單元的最后分片,結(jié)束位設(shè)置為0。
?? R: 1 bit
?? 保留位必須設(shè)置為0,接收者必須忽略該位。
?? Type: 5 bits
?? NAL單元荷載類型定義見下表
表1.? 單元類型以及荷載結(jié)構(gòu)總結(jié)
????? Type?? Packet????? Type name???????????????????????
????? ---------------------------------------------------------
????? 0????? undefined??????????????????????????????????? -
????? 1-23?? NAL unit??? Single NAL unit packet per H.264??
????? 24???? STAP-A???? Single-time aggregation packet????
????? 25???? STAP-B???? Single-time aggregation packet????
????? 26???? MTAP16??? Multi-time aggregation packet?????
????? 27???? MTAP24??? Multi-time aggregation packet?????
????? 28???? FU-A????? Fragmentation unit????????????????
????? 29???? FU-B????? Fragmentation unit?????????????????
????? 30-31? undefined??????????????????????????????????? -
3、拆包和解包
拆包:當(dāng)編碼器在編碼時需要將原有一個NAL按照FU-A進(jìn)行分片,原有的NAL的單元頭與分片后的FU-A的單元頭有如下關(guān)系:
原始的NAL頭的前三位為FU indicator的前三位,原始的NAL頭的后五位為FU header的后五位,FU indicator與FU header的剩余位數(shù)根據(jù)實(shí)際情況決定。
?
解包:當(dāng)接收端收到FU-A的分片數(shù)據(jù),需要將所有的分片包組合還原成原始的NAl包時,FU-A的單元頭與還原后的NAL的關(guān)系如下:
還原后的NAL頭的八位是由FU indicator的前三位加FU header的后五位組成,即:
nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
4、代碼實(shí)現(xiàn)
從RTP包里面得到H264視頻數(shù)據(jù)的方法:
??//?功能:解碼RTP?H.264視頻
?//?參數(shù):1.RTP包緩沖地址?2.RTP包數(shù)據(jù)大小?3.H264輸出地址?4.輸出數(shù)據(jù)大小
?//?返回:true:表示一幀結(jié)束??false:FU-A分片未結(jié)束或幀未結(jié)束?
?#define??RTP_HEADLEN?12?
?bool??UnpackRTPH264(?void???*??bufIn,??int??len,???void?**??pBufOut,???int???*??pOutLen)
?{
?????*?pOutLen??=???0?;
?????if??(len??<??RTP_HEADLEN)
?????{
?????????return???false?;
????}?
?
????unsigned??char?*??src??=??(unsigned??char?*?)bufIn??+??RTP_HEADLEN;
????unsigned??char??head1??=???*?src;?//?獲取第一個字節(jié)?
?????unsigned??char??head2??=???*?(src?+?1?);?//?獲取第二個字節(jié)?
?????unsigned??char??nal??=??head1??&???0x1f?;?//?獲取FU?indicator的類型域,?
?????unsigned??char??flag??=??head2??&???0xe0?;?//?獲取FU?header的前三位,判斷當(dāng)前是分包的開始、中間或結(jié)束?
?????unsigned??char??nal_fua??=??(head1??&???0xe0?)??|??(head2??&???0x1f?);?//?FU_A?nal?
??????bool??bFinishFrame??=???false?;
?????if??(nal?==?0x1c?)?//?判斷NAL的類型為0x1c=28,說明是FU-A分片?
??????{?//?fu-a?
??????????if??(flag?==?0x80?)?//?開始?
??????????{
?????????????*?pBufOut??=??src?-?3?;
?????????????*?((?int?*?)(?*?pBufOut))??=???0x01000000??;?//?zyf:大模式會有問題?
??????????????*?((?char?*?)(?*?pBufOut)?+?4?)??=??nal_fua;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??+???3?;
????????}?
?????????else???if?(flag?==?0x40?)?//?結(jié)束?
??????????{
?????????????*?pBufOut??=??src?+?2?;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??-???2?;
????????}?
?????????else?//?中間?
??????????{
?????????????*?pBufOut??=??src?+?2?;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??-???2?;
????????}?
????}?
?????else?//?單包數(shù)據(jù)?
??????{
?????????*?pBufOut??=??src?-?4?;
?????????*?((?int?*?)(?*?pBufOut))??=???0x01000000?;?//?zyf:大模式會有問題?
??????????*??pOutLen??=??len??-??RTP_HEADLEN??+???4?;
????}?
?
????unsigned??char?*??bufTmp??=??(unsigned??char?*?)bufIn;
?????if??(bufTmp[?1?]??&???0x80?)
?????{
????????bFinishFrame??=???true?;?//?rtp?mark?
?????}?
?????else?
??????{
????????bFinishFrame??=???false?;
????}?
?????return??bFinishFrame;
}???
從RTP包里面得到AAC音頻數(shù)據(jù)的方法:
//功能:解RTP?AAC音頻包,聲道和采樣頻率必須知道。
//參數(shù):1.RTP包緩沖地址?2.RTP包數(shù)據(jù)大小?3.H264輸出地址?4.輸出數(shù)據(jù)大小
//返回:true:表示一幀結(jié)束??false:幀未結(jié)束?一般AAC音頻包比較小,沒有分片。
bool?UnpackRTPAAC(void?*?bufIn,?int?recvLen,?void**?pBufOut,??int*?pOutLen)
{
????unsigned?char*??bufRecv?=?(unsigned?char*)bufIn;
????//char?strFileName[20];
????
????unsigned?char?ADTS[]?=?{0xFF,?0xF1,?0x00,?0x00,?0x00,?0x00,?0xFC};?
????int?audioSamprate?=?32000;//音頻采樣率
????int?audioChannel?=?2;//音頻聲道?1或2
????int?audioBit?=?16;//16位?固定
????switch(audioSamprate)
????{
????case??16000:
????????ADTS[2]?=?0x60;
????????break;
????case??32000:
????????ADTS[2]?=?0x54;
????????break;
????case??44100:
????????ADTS[2]?=?0x50;
????????break;
????case??48000:
????????ADTS[2]?=?0x4C;
????????break;
????case??96000:
????????ADTS[2]?=?0x40;
????????break;
????default:
????????break;
????}
????ADTS[3]?=?(audioChannel==2)?0x80:0x40;
????int?len?=?recvLen?-?16?+?7;
????len?<<=?5;//8bit?*?2?-?11?=?5(headerSize?11bit)
????len?|=?0x1F;//5?bit????1????????????
????ADTS[4]?=?len>>8;
????ADTS[5]?=?len?&?0xFF;
????*pBufOut?=?(char*)bufIn+16-7;
????memcpy(*pBufOut,?ADTS,?sizeof(ADTS));
????*pOutLen?=?recvLen?-?16?+?7;
????unsigned?char*?bufTmp?=?(unsigned?char*)bufIn;
????bool?bFinishFrame?=?false;
????if?(bufTmp[1]?&?0x80)
????{
????????//DebugTrace::D("Marker");
????????bFinishFrame?=?true;
????}
????else
????{
????????bFinishFrame?=?false;
????}
????return?true;
}
總結(jié)
以上是生活随笔為你收集整理的FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用友NC6.5 6.33 6.3 5.7
- 下一篇: 用Python+Django在Eclip