RFC3984是H.264的baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式。
1、单个NAL包单元
一个封装单个 NAL 单元包到 RTP 的 NAL 单元流的 RTP 序号必须符合 NAL 单元的解码顺序。单个 NAL 单元包的结构显示在图 1 。
注 : NAL 单元的第一字节和 RTP 荷载头第一个字节重合。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type | |
+-+-+-+-+-+-+ |
| |
| Bytes 2..n of a Single NAL unit |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
图 1. 单个 NAL 单元包的 RTP 荷载格式。
2、FU-A的分片格式
如图2 所 示, FU-A 的 RTP 荷载格式。 FU-A 由 1 字节的分片单元指示, 1 字节的分片单元头,和分片单元荷载组成。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator| FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-++-++-++-++-++-++-++-++-++-+|
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
图 2. FU-A 的 RTP 荷载格式
FU indicator 有以下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU 指示字节的类型域 ,28 表示 FU-A 。。 NRI 域的值必须根据分片 NAL 单元的 NRI 域的值设置。
FU header 的格式如下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
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. 单元类型以及荷载结构总结
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、拆包和解包
拆包:当编码器在编码时需要将原有一个 NAL 按照 FU-A 进行分片,原有的 NAL 的单元头与分片后的 FU-A 的单元头有如下关系:
原始的 NAL 头的前三位为 FU indicator 的前三位,原始的 NAL 头的后五位为 FU header 的后五位, FU indicator 与 FU header 的剩余位数根据实际情况决定。
解包:当接收端收到 FU-A 的分片数据,需要将所有的分片包组合还原成原始的 NAl 包时, FU-A 的单元头与还原后的 NAL 的关系如下:
还原后的 NAL 头的八位是由 FU indicator 的前三位加 FU header 的后五位组成,即:
nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
4、代码实现
void CVAUClientSource::AnalyzeHeader(unsigned char * src, int len)
{
unsigned char head1 = *src;// 获取第一个字节
unsigned char head2 = *(src+1);// 获取第二个字节
unsigned char type = head1 & 0x1f;// 获取 FU indicator 的类型域,
if (type==0x1c)// 判断 NAL 的类型为 0x1c=28 ,说明是 FU-A 分片
{//fu-a
unsigned char flag = head2 & 0xe0;// 获取 FU header 的前三位,判断当前是分包的开始、中间或结束
if (flag==0x80)
{// 开始
/* 进行处理 */
}
else (flag==0x40)
{// 结束
/* 进行处理 */
}
else
{// 中间
/* 进行处理 */
}
}
else
{// 单包数据
/* 进行处理 */
}
return;
}