# 视频码率分配 · 总预算分给各层

> 拥塞控制给了总码率预算，联播/SVC 有多条流多层，怎么分？这一章读 video/video_bitrate_allocator.h:VideoBitrateAllocator 如何把总码率分配到各层、遵循「先喂饱低层再给高层」的原则，以及码率不足时怎么砍掉高层。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/video-bitrate-allocation
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 视频码率分配 · 总预算分给各层

[拥塞控制](https://daiw.org/manual/webrtc/rate-control)给了这条视频流一个**总码率预算**，而[联播 / SVC](https://daiw.org/manual/webrtc/simulcast-svc) 有**多条流 / 多层**。总预算怎么分到各层？这是 **`VideoBitrateAllocator`**（`video/video_bitrate_allocator.h`）的活。分配策略看似简单，却直接影响体验。

## 问题：僧多粥少怎么分

假设总预算 1.5 Mbps，一条 [SVC](https://daiw.org/manual/webrtc/simulcast-svc) 流有三层，各层“吃饱”分别要 300 kbps / 600 kbps / 1500 kbps。怎么分？

<Callout type="info">
  **核心原则：「先喂饱低层，有剩再给高层」——从基础层开始，逐层往上，喂饱一层才喂下一层。** 为什么？因为[层是叠加的](https://daiw.org/manual/webrtc/simulcast-svc)：基础层是一切的地基，没喂饱基础层，高层再多码率也没用（高层依赖低层解码）。所以分配是**逐层填满**：

  - 总预算 1.5 Mbps，先给基础层 300 kbps（喂饱）→ 剩 1.2 Mbps。
  - 再给第二层 600 kbps（喂饱）→ 剩 600 kbps。
  - 剩下的 600 kbps 给第三层（它想要 1500 但只有 600，给它 600，这层就质量打折但能用）。

  如果总预算只有 500 kbps 呢？**只喂得饱基础层（300），第二层只能给 200（不够它的 600）**——那第二、三层可能干脆**不发**（发个半死不活的层没意义）。这就是[联播](https://daiw.org/manual/webrtc/simulcast-svc)里“码率不足时高档流被关掉”的由来：与其每档都发一点点、每档都糊，不如**集中资源保住能保的档**。`VideoBitrateAllocator` 就是执行这套“逐层填、不够就砍高层”逻辑的地方，`GetAllocation` 产出各层的码率分配。
</Callout>

## 音频优先：更上层的分配

再往上看，[码率分配其实是两级的](https://daiw.org/manual/webrtc/rate-control)：

1. **通话级** —— `BitrateAllocator`（[第 9 部分](https://daiw.org/manual/webrtc/source-map)）先在**音频流和视频流之间**分：**音频优先保住**（语音断了通话就废了，而画面糊点还能忍），剩下的给视频。
2. **流级** —— 视频拿到它那份后，`VideoBitrateAllocator` 再在这条视频流的**各层 / 各档之间**分（本章）。

<Callout type="info">
  **“音频优先于视频”是 WebRTC 一个坚定的价值排序。** 想想：视频会议网络突然变差，你更能忍受哪个——**画面糊成马赛克但对方声音清楚**，还是**画面高清但声音断断续续**？几乎所有人选前者：**听不清等于没法沟通，看不清还能凑合**。所以码率紧张时，系统**死保音频**（音频码率需求本就低，几十 kbps 就够），把稀缺的带宽尽量喂给它，视频再[降质 / 砍档](https://daiw.org/manual/webrtc/video-adaptation)。这个“保听觉、让视觉”的优先级，贯穿 WebRTC 的资源分配——是对“实时沟通，声音第一”的深刻理解。
</Callout>

## 分配的动态性

码率分配不是算一次就完——它**随[拥塞控制的目标码率](https://daiw.org/manual/webrtc/rate-control)实时变**。网络变好，总预算涨，`VideoBitrateAllocator` 就把更多码率分给高层、甚至[重新开启之前砍掉的档](https://daiw.org/manual/webrtc/simulcast-svc)；网络变差，预算缩，就逐层减、砍高层。这个分配结果又通过 [`SetRates`](https://daiw.org/manual/webrtc/video-encoder-abstraction) 告诉编码器“每层编多大”。**分配是连接[拥塞控制](https://daiw.org/manual/webrtc/rate-control)和[编码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)的最后一环**——总预算在这里被翻译成每层的具体码率。

## 小结与下一章

**`VideoBitrateAllocator`** 把[总码率预算](https://daiw.org/manual/webrtc/rate-control)分到[联播 / SVC 的各层](https://daiw.org/manual/webrtc/simulcast-svc)，核心原则**「先喂饱低层，有剩再给高层」**（层叠加，基础层是地基），不够就**砍掉喂不饱的高层**（集中资源保能保的）。更上层，`BitrateAllocator`（[第 9 部分](https://daiw.org/manual/webrtc/source-map)）先在**音频 / 视频间**分——**音频优先死保**（声音第一）。分配随[目标码率](https://daiw.org/manual/webrtc/rate-control)动态变，结果经 [`SetRates`](https://daiw.org/manual/webrtc/video-encoder-abstraction) 落到编码器。

编码 + 分配都齐了，压缩帧要打成 RTP 包发出。但不同[编解码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)的打包方式各异。下一章看视频打包。👉 [视频打包](https://daiw.org/manual/webrtc/video-packetization)。

## 参考资料

- [1] libwebrtc 源码.`video/video_bitrate_allocator.h`、`modules/video_coding/utility/simulcast_rate_allocator.h`、`svc/svc_rate_allocator.h`。
- [2] libwebrtc 源码.`call/bitrate_allocator.h`（通话级音视频分配，第 9 部分）。
- [3] 关联[拥塞控制码率控制](https://daiw.org/manual/webrtc/rate-control)。
