H.264编码原理01

2026-06-02 13:57:4329 阅读量

相关服务:香港GPU服务器

YUV 色彩空间(特别是 YUV 4:2:0 采样)。

简单来说,它解释了为什么视频文件能在保持清晰的同时,体积还能压得那么小。以下是详细拆解:


1. 核心公式:视频信号 = 亮度 + 色度

图左侧展示了图像是如何分解的:

  • Luma (Y): 亮度分量。它是图像的黑白底色,包含了细节和轮廓。人类的眼睛对亮度非常敏感。

  • Chroma (UV): 色度分量。它给图像“上色”。人类的眼睛对颜色的分辨率其实没有对亮度那么高。

  • 结论: 只要保证亮度(Y)清晰,稍微压缩一下颜色(UV),肉眼很难发现区别。

2. YUV 4:2:0 采样原理

图右侧那堆密密麻麻的 YU/V 字母解释的是采样方式:

  • Y (Luma): 每一个像素点都有一个 Y。如图所示,Y 是铺满的。

  • U/V (Chroma): 并不是每个像素都有自己的颜色信息。在 4:2:0 采样中,每 4 个亮度像素(2x2 的小方格)共用一组 U 和 V。

  • 为什么要这样做?

    通过这种方式,颜色的数据量直接减少了 75%。因为 Y(亮度)保留了所有细节,你看起来图像依然很清晰,但文件体积却大大缩小了。

3. 图中各部分含义

  • 左图(眼睛): 直观对比。左边是成品,中间是黑白的亮度图(决定清晰度),右边是模糊的色度图(决定颜色)。

  • 右侧字母阵列: 演示了 Y 和 UV 的分布。你可以看到红色的 UV 只有在特定的 Y 节点之间才出现。

  • 箭头指向的右侧 U 矩阵: 表示提取出来的色度分量,它的密度明显比 Y 稀疏很多。


总结

这节课讲的是 “人眼视觉特性”在视频压缩中的应用

它告诉你:为了省带宽和空间,视频工程师把颜色给“减配”了,但利用人眼的弱点,让你觉得画质没变。 这种技术被广泛应用于 H.264、H.265 等几乎所有的现代视频格式中。

这张图解释的是视频压缩技术的底层逻辑——数据冗余(Redundancy)

简单来说,视频之所以能压缩,是因为原始数据里有很多“废话”和“重复的信息”。图中重点介绍了两种最主要的冗余类型:


1. 空间冗余 (Spatial Redundancy)

  • 含义: 指的是单张图片内部相邻像素之间的相似性。

  • 图中解释: 比如一张图片里有一片蓝天,或者像图中这种白色的背景。如果你把图像分成很多 $16 \times 16$ 的小方块(宏块),你会发现很多相邻的方块长得几乎一模一样。

  • 压缩逻辑: 既然大家都一样,我就没必要记录每一个像素点的颜色,我只需要记录“这一片全是白色”或者“参考左边那个块的值”就行了。

  • 应用: 这就是 帧内压缩 (Intra-frame coding)

2. 时间冗余 (Temporal Redundancy)

  • 含义: 指的是视频前后两帧之间内容的相似性。

  • 图中演示: 注意看那个“在线秒表”。

    • 左边是 $01.420$ 秒,右边是 $10.836$ 秒。

    • 虽然时间变了,但你会发现秒表周围的背景、按钮、甚至是“在线秒表”这几个字,在前后几十帧甚至几百帧内都是完全没有变化的。

  • 压缩逻辑: 如果两帧图像之间只有秒表的数字变了,其他地方都没动,那我在存下一帧的时候,只记录变了的那个数字部分,不变的地方直接复用前一帧的数据。

  • 应用: 这就是 帧间压缩 (Inter-frame coding),也就是我们常听到的 I帧、P帧、B帧 的核心原理。


总结:他在讲什么?

这张课件是在告诉你:视频压缩不是靠变魔术,而是靠“找相同”。

  • 空间冗余 是在一张画里找相同(横向找)。

  • 时间冗余 是在一串画里找相同(纵向找)。

通过消除这些重复的信息,视频文件的大小可以从几十 GB 压缩到几百 MB,而你看起来画质却没怎么下降。

你这是在看音视频基础原理的视频吧?这部分内容是理解视频编码格式(如 H.264/AVC)最基础的理论依据。有什么具体的术语没听懂吗?

这张图进入了视频压缩最核心的实战环节:GOP(画面组)结构以及 I、P、B 帧的原理

它解释了视频是如何利用前面提到的“时间冗余”来省空间的,同时引出了一个非常关键的副作用——延迟


1. 三种帧类型的分工(找不同)

图中展示了三种不同角色的帧,它们各司其职:

  • I 帧 (Intra-coded frame): 关键帧。

    • 它是完整的图像,不依赖任何其他帧。

    • 图中位置: 最左边。它是整个序列的“祖宗”,后面的帧都要参考它。

  • P 帧 (Predictive-coded frame): 前向预测帧。

    • 原理: 它只记录与前一帧(I 或 P)的差别

    • 图中演示: 注意看最右边的 P 帧,它发现三角形没变,只有长方体变了,所以它“只记录长方体”的移动和变化。

  • B 帧 (Bipredictive-coded frame): 双向预测帧。

    • 原理: 它最“鸡贼”,既看前面的帧,又看后面的帧。

    • 图中演示: 中间那个 B 帧,它参考了左边的 I 帧(看三角形)和右边的 P 帧(看圆形和长方体),通过两头对比,算出自己的内容。它的压缩率最高,体积最小。


2. 两个关键顺序:解码 vs. 显示

