RTP包分析
记录一下对RTP包的理解
RTP包头
上图展示了RTP包的具体信息结构,字段明确如下:
RTP头部一般固定会有12字节。
V:版本号,2比特,用来标示使用RTP版本;
P:填充位,1比特,置成1,表示此包后面会一定数目的填充比特;
X:扩展位,1比特,置成1,表示此包固定头部后面会跟着一个扩展头部;CC:CSRC计数位,4比特,表示固定头部后面CSRC识别符的个数;
M:标示位,1比特,具体含义由特定协议解释;
PT:负载类型(Payload Type),7比特,表示具体的负载类型,比如音频、视频、文档等;
sequence number:序列号,16比特,发送方在每发送完一个RTP包后就将该值增加1,接收方可以由该值检测包的丢失及恢复包序列。序列号的初始值是随机的;
timestamp:时间戳,32比特,表示RTP数据包中第一个字节的采样时间;synchronization source (SSRC) identifier:同步源标示符,32比特,表示RTP数据包的来源,在同一个RTP会话中不可能存在两个相同的SSRC,SSRC的值是随机选取的;
contributing source (CSRC) identifiers:贡献源列表,0到15项,每项32比特,表示此包中负载的所有贡献源。若贡献源多于15个,仅识别15个,CSRC由混合器插入,便于接收端正确识别出会话者的身份。
头部之后加的都是负载,头部信息中SSRC需要关注,用来区分音频和视频流的唯一ID
H264负载内容:
H264在网络中传输的基本单元为NALU
NALU结构:NALU header(1byte) + NALU payload
header 部分可以判断类型等信息,从右往左5个bit位
各个类型的帧判断通过头来进行:
SPS: 0x67 header & 0x1F = 7 | SEI: 0x66 header & 0x1F = 6 |
---|---|
P Frame: 0x41 header & 0x1F = 1 | I Frame: 0x65 header & 0x1F = 5 |
PPS: 0x68 header & 0x1F = 8 |
RTP中H264拆包规则:
- 单NALU: P帧或者B帧比较小的包,直接将NALU打包成RTP包进行传输
RTP header(12bytes) + NALU header (1byte) + NALU payload - 多NALU: 特别小的包几个NALU放在一个RTP包中
- FUs(Fragment Units): I帧长度超过MTU的,就必须要拆包组成RTP包了,有FU-A
RTP header (12bytes)+ FU Indicator (1byte) + FU header(1 byte) + NALU payload
针对多个FU来说有如下规则:
NALU头被分散填充到FU indicator和FU header里面了,bit位按照从左到右编号0-7来算,nalu头中0-2前三个bit放在FU indicator的0-2前三个bit中,后3-7五个bit放入FU header的后3-7五个中 ,因此查看I帧p帧类型,遇到FU分片的,直接看第二个字节,即Fu header后五位,这个跟直接看NALU头并无差异,一般有:0x85,0x05,0x45等等
还原数据帧时,照旧从左到右,Fu header前两个bit表示start和end标记,start为1表示一个i帧分片开始,end为1表示一个i帧分片结束
看第一个字节FU Indicator,照旧从左到右,Fu Indicator前三个bit是NALU头的前三个bit,后五位为类型FU-A:28(11100),FU-B:29(11101),RTP抓包看下来整个字节是0x7c开头,如果不是分片,第一字节就是NALU头,如:0x67,0x68,0x41等
RTP抓包分析:
SPS包:
图中可以看出头部为0x67,即为sps包
I帧包(分片包为例):
I帧分片开始:
I帧分片开始,第一个字节FU Indicator,0x7c, 后五位11100,28,FU-A
第二个字节FU Header,0x85,前两个bit start位1,end位0 表示 分片开始,后五个bit值5,I帧
I帧分片
I帧分片,0x7c开头,第二个字节0x05, FU Header start和end位 0,后五个bit值5,I帧
I帧分片结束
I帧分片结束,7c开头,第二个字节0x45,FU Headr,start 0,end1,后五个bit值5,I帧, Mark标记一帧结束
AAC封包:
过程如下:
需要将aac的前7个字节的ADTS去掉;
- 添加12字节的RTP Header;
- 添加2字节的AU_HEADER_LENGTH;
- 添加2字节的AU_HEADER;
- 从第17字节开始就是payload(去掉ADTS的aac数据)数据了
格式:
AU-headers-length AU-header AU AU-header AU
一个RTP包中可以有一个AU-headers-length 和 n个AU-header和 n个AU(AU每包实际音频数据流)
AU-headers-length
头两个字节表示au-header的长度,单位是bit。 一个AU-header长度是两个字节(16bit)因为可以有多个au-header所以AU-headers-length的值是 16的倍数,一般音频都是单个音频数据流的发送,所以AU-headers-length的值是16
//AU_HEADER_LENGTH
bytes[12] = 0x00; //高位
bytes[13] = 0x10; //低位
因为单位是bit, 除以8就是auHeader的字节长度;又因为单个auheader字节长度2字节,所以再除以2就是auheader的个数。
AU-header
au-header的高13个bits就是一个au 的字节长度:
//AU_HEADER
bytes[14] = (byte)((len & 0x1fe0) >> 5); //高位
bytes[15] = (byte)((len & 0x1f) << 3); //低位
这样就能得到多个au的长度