一、H.264的RTP封包
感谢网友的讲解,非常详细 http://www.cppblog.com/czanyou/archive/2009/12/25/67940.html。在此做个记录,以备查询。
*********************************************
NALU header结构介绍
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
F: 1bit forbidden_zero_bit. h264规定这一位必须为0
NRI:2bit nal_ref_idc. 取00~11,代表NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放
Type:5bit nal_unit_type. 代表这个NALU单元的类型。
0 没有定义
1-23 NAL单元 单个NAL单元包
24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
nal_unit_type NAL类型
1 不分片、非IDR图像的片
2 片分区A
3 片分区B
4 片分区C
5 IDR图像中的片
6 补充增强信息单元(SEI)
7 序列参数集(SPS)
8 图像参数集(PPS)
9 分界符
10 序列结束
11 码流结束
12 填充
13-23 保留
**********************************************************
RTP header (一般12 bytes)
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
timestamp
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
V:版本号 (2 bits)
P:padding
M: marker bit(1 bit) 指示相同时间戳的最后一个
rtp
包。
PT:payload type(7 bits) 96代表h264打包
SN: sequence number(16 bits) 包的序号,对于单个NALU模式与非交错打包方式,序号用于对定NALU解码顺序
Timestamp
: 时间戳(32 bits) 设置为内容的采样时间戳。必须使用90kHz时钟频率。
**********************************************************
单一NALU模式
对于NALU的长度小于MTU大小的包,一般采用单一NAL单元模式。
一个原始的H.264 NALU常由 [Start Code] [NALU header] [NALU
Payload
]三部分组成。
Start Code用于标示这是一个NALU单元的内容,必须是 “00 00 00 01” 或 “00 00 01”。
NALU header 仅一个字节,其后都是NALU内容。
RTP打包时,去除“00 00 00 01”或“00 00 01”的开始码,把其他数据封包到RTP包即可。
[RTP header] [NALU header] [NALU
payload
]
实例:
有一个 h.264 的NALU是这样的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
这是一个序列参数集NAL单元。[00 00 00 01]是四个字节的开始码,67是NALU header,42开头的数据时NALU内容。
封装成 RTP 包将如下:
[RTP header][67 42 A0 1E 23 56 0E 2F ... ] 去掉4个字节的开始码
************************************************************************
FU-A 分片模式 (Fragmentation Units)
当一个NALU长度大于MTU时,就必须对NALU进行分片封包。
[RTP header] [FU indicator] [FU header] [FU
payload
]
FU indicator:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
NRI : 设置成NAL单元的NRI
Type: 28 表示 FU-A
FU header:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S: 1 bit 设置成1,开始位指示NAL单元的开始。
E: 1 bit 设置成1,结束位指示分片NAL单元的结束。
R: 1 bit 预留位,必须设置为0
Type: 设置成NAL单元的荷载类型
***********************************************************************
RTP包头的第2个32bit即为RTP包的时间戳,Time Stamp。
时间戳反映了RTP分组中的数组的第一个字节的采样时刻。在一次会话开始时的时间戳是随机选择的。即使没有信号发送时,时间戳的数值也要随时间不断的增加。接收端使用时间戳可准确知道应当在什么时间还原哪一个数据块,从而消除传输中的抖动。时间戳还可用来使音视频同步。
在RTP协议中并没有规定时间戳的粒度,这取决于有效载荷类型。因此RTP的时间戳又称为媒体时间戳,以强调这种时间戳的粒度取决于信号的类型。例如,对于8kHz采用的语音信号,若每隔20ms构成一个数据块,则一个数据块中包含有160个样本(0.02*8000=160)。因此每发送一个RTP分组,其时间戳的值就增加160.
关于libstreaming对时间戳的设置,有些许不解,有时间要好好研究。
二、RtpSocket类
未完待续...