这是图中非常硬核的部分,解释了为什么直播会有延迟:

  • 显示顺序 (1 -> 2 -> 3): 这是我们要看到的正常时间线(I 帧 -> B 帧 -> P 帧)。

  • 解码顺序 (1 -> 3 -> 2): 这是播放器处理数据的真实顺序。

    • 重点: 因为 B 帧(第 2 帧)需要参考后面的 P 帧(第 3 帧)才能计算出来。

    • 结果: 播放器必须先拿到第 1 帧,再拿到第 3 帧,最后才能把第 2 帧拼出来。


3. B 帧带来的代价:编码延迟

图中右侧红字写着:“B 帧带来编码延迟”

  • 原因: 如果你是在做直播,采集到了第 2 帧(B 帧),你不能马上发出去,你必须等第 3 帧(P 帧)也拍好了,才能把这两帧一起编码发走。

  • 结论: * 追求极高压缩率(存电影): 多用 B 帧,文件小。

    • 追求极低延迟(视频通话、直播): 通常会禁用 B 帧,只用 I 帧和 P 帧,因为这样画面拍到就能立刻发出去,不用等后面的帧。

总结

这张图的核心结论是:为了达到更高的压缩比,我们引入了双向参考的 B 帧,但也因此付出了“等待后续帧”的时间代价。

所以下面的0号秒编码i帧

是的,你抓住了重点。

图中底部的红字 “0ms: 编码I帧 ---- 直接发送出去” 解释了直播或实时视频传输中的起步逻辑

1. 为什么 0 毫秒必须是 I 帧?

因为 I 帧是“自给自足”的。在视频流刚开始(0ms)或者播放器刚点进去的那一刻,它手里没有任何参考数据。如果不发一个完整的 I 帧,解码器就没法画出第一张画。

2. “直接发送出去”意味着什么?

这对应了低延迟的需求:

  • 无依赖: I 帧不需要等待后续的 P 帧或 B 帧。

  • 零延迟处理: 只要摄像头采集完这一帧,编码器立刻就能把它打包发给观众。

  • 建立基准: 这一帧发出后,后面的 P 帧就可以基于这一帧去计算“变动的地方”了。

3. 结合你之前的图来看

如果你在 0ms 发送的是一个 B 帧,那麻烦就大了:

  • 观众的电脑得先收到 0ms 的 B 帧(打不开,得等),再收到 40ms 甚至 80ms 后的 P 帧。

  • 这样观众看到第一张脸的时间,就至少落后了 80 毫秒以上。


这里的逻辑链条是:

  1. 0ms: 采集到第 1 帧画面。

  2. 编码为 I 帧: 体积虽然大(包含全部像素),但不需要等别人。

  3. 立刻发送: 观众端秒开,并以此为基础,等待后续 40ms、80ms 发来的 P 帧增量数据。

所以说,I 帧是视频流的“锚点”。 无论是刷短视频的第一秒,还是直播点进去的一瞬间,你接收到的第一个包绝对是一个 I 帧。

你现在看这几张图,是不是已经能把色彩空间(YUV)、**数据冗余(找相同)帧类型(I/P/B)**这三者串起来了?这正是视频系统从“图像”变成“流”的完整过程。

所以先发p帧再发b帧

对头!在包含 B 帧的视频流中,**传输顺序(和解码顺序一致)**确实是先发 P 帧,再发 B 帧。

我们可以用你图里的逻辑梳理一个“时间线”,你就能秒懂为什么必须“插队”:

1. 现实中的顺序(显示顺序)

假设每帧间隔 40ms:

  • 第 1 帧 (0ms): I 帧(我是祖宗,直接发)。

  • 第 2 帧 (40ms): B 帧(我要看前后两帧)。

  • 第 3 帧 (80ms): P 帧(我只看前面的 I 帧)。

2. 传输和解码的顺序(插队逻辑)

为了让第 2 帧(B 帧)能顺利解出来,服务器必须玩个花招

  1. 先发 I 帧 (第 1 帧): 客户端收到,直接画出来。

  2. 跳过 B 帧,先发 P 帧 (第 3 帧): 客户端收到,先憋着不显示,存进缓存里。

  3. 再发 B 帧 (第 2 帧): 此时客户端手里既有 I 帧,又有 P 帧,终于可以把夹在中间的 B 帧算出来了。

所以结论是:

解码/传输顺序: I -> P -> B

显示顺序: I -> B -> P


3. 这也就是为什么直播会“卡”或者“延迟”

  • 编码端: 摄像机拍到了第 2 帧,但它不能发,它得等第 3 帧拍完。这一下就白白等了 40ms

  • 解码端: 观众手机收到了第 3 帧,也不能显示,得等第 2 帧到了才能一起排队显示。

总结一下你的思路:

你说的非常对。在有 B 帧的情况下,P 帧必须比 B 帧先走,因为 P 帧是 B 帧的“参照物”。

一个小考点:

如果老师问你,如何把直播延迟降到最低?

你现在就可以抢答:“把 B 帧删了,全部改成 I 帧和 P 帧,这样就不存在‘等下一帧’的逻辑,拍到哪发到哪!”(这就是为什么很多低延迟直播协议,比如 WebRTC,默认都不用 B 帧的原因)。

这张图通过时间线(Timeline)的方式,彻底拆解了为什么 B 帧会导致延迟的物理过程。它把每一毫秒发生的事情都列出来了,非常硬核。

我们按照图中的时间点(假设帧间隔是 40ms)来翻译一下:


1. 0ms:起步阶段

  • 动作: 摄像头采集到第 1 帧,编码为 I 帧

  • 状态: 因为 I 帧不依赖别人,所以立刻直接发送

  • 结果: 延迟为 0(理想状态下)。

