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 需要将这些包重新组装为完整的帧。

关键类

说明

PacketBuffer

通用视频包缓冲区,负责收集 RTP 包并按序号排列,检测帧边界后组装为完整帧

H264PacketBuffer

H.264 专用扩展,处理 H.264 特有的分片(FU-A)和聚合(STAP-A)NAL 单元

RtpFrameReferenceFinder

建立帧间参考关系(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 BufferWebRTC NetEQ 深度解析

关键参数

参数

说明

Buffer 大小

环形缓冲区槽位数,默认 2048。过小会导致帧不完整,过大会增加内存占用

最大等待时间

等待缺失包的最长时间。超时后放弃等待,触发 NACK 或 PLC

解码顺序

视频帧需要按解码顺序(DTS)输出,而非按到达顺序(PTS 可能不同)

参考资料