rtp扩展头的使用

本文深入解析RTP协议的固定头部字段,包括版本、填充、扩展位、CSRC计数、标志位、负载类型、序列号、时间戳及同步源等关键信息。探讨了RTP扩展头的作用与格式,并提供了抓包实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

rtp确定头(rtp fixed header field)

通常情况下是12字节,如下图
在这里插入图片描述

  • 版本(V):2bits。当前版本是2。
  • 填充(P):1bit。一般没有填充,是0。
  • 扩展位(X):1bit。如果有扩展,会在rtp头之后,payload之前增加rtp扩展头。
  • CSRC count(CC):4bits。一般为0。所以rtp固定头一般是12字节。
  • 上面是1byte
  • 标志位(M):1bit。The interpretation of the marker is defined by a profile.不太好翻译,先用原文。在打包h264数据时,表示一个frame的结束。
  • 负载类型(PT):7bits。范围是96-127。
  • 上面是1byte
  • 序列号(sequence number):16bits。一般是从0开始,但是没有强制要求。每发一个包,加一。
  • 上面是2bytes
  • 时间戳(timestamp):32bits。如果是视频,就是视频帧时间戳(单位秒)值乘以90000;如果是音频,就是音频帧时间戳(单位秒)乘以采样率,比如48k、16k。
  • 上面是4bytes
  • 同步源(SSRC):32bits。是一个随机值,用于区分每一路流。
rfc3550链接

https://tools.ietf.org/html/rfc3550#section-5.1

抓包举例(marker位)

在这里插入图片描述

代码实现可以参考
    typedef struct
    {
        /* byte 0 */
        uint8_t csrc_len : 4; /* CC expect 0 */
        uint8_t extension : 1;/* X  expect 1, see RTP_OP below */
        uint8_t padding : 1;  /* P  expect 0 */
        uint8_t version : 2;  /* V  expect 2 */
        /* byte 1 */
        uint8_t payload : 7; /* PT  RTP_PAYLOAD_RTSP */
        uint8_t marker : 1;  /* M   expect 1 */
        /* byte 2,3 */
        uint16_t seq_no;   /*sequence number*/
        /* byte 4-7 */
        uint32_t timestamp;
        /* byte 8-11 */
        uint32_t ssrc; /* stream number is used here. */
        uint8_t data[0];
    } RTP_FIXED_HEADER;/*12 bytes*/

rtp扩展头

当确定头的扩展位是1的时候,就会有扩展头。

  • 扩展头是跟在确定头后的。
  • 如果有CSRC,就跟在CSRC后。
    在这里插入图片描述
rtp扩展头格式
扩展头长度扩展头内容
16bits自定义
假设为L(rfc文档没有定义)长度32bits*L(其中,L可以为0)
rfc3550链接

https://tools.ietf.org/html/rfc3550#section-5.3.1

抓包举例

在这里插入图片描述

### RTP协议扩展部的格式、作用与实现 #### 格式 RTP扩展部出现在固定部之后,当固定部中的扩展比特位置为1时,表示存在一个长度可变的扩展部分[^2]。扩展部包含以下字段: - **长度域**:16比特,指示扩展项中32比特字的个数,不包括4个字节扩展(因此零是有效值)。 - **标识符或参数**:扩展项的前16比特用于识别标识符或参数,具体格式由上层协议定义。 #### 作用 RTP扩展部的主要作用是为特定应用提供额外的信息,这些信息可能无法通过固定部表达。例如,在WebRTC中,扩展部可以携带播放延迟限制(PlayoutDelayLimits)、绝对发送时间(AbsoluteSendTime)等信息[^3]。这种机制允许不同的实现独立生成不同的扩展,从而增强协议的灵活性和适应性。 #### 实现 以下是基于C++的RTP扩展部解析与写入的示例实现: ```cpp #include <cstdint> #include <vector> class RTPHeaderExtension { public: RTPHeaderExtension(const std::vector<uint8_t>& data) { if (data.size() < 4) { return; // 数据不足,无法解析 } uint16_t length = (data[0] << 8) | data[1]; // 长度域 uint16_t id = (data[2] << 8) | data[3]; // 标识符或参数 // 解析扩展数据 size_t payloadSize = length * 4; // 转换为字节数 if (data.size() >= 4 + payloadSize) { payload_ = std::vector<uint8_t>(data.begin() + 4, data.begin() + 4 + payloadSize); } } void write(std::vector<uint8_t>& buffer, uint16_t id, const std::vector<uint8_t>& payload) { uint16_t length = payload.size() / 4; // 转换为32比特字数 buffer.push_back((length >> 8) & 0xFF); // 写入长度域高字节 buffer.push_back(length & 0xFF); // 写入长度域低字节 buffer.push_back((id >> 8) & 0xFF); // 写入标识符高字节 buffer.push_back(id & 0xFF); // 写入标识符低字节 buffer.insert(buffer.end(), payload.begin(), payload.end()); // 写入负载 } private: std::vector<uint8_t> payload_; // 扩展数据负载 }; ``` 上述代码展示了如何解析和写入RTP扩展部。解析部分从输入数据中提取长度域和标识符,并根据长度域读取负载数据。写入部分则按照指定的标识符和负载数据构造扩展部。 #### 注意事项 在实际实现中,需要考虑字节序问题(大端或小端)。例如,UDP传输通常使用网络字节序(大端),而某些平台可能使用主机字节序(小端),因此需要进行必要的转换[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值