2. 40ms:尴尬的等待期

  • 动作: 摄像头采集到第 2 帧,按照算法,这一帧打算编成 B 帧

  • 困境: 图中红字写着 “是否能编码 B 帧?不能完成编码”

  • 原因: 因为 B 帧是双向参考的,它需要知道“未来的第 3 帧”长什么样才能动笔。此时第 3 帧还没拍出来呢!

  • 结果: 40ms 的时候没有数据可以发送。网络是空闲的,观众在干等。

3. 80ms:爆发式补发

  • 动作: 终于,第 3 帧(P 帧)拍出来了。

  • 逻辑: 1. 编码器终于集齐了第 1 帧和第 3 帧,现在可以回头把 40ms 时的那个 B 帧 编出来了。

    2. 此时手里有两颗“炮弹”:第 3 帧(P 帧)和第 2 帧(B 帧)。

  • 发送顺序: 按照咱们刚才讨论的,先发第三帧 P 帧,再发第二帧 B 帧

  • 代价: 此时第 2 帧已经迟到了整整 40ms 甚至更多,这就是所谓的编码延迟


4. 图中那个关键的提问

图中有一行小字问:“编码的时间点为啥 P 帧是在 B 帧后面,如果 P 帧在前面不就没有延迟了?”

这其实是一个很好的反向思考:

  • 如果视频里全是 I P P P 这样的序列(没有 B 帧),那么 40ms 的时候拍到 P 帧,P 帧只参考前面的 I 帧,它可以立刻发走

  • 结论: 确实,去掉 B 帧,延迟就消失了。但代价是文件会变大,因为 P 帧的压缩率没有 B 帧高。


总结

这张图的核心是在算账:

为了省点流量(用 B 帧),你必须在时间线上“憋”一帧的时间。

这就是为什么在打游戏、视频通话、互动直播时,技术人员会咬牙切齿地把 B 帧关掉——因为实时性比省那点流量重要得多

你现在对这个“憋数据”的过程理解了吗?这就是音视频开发里著名的 PTS(显示时间戳)DTS(解码时间戳) 不一致的根本原因。

为什么可以没有b帧

可以没有 B 帧,是因为 B 帧(双向预测帧)虽然是“压缩高手”,但它不是“必需品”

视频编码器完全可以只用 I 帧和 P 帧来工作。以下是为什么可以没有 B 帧的三个核心原因:

1. 为了极低的延迟(实时性优先)

这是不使用 B 帧最常见的理由。

  • 有 B 帧: 编码器必须等到“未来”的帧产生后,才能回头编码当前的 B 帧。这会导致至少 1-2 帧的物理等待延迟。

  • 没有 B 帧: 采用 IPPP 模式。每一帧 P 帧只参考它前面的帧。摄像头拍到一帧,编码器立刻就能算出一帧,算完立刻发走。

  • 应用场景: 视频通话(微信/飞书)、云游戏、远程监控、低延迟直播。在这些场景下,哪怕视频体积大一点,也要保证画面能“秒到”。

2. 降低硬件性能开销

  • 内存占用: 编码或解码 B 帧时,设备需要同时在内存里缓存“前一个参考帧”和“后一个参考帧”。如果去掉 B 帧,缓存压力会减小。

  • 计算复杂度: B 帧的算法最复杂(它要进行双向运动补偿)。对于一些低功耗的嵌入式设备、老旧的监控摄像头,它们可能跑不动复杂的 B 帧算法,所以直接舍弃。

3. 编辑和剪辑的便利性

  • 在专业的视频剪辑领域(如 ProRes 或 DNxHR 格式),经常甚至连 P 帧都不要,只保留 全 I 帧(All-Intra)

  • 如果没有 B 帧(甚至没有 P 帧),剪辑软件在拖动时间轴时,不需要进行复杂的跨帧换算,电脑性能损耗极低,每一帧都是独立的,剪辑极其流畅。


总结:性能与体积的博弈

你可以把视频编码想象成存钱

  • I 帧 是全额现金(体积大,最稳)。

  • P 帧 是欠条(只记变化量,体积小)。

  • B 帧 是极其复杂的金融衍生品(体积最小,但计算和兑现都要花时间)。

如果你追求省空间(存硬盘看电影),B 帧越多越好;

如果你追求快(打视频电话),B 帧就是累赘,必须去掉。

你现在接触到的这套知识点,其实就是音视频开发中经常听到的 “低延迟优化” 的核心。在你的实验环境(SRS、FFmpeg)中,如果你推流时加上 -bf 0 参数,就是在强制告诉编码器:“我不要 B 帧,我要快!”

这个逻辑在你之前的实验(SRS + Docker)中实践过吗?

这张图讲的是音视频开发中一个非常关键的参数:GOP(Group of Pictures,画面组)长度,以及它如何影响直播的秒开(首屏加载速度)

图中通过对比解释了:为什么在直播领域,GOP 不能设置得太长。


1. 什么是 GOP?

GOP 是指两个 I 帧 之间的间隔。

  • 如图中所示,一个 GOP 是从一个 I 帧开始,后面跟着一堆 P 帧或 B 帧,直到下一个 I 帧出现前结束。

  • GOP Length 计算公式:$秒数 \times 帧率$。图中举例:$5秒 \times 25fps = 125帧$。

2. 直播痛点:为什么 GOP 5 秒太长了?

图中用两条彩色线展示了观众点进直播间时的两种命运:

  • 运气好(红线): * 观众点进直播间时,服务器刚好正在发 I 帧

    • 结果: 播放器拿到 I 帧直接解码显示,画面秒开

  • 运气差(蓝线 - “完美错过 I 帧”):

    • 观众点进直播间时,I 帧刚发完,现在正在发 P 帧

    • 致命问题: 播放器手里没有“祖宗”I 帧,根本解不出这些 P 帧。

    • 结果: 观众必须等。如果 GOP 是 5 秒,极端情况下观众要对着黑屏等 接近 5 秒,直到下一个 I 帧出现。

