/**
* RtpHeader,普遍占用12个字节
*
* 由于 IP 协议采用大端序,这里需要转成小端序 (Java-Byte 是大端序,java 代码中可以不用转),
* 所以这里每一个字节内的各个属性跟标准 rtp 协议头刚好相反,
* 并且在使用 "大于1bit" 的属性时需要将网络序转成字节序.
*/
typedef struct rtp_header_t
{
// 1byte (0)
unsigned int cc : 4; /* CSRC count */
unsigned int x : 1; /* header extension flag */
unsigned int p : 1; /* padding flag */
unsigned int version : 2; /* protocol version */
// 1byte (1)
unsigned int pt : 7; /* payload type */
unsigned int m : 1; /* marker bit */
// 属性 m 表示是否到一帧的末尾,java 中可以使用 isFrameEnd = buf[1] & 0x80 == 0x80 来判断。
// & 0x80: 获取该 Byte 中第一个 bit 位. [ & 1000 0000 ].
// == 0x80: 该 Byte 第一个 bit 值为1时,Byte值为 0x80 ([1000 0000]).
// 2bytes (2,3)
unsigned int seq : 16; /* sequence number */
// 属性 seq 表示当前消息的序列号,在一定范围内每发出一个 RTP 包,seq 自增一次。
// java 中可以使用 seq = (((int) buf[2] & 0xff) << 8) + ((int) buf[3] & 0xff) 来获得其值。
// 4bytes (4-7)
uint32_t ts; /* timestamp */
// 4bytes (8-11)
uint32_t ssrc; /* synchronization source */
// 4bytes csrc 可选位
// uint32_t csrc[1]; /* optional CSRC list */
};
/**
* NaluHeader,占用1个字节,在 RtpHeader 之后。
* RTP 包含完整包时,RtpPayload = NaluHeader + NaluPayload.
*/
typedef struct nalu_header_t
{
unsigned int nalu_head_3 : 3;/* 前三位填充 nalu-head 的前三位 */
unsigned int nalu_type : 5;/* 后五位表示 nalu-type */
// nalu_type 表示 nal 单元的类型,1~12由H.264使用,24~31由其他应用使用,以下是具体定义。
0 没有定义
1-23 NAL单元 单个 NAL 单元包
1 不分区,非IDR图像的片
2 片分区A
3 片分区B
4 片分区C
5 IDR图像中的片
6 补充增强信息单元(SEI)
7 SPS
8 PPS
9 序列结束
10 序列结束
11 码流借宿
12 填充
13-23 保留
24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24 多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
30-31 没有定义
};
/**
* FuIndicator + FuHeader. 各占一个字节,在 RtpHeader 之后。
* NALU的长度超过 MTU 时,RTP 对其进行分片传输,称为 Fragmentation Unit(以下简称FU)。
*/
typedef struct fu_indicator_header_t
{
unsigned int nalu_head_3 : 3;/* FuIndicator, 前三位填充 nalu-header 的前三位 */
unsigned int nalu_type : 5;/* FuIndicator, 后五位表示 nalu-type */
/*
nalu_type,占5个bit,用于确定是否为切片封装。
如果候选值在 1-12 之间,则表示未切片,当前属性属于 NaluHeader,
如果候选值在 28-29 之间,则表示被切片,当前属性属于 FuIndicator,且后面会追加一个字节表示 FuHeader。
java 中可以使用 isFU-A = buf[RTPHeader.len] & 0x1F == 0x1C 判断是否属于切片包。
// buf[RTPHeader.len]: 取 RTP-Head 后的第一个 Byte.
// & 0x1F: 获取后5个 bit 位。[ & 0001 1111 ]
// == 0x1C: FU-A 的值为 28 ([0x1C]).
*/
unsigned int fu_flag : 3;/* FuHeader, 前三位表示 fu 的标志位. (0x80/0x40/0x00) */
unsigned int nalu_head_5 : 5;/* FuHeader, 后五位填充 nalu-header 的后五位. */
/*
fu_flag,只有在确定为切片包时有效,否则这个位置的字节已经属于 NaluPayload.
占用3个bit,SER,为 FU 的标志位,表示当前包为 FU 包的开头/结尾/内容。
S- StartFlag: 第1个 bit 位,为1表示 NALU-Start,则 flag 值为 0x80 ([1000 0000]);
E- EndFlag: 第2个 bit 位,为1表示 NALU-End,则 flag 值为 0x40 ([0100 0000]);
R- RemainFlag: 第3个 bit 位,保留位,恒为0.
java 中可以使用 `Fu_Flag = buf[RTPHeader.len+1] & 0xE0` 获得当前 flag 值。
*/
/*
nalu_head,完整包时为单独字节,切片包时被切割封装在 FuIndicator 的前3位和 FuHeader的后5位。
可以通过 nalu_header = (fu_indicator & 0xe0) | (fu_header & 0x1f) 获得其值。
(候选值:0x67-SPS、0x68-PPS、0x65-IDR帧、0x61-P帧)
此时 nalu_header 的后五位仍然表示 nalu-type,但是取值范围在1-12之间,表示当前切片包的类型是 I帧/P帧/SPS/PPS.
*/
};