WebRTC Packet Buffer
Abstract |
WebRTC Packet Buffer |
Authors |
Walter Fan |
Status |
v1.0 |
Updated |
2026-03-20 |
概述
从网络上收到的 RTP 包可能会丢失、乱序或延迟到达。 为了在不稳定的网络条件下保证音视频播放的流畅性,接收端需要缓冲区(Jitter Buffer)来:
重新排序乱序的 RTP 包
等待延迟到达的包(在一定时间窗口内)
组装完整的视频帧(从多个 RTP 包中)
为丢包恢复(NACK/FEC)提供时间
网络 → Packet Buffer → 解码器
(乱序/丢包) (排序/组帧/等待) (完整帧)
RTP 包流: [3] [1] [5] [2] [4]
↓
排序后: [1] [2] [3] [4] [5]
↓
组帧: [Frame 1: pkt 1,2,3] [Frame 2: pkt 4,5]
视频 Packet Buffer
视频帧通常由多个 RTP 包组成(一个 1080p 关键帧可能拆分为几十个 RTP 包)。 视频 Packet Buffer 需要将这些包重新组装为完整的帧。
关键类
类 |
说明 |
|---|---|
|
通用视频包缓冲区,负责收集 RTP 包并按序号排列,检测帧边界后组装为完整帧 |
|
H.264 专用扩展,处理 H.264 特有的分片(FU-A)和聚合(STAP-A)NAL 单元 |
|
建立帧间参考关系(I/P/B 帧依赖),确定帧的解码顺序 |
PacketBuffer 工作流程
RTP 包到达
│
▼
┌─────────────────────────┐
│ 按序号插入环形缓冲区 │
│ (大小通常 2048 个槽位) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 检测帧边界 │
│ (RTP Marker bit = 1 │
│ 表示帧的最后一个包) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 向前搜索帧的第一个包 │
│ (检查序号连续性) │
└────────┬────────────────┘
│
┌────┴────┐
│完整? │不完整
▼ ▼
组装帧输出 等待/请求 NACK
核心代码逻辑:
// 简化的 PacketBuffer 插入逻辑
InsertResult PacketBuffer::InsertPacket(std::unique_ptr<Packet> packet) {
uint16_t seq_num = packet->seq_num;
size_t index = seq_num % buffer_size_;
buffer_[index] = std::move(packet);
// 如果 Marker bit 为 1,尝试向前找到帧的起始包
if (buffer_[index]->marker_bit) {
return FindFrames(seq_num);
}
return InsertResult();
}
音频 Jitter Buffer
音频的 Jitter Buffer 通常独立于视频,因为音频帧较小(一个 Opus 帧通常只有一个 RTP 包) 且对延迟更敏感。
WebRTC 中音频 Jitter Buffer 的核心实现是 NetEQ,它不仅负责缓冲, 还集成了丢包隐藏(PLC)、加速播放、减速播放等功能。
详细内容参见 Jitter Buffer 和 WebRTC NetEQ 深度解析。
关键参数
参数 |
说明 |
|---|---|
Buffer 大小 |
环形缓冲区槽位数,默认 2048。过小会导致帧不完整,过大会增加内存占用 |
最大等待时间 |
等待缺失包的最长时间。超时后放弃等待,触发 NACK 或 PLC |
解码顺序 |
视频帧需要按解码顺序(DTS)输出,而非按到达顺序(PTS 可能不同) |