3. 直播领域的黄金准则

图中的核心结论是:直播领域的 GOP 绝对不能设置太长。

  • 电影/视频文件: GOP 可以很长(比如 10 秒),因为你可以随意拖动进度条,播放器会预读,而且文件体积小。

  • 直播间: 为了保证用户“秒开”,通常 GOP 设置为 1-2 秒

    • 这样观众最倒霉也就等 1 秒多就能看到画面。

    • 虽然 I 帧多了会导致文件稍微大一点点,但为了首屏秒开的体验,这个代价是必须付出的。


总结

这张图解释了**用户体验(秒开)与压缩效率(GOP 长度)**之间的平衡:

  1. I 帧是进入直播间的门票。

  2. GOP 越长,门票发的频率越低,新来的观众等得就越久。

  3. 5 秒的 GOP 会让直播间流失大量新观众。

你之前在配置 SRS 服务器或者用 FFmpeg 推流时,有没有注意到 -g 或者 gop_size 这个参数?通常我们会设为帧率的 1 倍或 2 倍。你在自己搭建的直播环境下测试过不同 GOP 长度的加载速度吗?

这张图是对前面几张散点知识的官方总结和定义。它把 GOP 的概念从“直观理解”上升到了“工程参数”层面。

以下是这张课件的核心知识点拆解:


1. 引入了更专业的术语:IDR 帧

  • 定义: 每一个序列的第一个图像叫做 IDR 图像(Instantaneous Decoding Refresh,立即刷新图像)

  • 关系: IDR 图像一定是 I 帧,但 I 帧不一定是 IDR 帧。

  • 作用: IDR 帧是一个“断层”标记。它告诉解码器:“从我这里开始,清空所有缓存,前面的参考帧都作废,大家从头开始看。”

  • GOP 长度: 两个 IDR 帧之间的距离。

2. GOP 长度的影响(博弈论)

这里总结了一个非常经典的工程矛盾:

  • GOP 越大(I 帧越稀疏): * 优点: 压缩效率越高(因为 I 帧最占空间,P/B 帧多,文件就小)。

    • 缺点: 视频流恢复能力差(如果你网络抖动丢了一个包,可能要等好几秒画质才能恢复正常)。

  • 反之亦然: GOP 越小,视频越大,但抗网络波动能力强,点进去显示得也快。

3. 实战参数建议

课件给出了非常具体的工业配置参考:

  • 直播场景: 如果一秒 25 帧,GOP 设置为 25 或 50(即 1 秒或 2 秒发一个 I 帧)。这是为了兼顾“秒开速度”和“流畅度”。

  • 非直播流(点播/存文件): * 可以把 B 帧设置为连续 2 帧(比如 IBBPBBP...)。

    • 目的: 极大地降低码率(文件体积),反正用户是下载着看或者点播看,不差那点编码延迟。


💡 深度分析:为什么是“帧率的倍数”?

图中提到 “一般是帧率的倍数”。这样做是为了保证 GOP 的时长是整数秒

如果你设置 GOP 为 50,帧率 25,那么正好每 2 秒一个 I 帧。这对于服务器计算切片(比如 HLS 协议的 .ts 文件)非常友好,能对齐时间戳。

总结

这张课件是把你之前的零散感觉转化成了可操作的配置代码。比如你之后用 FFmpeg 推流,你就会知道为什么要写 -g 50 -bf 2 这样的参数了。

你看到这里,音视频压缩的“时间、空间、质量”三者之间的三角博弈关系应该已经非常清晰了。这些基础打扎实了,以后调优推流服务器(SRS)时,你就知道每个参数背后的意义了。

为什么设置b帧降低码率

设置 B 帧之所以能显著降低码率(即减小文件体积),核心原因在于它的参考机制比 P 帧更“贪婪”,从而实现了更高的压缩效率。

我们可以从以下几个维度来理解:

1. “双向预测”:更精确的找不同

  • P 帧(单向): 只看前面的画。它记录的是:“我比前一帧多了什么、动了什么”。

  • B 帧(双向): 既看前面,又看后面。它记录的是:“我处在前面这帧和后面这帧的中间,我是怎么演变过去的”。

  • 为什么更省钱? 想象你在画一个飞行的皮球。P 帧只能根据上一帧推测球的位置;而 B 帧知道球从哪里来,也知道球要往哪里去。有了前后两个参考点,它描述“变化”所需的字节数就极少。

2. 极高的压缩比

在视频编码的“三兄弟”里,它们的体积通常呈现这样的比例:

  • I 帧: 像是一张高质量的 JPEG 照片(100% 体积)。

  • P 帧: 经过压缩,体积可能只有 I 帧的 20% - 50%

  • B 帧: 压缩最狠,体积通常只有 I 帧的 5% - 10%

  • 结论: 在同样的画质下,你放的 B 帧越多,整个视频序列(GOP)的总大小就越小。

3. “物尽其用”:利用人眼的生理弱点

  • B 帧在设计上就被定义为“非参考帧”(通常情况下)。这意味着 B 帧即便丢了一点细节,也不会影响到后面帧的清晰度。

  • 编码器会故意给 B 帧分配更低的质量(更高的量化参数值),反正它只是一闪而过的过渡。利用这种“牺牲”,换取了极大的码率节省。


形象比喻:

如果把视频编码比作补全一句话

  • I 帧: “今天天气真的非常不错。”(全文完整记录)

  • P 帧: “同上,多了一个‘哈’字。”(参考前面,记录增量)

  • B 帧: “夹在上面两句中间。”(通过两头推导,几乎不占字数)

实际工程中的应用

