基础知识
RTSP RTP RTCP SDP基础知识_rtp rtsp-优快云博客
扩展类型
基本扩展字段
mid(Media Identification)
作用:媒体流标识符,用于标识 RTP 包属于哪个媒体流
URI:
urn:ietf:params:rtp-hdrext:sdes:mid用途:在 RTP Bundle 多路复用中,帮助接收端区分不同的媒体流(音频、视频等)
重要性:WebRTC 中实现多媒体流复用的关键机制
rid(RTP Stream ID)
作用:RTP 流标识符,用于区分同一媒体源的不同编码流(如联播)
URI:
urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id用途:支持同一视频源的多个分辨率/码率版本的联播传输
应用场景:视频会议中根据网络条件选择不同质量的视频流
rrid(Repaired RTP Stream ID)
作用:修复流标识符,标识重传包对应的原始流
URI:
urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id用途:用于 RTX(重传)机制,指示重传包修复的是哪个原始流
重要性:提高传输可靠性,减少丢包影响
时间相关扩展
absSendTime(Absolute Send Time)
作用:绝对发送时间戳,记录包离开发送方的时间
URI:
http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time格式:24 位固定点数,6.18 格式,3.8μs 精度
用途:服务端带宽估算、拥塞控制、网络延迟测量
absCaptureTime(Absolute Capture Time)
作用:绝对捕获时间戳,记录媒体帧的原始捕获时间
URI:
http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time用途:音视频同步、端到端延迟测量,特别适用于有中间处理节点的场景
toffset(Transmission Time Offset)
作用:传输时间偏移,记录实际发送时间与标称发送时间的差值
URI:
urn:ietf:params:rtp-hdrext:toffset格式:24 位有符号整数
用途:更精确的抖动计算,适用于非实时传输场景
拥塞控制扩展
transportWideCc01(Transport Wide Congestion Control)
作用:传输层拥塞控制,提供跨所有媒体流的统一拥塞控制
URI:
http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01机制:每个包分配唯一序号,接收端反馈到达时间信息
优势:相比单流拥塞控制更准确、高效
视频相关扩展
frameMarking07/frameMarking(Frame Marking)
作用:视频帧标记,提供帧的关键信息用于转发决策
URI:
urn:ietf:params:rtp-hdrext:framemarking信息:帧开始/结束、独立帧、可丢弃帧、时域/空域层信息
用途:SFU 选择性转发,不需要解码即可进行帧级处理
注意:
frameMarking07是旧版本,将被标准版本替代
videoOrientation(Video Orientation)
作用:视频方向信息,指示视频需要的旋转角度
URI:
urn:3gpp:video-orientation用途:移动设备旋转时避免重新编码,通过头部扩展传递旋转信息
限制:Firefox 和某些服务端不支持,需要移除此扩展强制客户端编码旋转视频
音频扩展
ssrcAudioLevel(Audio Level)
作用:音频电平指示,包含音频包的音量信息
URI:
urn:ietf:params:rtp-hdrext:ssrc-audio-level格式:包含音量值和语音活动检测位
用途:服务端无需解码即可识别活跃说话人、实现音频混音
/**
* RTP头部扩展ID集合。
*
* 用于存储RTP头部扩展的ID值,部分ID由使用相同Transport的所有Producers共享,
* 其他ID则每个Producer各不相同。值为0表示未设置该扩展。
*/
struct RtpHeaderExtensionIds {
// 0 means no id.
uint8_t mid{0u};
uint8_t rid{0u};
uint8_t rrid{0u};
uint8_t absSendTime{0u};
uint8_t transportWideCc01{0u};
uint8_t frameMarking07{0u}; // NOTE: Remove once RFC.
uint8_t frameMarking{0u};
uint8_t ssrcAudioLevel{0u};
uint8_t videoOrientation{0u};
uint8_t toffset{0u};
uint8_t absCaptureTime{0u};
};
扩展字段封包封包
依然是RTP固定头: 12字节
扩展字段:
起始固定头部 4 字节(0xBEDE + 长度) 单字节模式 or twoByte模式则是0x1000
该扩展的条目头 1 字节(ID+len)+ 1 字节数据(level)
对齐填充到 32-bit 边界
合计通常为 8 字节
举例:
RTP固定头: 12字节:其中常见90是包含扩展 80是不包含扩展。BE DE 00 03 42 00 00 00 51 00 00 A0 CE 00 00 00
RTP固定头: 12字节
扩展头+扩展数据: 16字节
0xBE 0xDE 0x00 0x03 → RFC5285 one-byte扩展头,长度=3个32-bit字=12字节扩展数据
扩展数据逐项:
0x42 00 00 00 → 0100 0010 ID=4,len=2 数据全0(多为 AbsoluteSendTime 3字节占位)
0x51 00 00 → 0101 0001 ID=5,len=1字节,数据全0(多为 TransportWideCc 2字节占位)
0xA0 CE → 1010 0000 ID=10,len=0字节,0xCE=1100 1110 → V=1,level=0x4E=78(AudioLevel)
0x00 0x00 0x00 → 填充到32-bit对齐
合计: 12 + (4 + 12) = 28字节
剥离扩展字段示例代码
把包含扩展字段的rtp转换成标准12字节头部rtp。
bool StripRtpExtensionBlock(uint8_t* rtp, size_t& rtp_len, bool stripKnownProfilesOnly = true) {
if (!rtp || rtp_len < 12) return false;
const uint8_t vpxcc = rtp[0];
const uint8_t cc = (vpxcc & 0x0F);
const bool xbit_set = (vpxcc & 0x10) != 0;
// 扩展起始偏移:固定头(12) + CSRC(4*CC)
size_t ext_off = 12u + (static_cast<size_t>(cc) * 4u);
if (!xbit_set) return true; // 没有扩展
if (ext_off + 4u > rtp_len) return false; // 不完整
// 读取扩展头:profile(16) + length(16, 单位32-bit word)
const uint16_t profile = (static_cast<uint16_t>(rtp[ext_off + 0]) << 8) |
static_cast<uint16_t>(rtp[ext_off + 1]);
const uint16_t length_words = (static_cast<uint16_t>(rtp[ext_off + 2]) << 8) |
static_cast<uint16_t>(rtp[ext_off + 3]);
const size_t ext_bytes = 4u + static_cast<size_t>(length_words) * 4u; // 整块扩展字节数
if (ext_off + ext_bytes > rtp_len) return false; // 越界保护
if (stripKnownProfilesOnly) {
// 仅剥离 RFC5285 的两种规范扩展
if (profile != 0xBEDE && profile != 0x1000) return true;
}
// 清除固定头 X 位
rtp[0] = static_cast<uint8_t>(rtp[0] & ~0x10);
// 剩余数据整体前移覆盖扩展区
const size_t tail_off = ext_off + ext_bytes;
const size_t tail_len = rtp_len - tail_off;
if (tail_len > 0) {
std::memmove(rtp + ext_off, rtp + tail_off, tail_len);
}
rtp_len -= ext_bytes;
return true;
}

1374

被折叠的 条评论
为什么被折叠?



