網絡抽象層單元類型 (NALU):
NALU頭由一個字節組成,它的語法如下:
F: 1個比特. forbidden_zero_bit. 在 H.264 規范中規定了這一位必須為 0.
NRI: 2個比特. nal_ref_idc. 取00~11,似乎指示這個NALU的重要性,如00的NALU解碼器可以丟棄它而不影響圖像的回放.
Type: 5個比特. nal_unit_type. 這個NALU單元的類型.簡述如下:
h264僅用1-23,24以后的用在RTP H264負載類型頭中
不同類型的NALU的重要性指示如下表所示:
RTP 頭的結構:
V: RTP協議的版本號,占2bits,當前協議版本號為2
P: 填充標志,占1bit,如果P=1,則在該報文的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分。
X: 擴展標志,占1bit,如果X=1,則在RTP報頭后跟有一個擴展報頭
CC: CSRC計數器,占4位,指示CSRC 標識符的個數
M: 1bit,標記解釋由設置定義,目的在于允許重要事件在包流中標記出來。如不同的有效載荷有不同的含義,對于視頻,標記一幀的結束;對于音頻,標記會話的開始。
負載類型 Payload type(PT): 7bits
注:rfc里面對一些早期的格式定義了這個payload type。但是后來的,如h264并沒有分配,那就用96來代替。因此現在96以上都不表示特定的格式,具體表示什么要用sdp或者其他協議來協商。
序列號 Sequence number(SN): 16bits,用于標識發送者所發送的RTP報文的序列號,每發送一個報文,序列號增1,序列號的初始值是隨機產生的??梢杂糜跈z查丟包以及進行數據包排序。
時間戳 Timestamp: 32bits,必須使用90kHz時鐘頻率。
同步信源(SSRC)標識符: 32bits,用于標識同步信源。該標識符是隨機隨機產生的,參加同一視頻會議的兩個同步信源不能有相同的SSRC。
特約信源(CSRC)標識符: 每個CSRC標識符占32bits,可以有0~15個。每個CSRC標識了包含在該RTP報文有效載荷中的所有特約信源。
上面介紹了NALU和RTP header的基本結構,下面介紹的全部都是RTP PayLoad的部分
Rtp負載第一個字節的結構如下,它和H.264的NALU頭結構一致,可以把它認為是RTP h264負載類型字節,完全是多增加的一個字節,不影響后面的NALU結構
封包介紹:
單一NAL單元模式
對于 NALU 的長度小于 MTU 大小的包, 一般采用單一 NAL 單元模式. 對于一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用于標示這是一個
NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個字節, 其后都是 NALU 單元內容. 打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他數據封包的 RTP 包即可.
例: 如有一個 H.264 的 NALU 是這樣的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個字節的開始碼, 67 是 NALU 頭, 42 開始的數據是 NALU 內容.
封裝成 RTP 包將如下:
[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]
即只要去掉 4 個字節的開始碼就可以了.
組合封包模式
其次, 當 NALU 的長度特別小時, 可以把幾個 NALU 單元封在一個 RTP 包中.
這里只介紹STAP-A模式,如果是STAP-B的話會多加入一個DON域,另外還有MTAP16、MTAP24,具體不介紹,可以看rfc文檔,文章尾貼一個鏈接可以去看。
轉載的話注明一下作者:jwybobo2007 出處:http://blog.csdn.net/jwybobo2007/article/details/7054140
例:
如有一個 H.264 的 NALU 是這樣的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
[00 00 00 01 68 42 B0 12 58 6A D4 FF ... ]
封裝成 RTP 包將如下:
[ RTP Header ] [78 (STAP-A頭,占用1個字節)] [第一個NALU長度 (占用兩個字節)] [ 67 42 A0 1E 23 56 0E 2F ] [第二個NALU長度 (占用兩個字節)] [68 42 B0 12 58 6A D4 FF ... ]
FU-A
當NALU的長度超過MTU時,就必須對NALU單元進行分片封包.也稱為Fragmentation Units(FUs)。
本荷載類型允許分片一個NAL單元到幾個RTP包中。下圖 表示FU-A的RTP荷載格式。FU-A由1字節的分片單元指示,1字節的分片單元頭,和分片單元荷載組成。

FU指示字節有以下格式:

FU指示字節的類型域的28,29表示FU-A和FU-B。F的使用在5。3描述。NRI域的值必須根據分片NAL單元的NRI域的值設置。
注意:這是第一個字節FU indicator,NRI為 幀重要程度 00 可以丟 ,11不能丟。F一般設置0。這一個字節用來表示當前包為分片FU-A包。
FU頭的格式如下:

S: 1 bit
當設置成1,開始位指示分片NAL單元的開始。當跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設為0。
E: 1 bit
當設置成1, 結束位指示分片NAL單元的結束,即, 荷載的最后字節也是分片NAL單元的最后一個字節。當跟隨的
FU荷載不是分片NAL單元的最后分片,結束位設置為0。
R: 1 bit
保留位必須設置為0,接收者必須忽略該位。
Type: 5 bits
NAL單元荷載類型定義在[1]的表7-1.
注意:這是第二個字節,用來表示開始結束和NAL幀的類型。
示例代碼:
if (iLen > iSize) { //超過MTU
const unsigned char s_e_r_Start = 0x80;
const unsigned char s_e_r_Mid = 0x00;
const unsigned char s_e_r_End = 0x40;
//獲取幀頭數據,1byte
unsigned char naluType = *((unsigned char *) pcData) & 0x1f; //獲取NALU的5bit 幀類型
unsigned char nal_ref_idc = *((unsigned char *) pcData) & 0x60; //獲取NALU的2bit 幀重要程度 00 可以丟 11不能丟
//nal_ref_idc = 0x60;
//組裝FU-A幀頭數據 2byte
unsigned char f_nri_type = nal_ref_idc + 28;//F為0 1bit,nri上面獲取到2bit,28為FU-A分片類型5bit
unsigned char s_e_r_type = naluType;
bool bFirst = true;
bool mark = false;
int nOffset = 1;
while (!mark) {
if (iLen < nOffset + iSize) { //是否拆分結束
iSize = iLen - nOffset;
mark = true;
s_e_r_type = s_e_r_End + naluType;
} else {
if (bFirst == true) {
s_e_r_type = s_e_r_Start + naluType;
bFirst = false;
} else {
s_e_r_type = s_e_r_Mid + naluType;
}
}
memcpy(aucSectionBuf, &f_nri_type, 1);
memcpy(aucSectionBuf + 1, &s_e_r_type, 1);
memcpy(aucSectionBuf + 2, (unsigned char *) pcData + nOffset, iSize);
nOffset += iSize;
makeH264Rtp(aucSectionBuf, iSize + 2, mark, uiStamp);
}
} else {
makeH264Rtp(pcData, iLen, true, uiStamp);
}