视频编码中的 I帧、P帧、B帧
理解 I帧、P帧、B帧是学习视频编解码、WebRTC、直播技术的基础。本文从「为什么需要三种帧」出发,讲清楚三者的定义、解码顺序、以及 WebRTC 为什么不用 B帧。
一、为什么需要这三种帧
视频本质是一串图片,每秒 30 帧就是 30 张图。如果每张都完整存储,1080p 视频 1 秒钟原始数据大约 400MB,完全没法传输。
压缩的核心思路:相邻帧之间变化很小,只记录「变了什么」,不记录「完整画面」。
三种帧就是围绕这个思路设计的:
- I帧:必须有一张完整的参考图
- P帧:只记录相对前一帧的变化
- B帧:同时参考前后帧,压缩率最高
二、三种帧的定义
I帧(Intra-coded frame,帧内编码帧)
1 | 完整的一张图,不依赖任何其他帧,可以独立解码 |
P帧(Predictive frame,预测帧)
1 | 只记录「相对于前一帧,哪些地方变了」 |
B帧(Bidirectional frame,双向预测帧)
1 | 同时参考前一帧(I或P)和后一帧(I或P)来预测当前帧 |
三、解码顺序详解
播放顺序 vs 编码/传输顺序
假设一段视频的播放顺序是:
1 | I B B P B B P I |
但实际编码和传输顺序是:
1 | I P B B P B B I |
为什么要重排?
B帧(第2、3帧)解码时需要参考「后面」的 P帧(第4帧),所以 P帧必须先传输到达,B帧才能解码。编码器提前把 P帧排到 B帧前面。
逐帧解码过程
1 | 收到顺序: I(1) → P(4) → B(2) → B(3) → P(7) → B(5) → B(6) → I(8) |
B帧只依赖 I/P帧,不依赖其他 B帧
这是一个常见的误解:B(2) 和 B(3) 互相不依赖,两者都只参考前后的 I/P 帧。
1 | I B B P |
只要 I(1) 和 P(4) 都到了,B(2) 和 B(3) 可以同时解码,不需要等对方。
特殊情况:分层 B帧(了解即可)
高压缩率编码器(如 x265)会用分层 B帧,B帧之间也可以互相参考:
1 | I P |
中间的 B 参考外层的 B,外层的 B 再参考 I/P。压缩率更高,但解码复杂度和延迟也更大。WebRTC 完全不使用这种模式。
四、B帧引入的延迟
每个 B帧都需要等它后面的 P/I 帧到达后才能解码,播放器必须缓冲几帧,等「未来帧」到齐再解码输出:
1 | 缓冲区:[I(1), P(4), B(2), B(3)] → 等 P(4) 到了才能输出 B(2) B(3) |
五、WebRTC 为什么不用 B帧
1 | B帧需要等「未来帧」到了才能解码 |
只用 I + P 的解码流程
1 | 收到顺序: I(1) → P(2) → P(3) → P(4) → ... |
收到即解码,零缓冲,延迟低。代价是压缩率不如有 B帧的方案,同等画质码率更高。
六、I帧(关键帧)的实际意义
视频跳转(Seek)
视频 seek 时必须找到最近的 I帧开始解码,因为 P/B 帧无法独立解码。这就是为什么有些视频跳转不精确——只能跳到最近的关键帧位置。
花屏恢复
网络丢包导致某个 P帧丢失,之后所有依赖它的帧都无法正确解码 → 花屏。等到下一个 I帧到来才能恢复正常画面。
WebRTC 的 PLI 机制
WebRTC 检测到花屏时,接收端发 PLI(Picture Loss Indication) 给发送端,请求立即插入一个 I帧:
1 | 接收端发现花屏 |
七、对比总结
| I帧 | P帧 | B帧 | |
|---|---|---|---|
| 完整画面 | 是 | 否 | 否 |
| 依赖 | 无 | 前面的 I/P 帧 | 前后的 I/P 帧 |
| 体积 | 大 | 中 | 最小 |
| 解码延迟 | 无 | 低 | 高(需缓冲未来帧) |
| WebRTC 使用 | 是 | 是 | 否 |
| 适用场景 | 所有 | 所有 | 点播/录制 |
最后更新:2026-06