在你刚才看的课件里提到:“非直播流,B 帧一般设置 2 帧连续”

  • 如果你设置序列为 IBBPBBP,这比 IPPP 模式在同等画质下,码率能降低 20% - 40% 左右。

  • 这也是为什么你在 B 站看视频或者存电影时,文件里到处都是 B 帧,因为对于离线视频来说,省流量、省空间才是硬道理。

你现在明白为什么课件里说“B 帧降低码率”了吧?它就是用计算量(CPU 累)时间(延迟高)换取了更细致的差分信息

既然你正在研究这块,你之后在自己跑 FFmpeg 命令时,可以试着对比一下加了 -bf 2(开启两个 B 帧)和 -bf 0(关闭 B 帧)后的文件大小差异,效果会非常明显。

所以直播里b帧不是越低越好吗

没错,你一语道破了直播工程学的核心权衡。

在**直播(尤其是对延迟极度敏感的互动直播)**里,你的直觉非常精准:B帧确实是越少越好,甚至最好是 0。

为了让你理解得更透彻,我们可以把这个逻辑拆解为两个极端场景:


1. 为什么直播要“痛杀”B帧?(延迟是天敌)

正如你之前分析的那张时间线图,只要有 B 帧存在,编码器就必须“等”。

  • 物理延迟: 必须等后一帧拍出来,当前的 B 帧才能编码。

  • 逻辑延迟: 必须先发 P 帧,再发 B 帧。

  • 后果: 在像连麦、打游戏直播、或者是电商秒杀抢购这种场景下,40ms 或 80ms 的额外延迟可能就是“生与死”的区别。所以,专业的直播推流通常会将 B 帧设为 0。

2. 那为什么 B 帧还没被“开除”?(带宽是成本)

既然 B 帧这么耽误事,为什么还没从视频界消失?因为它有一个杀手锏:省钱

  • 高画质 vs 低码率: 如果你是在做一个晚会直播或者体育比赛直播,延迟 2-3 秒其实没人在乎,但画面一定要清晰。

  • 成本博弈: 如果不用 B 帧,达到同样的画质可能需要 8Mbps 的带宽;用了 B 帧,可能只需要 5Mbps。对于平台来说,这省下的 3Mbps 乘以百万观众,就是天文数字般的带宽费。


3. 直播配置的“潜规则”总结

根据你的学习进度,你可以记住这套工业界常用的选择:

场景B 帧设置核心诉求
视频会议 / 云游戏必须为 0追求绝对的实时,延迟 > 100ms 就没法玩了。
互动直播(主播连麦)通常为 0保证主播和观众说话能对得上,不卡顿。
普通秀场直播 / 赛事0 或 1在延迟和画质之间找个平衡点。
电影点播 / 短视频2 或更多不怕延迟(反正有预加载),只求文件越小越好。

💡 给你一个“高手级”的思考

你正在学习的这些知识点,实际上是在做一个三元博弈

  1. 码率(文件大小/带宽成本)

  2. 延迟(实时性)

  3. 画质(清晰度)

你想降低码率(省钱)? 那就得加 B 帧,但延迟就上来了。

你想降低延迟(快)? 那就得砍掉 B 帧,但码率就上来了(为了保住画质)。

所以,你说“B 帧越低越好”是对的,但前提是你在**“追求速度”**这条赛道上。如果你哪天成了视频网站的老板,想省带宽费,你可能反而会觉得“B 帧越多越好”了。

你现在的思路已经完全进入音视频专家的逻辑了。你打算在你那个 Docker 里的 SRS 环境试着把 B 帧关掉(-bf 0)看看延迟的变化吗?

没看懂为什么b帧越多文件越小

其实道理很简单,你可以把 B 帧想象成一个**“超级省话大王”**。

为了让你秒懂,我们不用专业术语,直接用**“记账”**来打比方。

假设你要向朋友描述一个人从左边走到右边的三张照片:


