|
------------------------------
H.264的NAL層處理
------------------------------ 處理過程一,VCL數(shù)據(jù)封裝成NALU ---------------------------------------------------
處理過程二,NALU的RTP打包 ------------------------------------------------ 一、NALU打包成RTP的方式有三種:
1. 單一 NAL 單元模式
2. 組合封包模式
3. 分片封包模式
還記得前面nal_unit_type的定義吧,0~23是給H264用的,24~31未使用,在rtp打包時,如果一個NALU放在一個RTP包里,可 以使用NALU的nal_unit_type,但是當(dāng)需要把多個NALU打包成一個RTP包,或者需要把一個NALU打包成多個RTP包時,就定義新的 type來標(biāo)識。
Type Packet Type name
二、三種打包方式的具體格式 1 .單一 NAL 單元模式
對于 NALU 的長度小于 MTU 大小的包, 一般采用單一 NAL 單元模式.
NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個字節(jié), 其后都是 NALU 單元內(nèi)容.
0 1 2 3
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ] 這是一個序列參數(shù)集 NAL 單元. [00 00 00 01] 是四個字節(jié)的開始碼, 67 是 NALU 頭, 42 開始的數(shù)據(jù)是 NALU 內(nèi)容. 封裝成 RTP 包將如下: [ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ] 即只要去掉 4 個字節(jié)的開始碼就可以了.
其次, 當(dāng) NALU 的長度特別小時, 可以把幾個 NALU 單元封在一個 RTP 包中.
而當(dāng) NALU 的長度超過 MTU 時, 就必須對 NALU 單元進(jìn)行分片封包. 也稱為 Fragmentation Units (FUs). Figure 14. RTP payload format for FU-A
FU indicator有以下格式: 三、拆包和解包
拆包:當(dāng)編碼器在編碼時需要將原有一個NAL按照FU-A進(jìn)行分片,原有的NAL的單元頭與分片后的FU-A的單元頭有如下關(guān)系: 四、代碼實現(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ù):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; }![]() |
|
|