1.V:RTP协议的版本号,占2位,当前协议版本号为2。
P:填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
X:扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头。
CC:CSRC计数器,占4位,指示CSRC 标识符的个数。
M: 标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。
PT: 有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等,在流媒体中大部分是用来区分音频流和视频流的,这样便于客户端进行解析。
序列号:占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。
应用场景:对视频进行无变形缩放选定要裁剪的坐标点、对应的宽高进行裁
RTP头部协议,前12位为基础字节,对应第一个结构体,如果extension为1时候,才有外部扩展信息,外部扩展信息结构对应第二个结构体,分别对应profile、length、data。
创建RTP头部:
void create_rtp_header( ) {
uint8_t *buf;
int version=2;
int padding=0;
int extension=1;
int csrc_count=2;
int marker=2;
int payload_type=96;
uint16_t sequence_number=12345;
uint32_t timestamp=1234567890;
uint32_t ssrc=987654321;
//extension扩展信息
int profile=7;
int length=1;
uint16_t data[]={0x0001};
//Version (2 bits) + Padding (1 bit) + Extension (1 bit) + CSRC count (4 bits)
buf[0] = (version << 6) | (padding << 5) | (extension << 4) | csrc_count;
//Marker (1 bit) + Payload type (7 bits)
buf[1] = (marker << 7) | payload_type;
// 设置序列号
buf[2] = (sequence_number >> 8) & 0xFF;
buf[3] = sequence_number & 0xFF;
// 设置时间戳
buf[4] = (timestamp >> 24) & 0xFF;
buf[5] = (timestamp >> 16) & 0xFF;
buf[6] = (timestamp >> 8) & 0xFF;
buf[7] = timestamp & 0xFF;
// 设置同步源ID
buf[8] = (ssrc >> 24) & 0xFF;
buf[9] = (ssrc >> 16) & 0xFF;
buf[10] = (ssrc >> 8) & 0xFF;
buf[11] = ssrc & 0xFF;
// 添加扩展信息头profile
buf[12] = profile >> 8;
buf[13] = profile & 0xff;
// 设置扩展信息头长度
buf[14] = (length >> 8) & 0xFF;
buf[15] = length & 0xFF;
// 设置扩展信息data
buf[16] = (data[0] >> 8) & 0xFF;
buf[17] = data[0] & 0xFF;
// 复制扩展信息到RTP头中
memcpy(buf + 16, data, length);
}
解析RTP头部:
// 读取版本号和填充位
uint8_t version = (buf[0] >> 6) & 0x03;
uint8_t padding = (buf[0] >> 5) & 0x01;
// 读取扩展位和CSRC计数器
uint8_t extension = (buf[0] >> 4) & 0x01;
uint8_t csrc_count = buf[0] & 0x0f;
// 读取标记位和负载类型
uint8_t marker = (buf[1] >> 7) & 0x01;
uint8_t payload_type = buf[1] & 0x7f;
// 读取序列号
seq_num = (buf[2] << 8) | buf[3];
// 读取时间戳
timestamp = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
// 读取同步源标识符
ssrc = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
//profile
uint16_t profile = ntohs(*((uint16_t*)(data + 12)));
//length
uint32_t length = ntohl(*((uint16_t*)(data + 14)));
//data
uint32_t data = ntohl(*((uint16_t*)(data + 16)));
void parse_rtp_header(const uint8_t *buf, rtp_header *header) {
// 读取版本号和填充位
uint8_t version = (buf[0] >> 6) & 0x03;
uint8_t padding = (buf[0] >> 5) & 0x01;
// 读取扩展位和CSRC计数器
int extension = (buf[0] & 0x10) >> 4;
uint8_t csrc_count = buf[0] & 0x0f;
// 读取标记位和负载类型
uint8_t marker = (buf[1] >> 7) & 0x01;
int payload_type = buf[1] & 0x7f;
// 读取序列号
header->seq_num = (buf[2] << 8) | buf[3];
// 读取时间戳
header->timestamp = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
// 读取同步源标识符
header->ssrc = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
if (extension) {
uint16_t extension__len = AV_RB16(&buf[14]);
printf("Extension length: %d\n", extension__len);
uint16_t ext_id = (((const uint8_t*)(buf+16))[1]);
// uint16_t ext_id = AV_RB16(&buf[12]);
// int extension_data= AV_RB16(&buf[16]);
//int ext = (AV_RB16(buf + 2) + 1) << 2;
// printf("extension_data: %d\n", extension_data);
printf(" Profile: %d\n", ext_id);
}
// 输出解析结果
printf("RTP header:\n");
printf("Version: %u\n", version);
printf("Padding: %u\n", padding);
printf("Extension: %d\n", extension);
printf("CSRC count: %u\n", csrc_count);
printf("Marker: %u\n", marker);
printf("Payload type: %d\n", payload_type);
printf("Sequence number: %u\n", header->seq_num);
printf("Timestamp: %u\n", header->timestamp);
printf("SSRC: %u\n", header->ssrc);
}
xcode-demo下载地址:
demo下载