RTP载荷H264

182 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

RTP包由两部分组成,RTP头和RTP载荷:

图片.png

RTP头

RTP头结构:

图片.png ​代码结构:

typedef struct RtpHdr
{
	uint8_t cc : 4,  			// CSRC count
		x : 1,   			// header extend
		p : 1,   			// padding flag
		version : 2;		// version
	uint8_t pt : 7,				// payload type
		m : 1;				// mark bit
	uint16_t seq;				// sequence number;
	uint32_t ts;				// timestamp
	uint32_t ssrc;				// sync source
}RtpHdr;

v : RTP协议的版本号,当前的RTP版本号为2.

p : 填充标志, 如果p=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。

x : 扩展标志,如果x=1,则在RTP报头后跟有一个扩展报头.

cc : CSRC计数器,指示CSRC 标识符的个数

m : 标记,编辑帧的开始和结束,例如一帧的数据比较大,分成了好多RTP包进行传输,则最后一包m=1带包一帧数据传输完成,其他包m=0。

pt : 有效荷载类型,用于说明RTP报文中有效载荷的类型。一般都是用96-127.

seq : 用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1, 不同的源有独立的计数体制,如音频视频的seq是独立的。这个序列号的初始值可以为0但是也可以为其它随机值,只要符合+1就行;

ts : 时间戳

ssrc : 用于标识同步信源。该信源的值是自定义的,可以使用time(NULL)赋值。

RTP载荷

RTP载荷根据帧数据的大小可以分为三种模式:单包,分片包,聚合包

单包:

帧数据和RTP头总数不大于网络传输MTU,就可以采用单包,一个RTP包包含一帧数据。

分片包:

帧数据比较大,在网络传输时由于MTU的限制就会采用分片策略,将一个数据帧分成多个RTP包进行传输。

分片传输有两种类型:

FU-A:

图片.png

载荷会有两个字节的RTP载荷信息描述。

FU indication:

|0|1|2 |3|4|5|6|7|

|F|NRI| Type |

FU indication 的前三个bit(F NRI)和H264开始码后的第一个字节的前三个bit是一样的,H264类型字节:

nal_unit_head{
    forbidden_zero_bit(1bit):禁止位 == N
    nal_ref_idc(2bit): == NRI
    nal_unit_type(5bit):NALU类型
};

Type是FU-A的类型28.

FU header

|0| 1|2|3|4|5|6|7|

|S|E|R| Type |

S:帧数据的第一个RTP包,该标志置1, 其他RTP包置0.

E:帧数据的最后一个RTP包,该标志置1,其他RTP包置0.

R: 设置为0

Type:H264的NALU的第一个字节的类型,及上图中的nal_unit_type(5bit):NALU类型

FU indication和FU header之后便是H264的载荷数据,该载荷数据去掉了H264的起始码和起始码后的第一个字节, 因为该字节的信息已经全部由FU indication和FU header包含。

实例:

H264数据: 00 00 00 01 65 xx xx xx xx xx xx xx...

RTP数据:

RTP头 FUindication FUheader xx xx xx xx xx xx xx...(去掉起始码00 00 00 01 和NAL head 65)

FU-B:

图片.png 相较于FU-A,该模式多了个两字节的DON(解码顺序号)字段, FU-B的FU indication的Type是29。一般都是用FU-A.

多种包类型可以混合使用,例如帧数据比较小可以使用单包或者聚合包进行网络传输,帧数据比较大可以使用分片包进行网络传输。

聚合包:

即帧数据比较少,多个帧打包在一个RTP包中。

现实中,单包,分片包比较常用。