rtp协议
// 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 32位 uint8_t* buffer size_t size
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P|X| CC |M| PT | sequence number | buffer[0] buffer[1] buffer[2] buffer[3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp | buffer[4] buffer[5] buffer[6] buffer[7]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | synchronization source (SSRC) identifier | buffer[8] buffer[9] buffer[10] buffer[11]
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | Contributing source (CSRC) identifiers | buffer[12] ~ buffer[11 + CC * 4]
// | .... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | header eXtension profile id | length in 32bits | buffer[12 + CC * 4]~ buffer[12 + CC * 4 +3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Extensions | buffer[12 + CC * 4 + 4]
// | .... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | Payload |
// | .... : padding... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | padding | Padding size | buffer[size - 2] buffer[size - 1]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/* RTP header extension, RFC 3550.
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 payload_offset = 12 + CC * 4;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ id | 扩展容量
| defined by profile | length | buffer[payload_offset + 4] | buffer[payload_offset + 4 +2]
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|header extension|
|....|
*/
// 数据流
80 e0 00 1e 00 00 d2 f0 00 00 00 00 41 9b 6b 49 €?....??....A?kI
e1 0f 26 53 02 1a ff06 59 97 1d d2 2e 8c 50 01 ?.&S....Y?.?.?P.
cc 13 ec 52 77 4e e50e 7b fd 16 11 66 27 7c b4 ?.?RwN?.{?..f'|?
f6 e1 29 d5 d6 a4 ef3e 12 d8 fd 6c 97 51 e7 e9 ??)????>.??l?Q??
cfc7 5e c8 a9 51 f6 82 65 d6 48 5a 86 b0 e0 8c ??^??Q??e?HZ????
其中,
80 是V_P_X_CC
e0 是M_PT
00 1e 是SequenceNum
00 00 d2 f0 是Timestamp
00 00 00 00 是SSRC
换成二进制:
0X80 = 1000 0000
= 10|0|0|0000
v|p|x|cc
0Xe0 = 1110 0000
= |1|110000
|m|pt
在每个 RTP 包中包含着长度为 12 的前缀字段,在其被混合器插入的位置上才会出现 CSRC 识别符列表。这些字段各自承担着特定的功能。
版本(V): 2位 RTP版本。此协议定义的版本是2 解析: buffer[0] >> 6
填充(P): 1位 如果标志位被设置,则该包尾随包含一个或多个填充位(peb),这些填充位不计入负载数据。这些填充位由末尾的一个字节标识可丢弃的数量。该技术通常应用于那些采用固定长度加密算法的系统,并可用于多路RTP数据分组传输。
解析: buffer[0] & 0x20
扩展(X): 占1位 若设置扩展比特,固定头(仅)后面跟随一个头扩展。 解析: buffer[0] & 0x10
CSRC计数(CC): 占4位 CSRC计数器,
标志(M): 占1位 标志的解释由具体协议规定。它用来允许在比特流中标记重要的事件,如帧边界。
负载类型(PT): 有效的载荷类别占用7位数字此字段明确了载荷的形式其解析依据通常由具体应用场景确定
其中序列号字段占16位;每当传输一个 RTP 数据报时, 序列号字段会递增1. 接收端可依据此信息检测数据包丢失并重构丢失的数据流. 其初始值采用随机数生成(具有不可预测性),在实际应用中尤其适用于那些可能经过中间设备处理的数据流
时间戳(timestamp): 占用32位,表示RTP数据包的第一个字节所记录的采样时刻。时钟频率受所承载的数据格式影响,并在配置文件(profile)中予以说明。此外,还可以利用RTP机制对承载的数据格式进行动态配置.
SSRC: 占据32位并用于标识同步源。为了确保在同一个RTP对话期内没有两个同步源拥有相同的SSRC标识码,在生成过程中会采用随机机制以提高唯一性。
CSRC列表中,每个CSRC标识符占用32位,并且其数量范围为0至15个。每一个特定的CSRC则标识其所在RTP报文的有效载荷中所包含的所有特约信源。
// uint8_t 0~255 0000 0000
bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
if (size < kFixedHeaderSize) {
return false;
}
// 前两位为版本号
const uint8_t version = buffer[0] >> 6;
if (version != kRtpVersion) {
return false;
}
// 0x20 = 0010 0000
const bool has_padding = (buffer[0] & 0x20) != 0;
// 0x10 = 0001 0000
const bool has_extension = (buffer[0] & 0x10) != 0;
// 0x0f = 0000 1111
const uint8_t number_of_crcs = buffer[0] & 0x0f;
// 0x80 = 1000 0000
marker_ = (buffer[1] & 0x80) != 0;
// 0x7f = 0111 1111
payload_type_ = buffer[1] & 0x7f;
// 读16位 4字节
sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
// 读32位 8字节
timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
// 读32位 8字节
ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
// 数据足够,没有丢失
if (size < kFixedHeaderSize + number_of_crcs * 4) {
return false;
}
// payload 偏移
payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
if (has_padding) {
padding_size_ = buffer[size - 1];
if (padding_size_ == 0) {
RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
return false;
}
} else {
padding_size_ = 0;
}
// 初始化extension
extensions_size_ = 0;
extension_entries_.clear();
if (has_extension) {
/* RTP header extension, RFC 3550.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|defined by profile|length|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|header extension|
|....|
*/
// 扩展偏移
size_t extension_offset = payload_offset_ + 4;
if (extension_offset > size) {
return false;
}
// ID
uint16_t profile =
ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
// 扩展容量
size_t extensions_capacity =
ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
extensions_capacity *= 4;
// 判断扩展合法
if (extension_offset + extensions_capacity > size) {
return false;
}
// 判断是否支持rtp扩展
if (profile != kOneByteExtensionProfileId &&
profile != kTwoByteExtensionProfileId) {
RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
} else {
// 扩展头长度
size_t extension_header_length = profile == kOneByteExtensionProfileId
? kOneByteExtensionHeaderLength
: kTwoByteExtensionHeaderLength;
// 填充字节
constexpr uint8_t kPaddingByte = 0;
// 填充Id
constexpr uint8_t kPaddingId = 0;
// 一字节报头扩展保留ID
constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
// 读取extensions
while (extensions_size_ + extension_header_length < extensions_capacity) {
// 填充字节为0
if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
extensions_size_++;
continue;
}
int id;
uint8_t length;
// 例如: 0100 1000
// 单字节扩展
if (profile == kOneByteExtensionProfileId) {
// id 0100
id = buffer[extension_offset + extensions_size_] >> 4;
// 1 + 1000
length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
// id = 15 或者 id = 0 且 长度 != 1
if (id == kOneByteHeaderExtensionReservedId ||
(id == kPaddingId && length != 1)) {
break;
}
} else {
// id 0100 1000
id = buffer[extension_offset + extensions_size_];
length = buffer[extension_offset + extensions_size_ + 1];
}
// 超大的rtp标头扩展
if (extensions_size_ + extension_header_length + length >
extensions_capacity) {
RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
break;
}
// 查找或创建扩展信息
ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
if (extension_info.length != 0) {
RTC_LOG(LS_VERBOSE)
<< "Duplicate rtp header extension id " << id << ". Overwriting.";
}
// 偏移
size_t offset =
extension_offset + extensions_size_ + extension_header_length;
if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
break;
}
extension_info.offset = static_cast<uint16_t>(offset);
extension_info.length = length;
extensions_size_ += extension_header_length + length;
}
}
// 更新paload偏移
payload_offset_ = extension_offset + extensions_capacity;
}
// 判断越界错误
if (payload_offset_ + padding_size_ > size) {
return false;
}
// payload 大小
payload_size_ = size - payload_offset_ - padding_size_;
return true;
}
