🎬 第六章 音视频压缩编码基础
📄 一句话概括

四种帧里最容易混的是 I 帧与 IDR 帧——所有 IDR 都是 I 帧,但不是所有 I 帧都是 IDR;拖动定位找的其实是 IDR。

📝 本节和前面几节的关系

6.4 讲了帧内与帧间编码,6.5 收在三个具体结构上。先分清四种帧。

一、四种帧

I 帧:帧内编码,不参考任何帧——能独立解码。 P 帧:帧间编码,只参考前面的帧。 B 帧:帧间编码,参考前后两侧。 IDR 帧:一种特殊的 I 帧——明确切断与前面所有帧的依赖。

二、I 帧与 IDR 帧的差别

这是最容易混的一点: 所有 IDR 都是 I 帧——它本身也是帧内编码的。 但不是所有 I 帧都是 IDR——有些 I 帧【参考列表里还留着前面的帧】。 差别在实际效果上:IDR 之后的帧,绝不能再参考 IDR 之前的帧。 所以 IDR 才是真正的【随机访问点】。

三、为什么这个差别重要

因为播放器拖进度条时,要找的是 IDR 帧,而不是随便一个 I 帧。 如果从一个普通的 I 帧开始解,后面的帧可能还要参考更早的内容——解不出来。 所以【关键帧间隔】这个参数(5.1.4 提过),严格说的其实是 IDR 间隔。

四、四者的取舍

I/IDR 帧:贵,但提供落脚点——不能没有。 P 帧:省,延迟低——实时场景的主力。 B 帧:最省,但要缓存与重排序——点播场景的主力。 所以编码档位里往往有一项【是否允许 B 帧】,它直接对应延迟与码率的取舍。

五、动手 Demo:I、P、B、IDR 四种帧,各是什么角色

除了 I/P/B,还有一个特殊角色:IDR 帧。

rows = [("I 帧", "能", "不参考任何帧,但未必是随机访问点"),
        ("IDR 帧", "能", "I 帧的一种,明确切断依赖"),
        ("P 帧", "不能", "只参考前面"),
        ("B 帧", "不能", "参考前后,码率最低")]
for a, b, c in rows:
    print("%-8s %-14s %s" % (a, b, c))

实跑输出:

--------------------------------------------------------------------
I、P、B、IDR 四种帧,各是什么角色
--------------------------------------------------------------------

除了 I/P/B,还有一个特殊角色:IDR 帧。

  帧         能否独立解码     关键特征
  -------------------------------------------------------------
  I 帧       能               不参考任何帧,但未必是随机访问点
  IDR 帧     能               I 帧的一种,明确切断依赖
  P 帧       不能             只参考前面
  B 帧       不能             参考前后,码率最低

  最容易混的是前两行:**所有 IDR 都是 I 帧,但不是所有 I 帧都是 IDR。**
  差别在于:**IDR 之后的帧绝不能再参考 IDR 之前的帧**——
  所以拖动定位时,**找的其实是 IDR 帧,而不只是 I 帧**。

最容易混的是前两行:所有 IDR 都是 I 帧,但不是所有 I 帧都是 IDR。 所以拖动定位时,找的其实是 IDR 帧,而不只是 I 帧。

30 秒实验

  1. 用 ffprobe 加 -show_frames 看一段视频,找出其中的 IDR 帧。
  2. 看它们是不是都带着 key_frame=1 的标记。

常见误区

  1. 把 I 帧与 IDR 帧当成一回事。IDR 才是真正的随机访问点。
  2. 以为 B 帧在任何场景都更优。低延迟场景要禁用它。
自测三问(点开对答案) 1. I 帧与 IDR 帧的关系是什么? —— 所有 IDR 都是 I 帧,但不是所有 I 帧都是 IDR。 2. 为什么拖动定位要找 IDR 帧? —— IDR 切断了与前面所有帧的依赖,从它开始才能独立解码。 3. 四类帧在码率与延迟上怎么取舍? —— I/IDR 贵但提供落脚点,P 帧省且延迟低,B 帧最省但要缓存重排序。

相关笔记