1. 如果没有 B 帧(只有 I 帧和 P 帧)

  • 第 1 张 (I 帧): 你必须画出整个人,背景、衣服、五官,全部画出来。(画了 100 笔

  • 第 2 张 (P 帧): 你参考第 1 张,只写:“人向右挪了 10 厘米”。(写了 10 笔

  • 第 3 张 (P 帧): 你参考第 2 张,又写:“人又向右挪了 10 厘米”。(又写了 10 笔

  • 总成本:120 笔。

2. 如果引入了 B 帧(I - B - P 模式)

  • 第 1 张 (I 帧): 还是画全整个人。(100 笔

  • 第 3 张 (P 帧): 参考第 1 张,写:“人挪到了最右边 20 厘米处”。(10 笔

  • 第 2 张 (B 帧): 此时它最聪明,它看着左边的 I 帧和右边的 P 帧,直接写:“我正好就在你们两个的正中间。”

  • 关键点: 因为它同时参考了“过去”和“未来”,它描述自己位置的时候,逻辑极度精简,甚至可能只需要 2 笔 就能说清楚。

  • 总成本:112 笔。


为什么 B 帧能“省话”?

  1. 双向参考更准:

    单向参考(P 帧)就像“盲人摸象”,只能猜下一步。双向参考(B 帧)就像“填空题”,已知开头和结尾,填中间那个空是非常容易且准确的,所以它记录的“差值数据”极小。

  2. 预测更“便宜”:

    在视频编码里,描述“物体动了多少”比描述“物体长什么样”要省钱得多。B 帧因为有两个参考源,它能找到最像自己的块,剩下的微小差异(残差)就变得非常少,数据量自然暴跌。

  3. 数据丢了也没关系:

    编码器在压缩时,会故意给 B 帧分配更少的带宽(码率)。因为它知道 B 帧不作为别人的参考,即便稍微模糊一点点,只要下一帧 P 帧或 I 帧是清晰的,人眼就会自动“脑补”过去,觉得整体画质还行。


总结

B 帧越多,视频里这种“半卖半送”的参考帧比例就越高。

虽然每帧都还是 1/25 秒,但由于 B 帧只有 I 帧体积的 5% 甚至更小,所以当你把视频里大量的 P 帧换成 B 帧时,整个文件就像挤掉了水分的海绵,体积迅速缩水。

这回能理解为什么它能让文件变小了吗?

什么带宽码率啊,为什么要把p帧换成b帧

这两个词是音视频开发的“度量衡”,理解了它们,你就能看懂为什么我们要费尽心思把 P 帧换成 B 帧了。


1. 什么是码率(Bitrate)?

码率就是:1 秒钟的视频,包含了多少数据量。

它的单位通常是 Mbps(兆位每秒)。

  • 低码率: 1 秒的数据量少。文件小,网络要求低,但画质可能像打了一层马赛克。

  • 高码率: 1 秒的数据量大。文件大,画质非常清晰,但如果你网速慢,看视频就会一直转圈。

2. 什么是带宽(Bandwidth)?

带宽就是:你的“网速上限”。

你可以把它想象成一根水管

  • 如果视频的码率大于你的带宽(水流比水管粗),视频就会卡顿。

  • 对于直播平台老板来说,带宽就是钱。给 100 万观众看 8Mbps 的视频,和看 4Mbps 的视频,老板付给电信运营商的钱差了一倍。


3. 核心问题:为什么要把 P 帧换成 B 帧?

把 P 帧换成 B 帧,其实是在玩一个**“偷梁换柱”**的游戏,目标是:在不降低画质的前提下,强行把码率压下去。

场景 A:全是 P 帧(无 B 帧)

如果你想让观众看清楚,可能每秒需要发 10MB 的数据。

  • 缺点: 码率高(10MB/s),对观众网速要求高,平台带宽费极贵。

场景 B:把部分 P 帧换成 B 帧

因为 B 帧体积超级小(只有 P 帧的几分之一),换完之后:

  • 同样的一秒钟,数据量可能从 10MB 掉到了 6MB

  • 神奇之处: 观众看起来,画面清晰度几乎没变


总结:换成 B 帧的本质逻辑

  1. 为了省钱: 同样的清晰度,用 B 帧能让视频文件变小。如果一个视频从 1G 变成 700MB,老板能省下 30% 的流量费。

  2. 为了不卡: 观众的“水管”(带宽)是有限的。如果我能用更低的码率(B 帧多一点)传出同样的画质,那些网速不太好的观众也能流畅观看,不会卡顿。

一句话总结:

把 P 帧换成 B 帧,就是为了用更少的“流量”(码率),装下同样清晰的“画面”。

你现在理解为什么在做离线视频(比如存电影、发短视频)时,大家拼了命也要多塞点 B 帧进去了吧?因为在这些场景下,省流量就是最高的优先级。

你是在为你那个直播服务器计算带宽成本吗?

为什么能把 P 帧换成 B 帧

这其实是在问:编码器凭什么觉得 B 帧能代替 P 帧?

答案很简单:因为 B 帧是 P 帧的“加强版”。它们都是为了记录“变化”,但 B 帧记录变化的方式更高级。

我们可以从以下三个层面拆解:

1. 逻辑层面:只要有“参照物”就行

视频压缩的核心逻辑是:“能不画就不画,找个参考凑合一下”。

  • P 帧说: 我参考过去(前一帧),算算我变了多少。

  • B 帧说: 我既参考过去(前一帧),又参考未来(后一帧),算算我在它们中间是什么样的。

既然 B 帧也能通过参考(Prediction)把图像拼出来,那它在逻辑上就能完全替代 P 帧。


2. 物理层面:它比 P 帧更省空间

为什么我们要费劲把 P 帧换成 B 帧?因为 B 帧更“虚”

  • P 帧: 它是实打实的增量。比如人往右走,它要记录“人挪动了”这个完整的信息。

  • B 帧: 它是“插值”。因为它看到了开头(前一帧)和结尾(后一帧),它记录的信息更像是“补全中间的残影”。

由于 B 帧有两个参考源,它能找到的“相同部分”更多,剩下的“不同部分”(残差)就非常小。在计算机里,残差越小,占用的比特位(Bit)就越少,文件就越小。


3. 工程层面:牺牲“时间”换取“体积”

你能把 P 帧换成 B 帧,是因为你接受了延迟

  • 如果不换(全用 P 帧): 采集到第 2 帧,参考第 1 帧,,编码发走了。速度极快。

  • 如果换成 B 帧: 采集到第 2 帧,编码器说:“别急,我得等第 3 帧(P 帧)出来,我好前后对比一下。” 于是第 2 帧被扣在了内存里。

总结一下:

你可以把 P 帧换成 B 帧,是因为你觉得**“文件小、省带宽”“实时性”**更重要。

为什么现在的软件默认都这么干?

因为在非直播场景(比如你拍个视频发朋友圈、看 B 站),多等 100 毫秒的编码时间你根本没感觉,但如果视频体积能从 100MB 缩减到 60MB,你的流量费省了,下载速度也快了。这就是“白给”的福利,所以大家都会把 P 帧尽可能换成 B 帧。

你现在能把这个“等一帧”的延迟逻辑,和你刚才看的那些时间线图对上了吗?

这张图讲的是播放器中一个非常经典的操作:Seek(拖动进度条) 的底层逻辑,以及为什么有些视频拖动时会卡顿或者“马赛克”。

这里核心解释了 “Seek 必须找 I 帧” 的原则。


1. 核心动作:Seek 清空解码器

当你拖动进度条(比如从 10 秒拉回到 5 秒)时,播放器会执行一个动作:清空解码器状态

  • 为什么要清空? 因为之前的解码器里存的是 10 秒前后的参考信息。你突然跳到了 5 秒,之前的参考信息全没用了,必须“毁迹灭迹”重新开始。

2. 图中的尴尬情况:Seek 到了 P 帧

图中展示了一个很惨的情况:

  • 目标位置: 你想看 5 秒 处的内容。

  • 现实情况: 5 秒那个地方正好是一个 P 帧

  • 结果: 虽然解码器清空了,准备开始干活,但它发现 5 秒这个 P 帧是个“残废”,它必须参考前面的 I 帧才能画出来。可是此时解码器是空的!

3. 两种命运

  • 蓝色线(完美错过 I 帧):

    如果你非要从 5 秒这个 P 帧开始播,解码器就傻眼了。表现出来就是:画面卡住不动,或者出现一堆花花绿绿的马赛克,直到下一个 I 帧(比如图中的 10 秒处)出现,画面才会恢复正常。

  • 红色线(刚好拉到 I 帧):

    如果你运气好,或者播放器足够聪明(做了关键帧对齐),它会让你直接跳到最近的一个 I 帧。画面秒开,非常流畅。


4. 深度总结:为什么 5 秒的 GOP 让人痛苦?

结合你之前的图:

  • 如果一个视频的 GOP 是 5 秒(即每 5 秒才有一个 I 帧)。

  • 你在拖动进度条时,播放器为了保证画面不花,往往会强制帮你跳转到最近的那个 I 帧。

  • 这就会导致:你明明想看 7 秒,它非把你弹回 5 秒;或者你想看 9 秒,它把你弹回 5 秒。这种**“拖不动”或者“乱跳”**的感觉,就是因为 I 帧太稀疏了。

💡 总结一下

这张图是在告诉你:I 帧不仅是直播的“开门砖”,也是播放器进度条的“锚点”。 GOP 设置得短(比如 1-2 秒),不仅直播秒开快,用户拖动进度条时的精准度和流畅度也会高很多。

你现在明白为什么有些劣质网页播放器,进度条一拽就卡死,或者画面要闪好几秒了吧?那就是 GOP 太长,且播放器没处理好“非关键帧 Seek”的问题。

这张图带你进入了视频编码的最后一步,也是最数学化的一步:熵编码(Entropy Coding)与 Z 字形扫描(Zig-Zag Scan)

如果你把之前的 YUV、帧间预测比作“脱水”,那这一步就是“真空包装”。


1. 扫描像素值的目的:为了编码

图中左侧那个 $4 \times 4$ 的矩阵代表的是图像经过变换(如 DCT 变换)和量化后的系数。

  • 为什么要有那个箭头的路径(Z 字形扫描)?

    • 在图像处理中,能量通常集中在左上角(低频部分,代表图像的大致轮廓)。

    • 越往右下角,数值通常越小,甚至会出现大量的连续 0(高频部分,代表细节)。

    • Z 字形扫描能把二维矩阵变成一维序列,并且让大数字排在前面,0 排在后面。这样在存储时,就可以用极短的代码表示“后面全是 0”,从而大幅节省空间。

2. 核心逻辑:出现概率越大,用越少的 bit 表示

图中红字写着:“出现概率越大的,使用更少的 bit 表示”

这是信息论里的 哈夫曼编码(Huffman Coding)算术编码(Arithmetic Coding) 的核心思想:

  • 举个例子: 如果视频里“0”出现的频率是 90%,我们就给“0”分配一个超级短的代号(比如 1);如果“212”这种大数字很少出现,我们就给它分配一个长代号(比如 1101010)。

  • 结果: 整体算下来,总的比特数(bit)就会变得非常少。

3. 编码压缩:数值越小,字节越少

  • 结合你之前看的 P 帧B 帧

    • 因为 P/B 帧只记录“残差”(差值),这些差值通常都很小(接近 0)。

    • 数值越小,经过这种“概率预测”编码后的字节数就越少。

  • 这就是为什么 B 帧文件小的终极原因: 它的残差值经过这一步处理后,几乎被压缩到了极致。


总结:视频压缩的全过程

看到这张图,你其实已经把视频编码的完整链路串起来了:

  1. 色彩空间转换: RGB 转 YUV,把颜色信息抽稀(图 1)。

  2. 空间冗余: 找一张图里的重复部分(图 2)。

  3. 时间冗余: 找前后帧的重复部分,生成 I、P、B 帧(图 3、4、5)。

  4. 变换量化: 把图像变成图中这种数字矩阵。

  5. 熵编码: 按照图中这种 Zig-Zag 路径 扫描,用“短代号”代替“高频数”,完成最后的压缩(图 8)。

💡 老师想表达的意思:

他在讲 “变长编码”。视频不是像存文本文件那样一个字符占 8 位,而是聪明的编码器会根据数字出现的频率动态分配长度。**“省掉废话”**就是视频压缩的最后一道工序。

你这套课件含金量很高啊,从物理采样一直讲到了信息论底层。这部分关于“扫描路径”和“概率编码”的内容,你在写代码(比如用 FFmpeg 配置 entropy 编码器)时会遇到相关的参数选择(如 CABAC 或 CAVLC)。

现在你对整个视频从摄像头拍到、到压成 MP4 发出去的流程,是不是感觉已经通关了?

我让你分析这个照片里的内容,什么垂直预测

这张图展示的是 H.264 编码中非常核心的“帧内预测 (Intra Prediction)” 技术。

简单来说,它的目的就是:消灭一张图片内部的重复信息(空间冗余)

以下是详细拆解:

1. 核心原理:相邻像素的相关性

  • 现象:在同一张画面里,相邻的像素通常非常接近(比如蓝天的一片区域,像素值几乎一样)。

  • 策略:既然相邻像素差不多,我们就不记录每个像素的具体数值,而是用“邻居”的值来预测当前块的值,最后只记录两者的差值

2. 什么是“垂直预测”和“水平预测”?

图中展示了两种具体的预测模式(以 $4 \times 4$ 的像素小块为例):

  • 垂直预测 (Vertical Prediction)

    • 操作:把上一行像素的值直接“复制”下来,作为下面每一行像素的预测值。

    • 适用场景:画面呈现上下纹理一致时。

  • 水平预测 (Horizontal Prediction)

    • 操作:把左侧一列像素的值水平地“推”过去,作为右侧每一列像素的预测值。

    • 图中演示:你看右侧那个标注“这个小块是预测”的图,它就是把最左边的数值(212, 170, 128, 96)直接横向填充到了整行。

3. 为什么要算“差值 (Residual)”?

这是压缩最精妙的地方。图中给出了一个公式:

$$\text{原始值 } X - \text{预测值 } X_p = \text{差值 } d$$

  • 原始块:里面的数值很大(比如 212, 189 等),直接存储很占空间。

  • 预测块:利用左侧块预测出来的“假想图”。

  • 残差块 (黄框部分):这是最终要存储的数据。你会发现里面的数值变得非常小(比如 0, 2, 6 等)。

4. 结论:为什么这样能压缩?

在计算机里,存一个大数字(比如 212)需要的比特位很多,而存一个小数字(比如 0 或 2)需要的比特位非常少。

  • H.264 就是通过这种方式,把原本饱满的图像数据变成了大量接近 0 的微小差值。 * 再结合你之前看的那张 Zig-Zag 扫描图,这些小数字和大量的 0 会被极度压缩,从而实现视频体积的暴减。

一句话总结

垂直/水平预测就是利用已知的像素去“猜”未知的像素。猜得越准,剩下的差值就越小,视频文件也就越小。

你现在能理解为什么这个步骤叫“帧内”预测了吗?因为它只在这一张画里找规律,还没涉及到前后的运动。

原始值是本来的图,预测值是上一张图的值

不完全是,这是一个非常容易混淆的点。

H.264 的“帧内预测”(也就是你这张图 1000109408.jpg 讨论的场景)中,预测值并不是来自“上一张图”(上一帧),而是来自**“当前这张图”里已经编码过的邻居像素**。

我们来精准拆解一下:

1. 预测值从哪来?(当前帧的邻居)

  • 帧内预测 (Intra Prediction):预测值来自当前画面中,该块左边或者上面的像素。

    • 垂直预测:把“头顶上”那行像素向下复制。

    • 水平预测:把“左手边”那列像素向右复制。

  • 目的:利用一张图内部的空间相关性来省空间。

2. 你说的“上一张图”叫什么?(帧间预测)

如果你用“上一张图”的值来预测当前图,那叫 帧间预测 (Inter Prediction)

  • 这对应的是你之前看的 P 帧B 帧

  • 它利用的是时间上的重复性(比如背景没动,就直接用上一帧的像素)。


3. 为什么一定要用“邻居”而不用“上一张”?

在编码 I 帧(关键帧) 时,解码器手里还没有任何“上一张图”的数据。

  • 为了让 I 帧能独立打开(秒开),它只能“自力更生”,在自己的画面里找规律。

  • 所以,你图里的原始值是你想编码的那个 $4 \times 4$ 小块,预测值是它紧挨着的左侧或上方像素的“克隆体”。

总结

  • 帧内预测(这张图的内容):预测值 = 同图片的左边/上面像素。

  • 帧间预测(P/B 帧的内容):预测值 = 前一张/后一张图片的像素。

这就是为什么图中强调的是“相邻像素的相关性”,而不是“相邻帧的相关性”。这种“空间上的修补”让即便是一个独立的 I 帧,也能被压得很小。

左侧或上方像素的“克隆体”,左侧和上方像素哪来的

这个问题问到了点子上!这涉及到一个非常关键的概念:编码顺序

你可以把编码一张图片想象成**“粉刷匠刷墙”,它是按照从左到右、从上到下**的顺序进行的。

1. 邻居像素是怎么“无中生有”的?

当你准备编码图中那个黄色的 $4 \times 4$ 小块(当前块)时,它的左侧和上方其实已经被编码完了

  • 上方的像素: 是在处理“上一行”宏块时存下来的。

  • 左侧的像素: 是在处理“当前行”的前一个宏块时存下来的。

2. 它们为什么能被当成参考?

因为解码端(播放器)也会按照完全一样的顺序来解码。

  1. 播放器先解出最左上角的像素。

  2. 到了你要看的小块时,播放器手里已经拿到了左边和上面的真实像素值。

  3. 编码器只需要告诉播放器:“喂,用你左边那排像素往右填充,然后再加减我给你的这几个差值。”

  4. 播放器照做,画面就还原出来了。

3. 一个极端的逻辑挑战:最左上角的像素参考谁?

如果你是这张图的第一个像素(坐标 0,0),左边没邻居,上面也没邻居,怎么办?

  • 这时候就不能用“水平”或“垂直”预测了。

  • H.264 有一种模式叫 DC 预测:如果不靠邻居,就取一个默认的平均值(比如 128),或者干脆直接记录原值。


总结

左侧和上方的像素,其实是**“前辈”。 在处理当前这一块的时候,编码器会把紧邻的“前辈”边缘像素暂存在内存里**,专门等着给当前块当“模板”用。

所以,这套逻辑成立的前提是:所有块必须按顺序排队。

这个“粉刷匠顺序”的逻辑,能解释你对“邻居像素来源”的疑问了吗?这也正是为什么 H.264 叫“行扫描”编码的原因。

本文地址:https://www.idc504.com/news/9_95802.html