H.264编码
目录
1 视频的本质
2 核心思路
2.1 空间重复(同一张图内的重复)
2.2 时间重复(前后帧之间的重复)
3 具体压缩步骤
3.1 分块处理
3.2 预测
3.2.1.1 目标
3.3 简化信息
3.4 打包
3.5 修复瑕疵
4 最终效果
5 实际例子
1 视频的本质
视频其实就是一连串快速播放的图片(比如每秒30张图)。但直接保存这些图片会占用巨大的空间,比如一部电影可能要几百GB,根本无法通过网络传输。因此,我们需要一种方法把视频“压缩”到很小,同时尽量保持清晰。
H.264就是一种高效的“视频压缩方法”,像“打包行李”一样,把重复的东西去掉,只保留关键信息。
2 核心思路
H.264的秘诀是找到视频中的“重复内容”并简化它们,主要分两种:
2.1 空间重复(同一张图内的重复)
-
例子:比如一张蓝天白云的图片,很多地方的蓝色像素是相似的。
-
怎么做:H.264会把图片切成小块(比如4x4像素),然后对每个块说:“这一块的颜色和左边那一块差不多,我只需要记录它们的差异就行了!”这样就省了很多空间。
2.2 时间重复(前后帧之间的重复)
-
例子:视频中一个人站着说话,背景不动,只有嘴巴在动。大多数帧的背景几乎一样。
-
怎么做:H.264会说:“这一帧的背景和上一帧一模一样,我只记录人物嘴巴的变化,其他直接复制上一帧!”这样又省了大量空间。
3 具体压缩步骤
假设现在要压缩一段视频,H.264会做以下几件事:
3.1 分块处理
-
把每一帧的图片切成许多小方块(比如16x16像素的“宏块”),就像拼图一样。
为什么要分块?
-
问题:一整张图片直接压缩太复杂,比如1080p的图片有200多万个像素,处理起来效率极低。
-
解决:将图片切成小块,独立处理每个块,就像用乐高积木拼图一样。
块的大小
-
宏块(Macroblock):H.264的基本单位是16x16像素的宏块。
-
每个宏块可以进一步拆分为更小的子块(如8x8、4x4),以适应细节变化。
-
例子:假设你拍一个人的脸,眼睛和嘴巴的细节多,用4x4的小块;额头和背景较简单,用16x16的大块。
-
3.2 预测
-
如果是第一张图(关键帧/I帧):
只用“空间重复”压缩。比如某个块的颜色和周围块相似,就直接预测出来,只记录误差。 -
如果是后续的图(P帧/B帧):
先用“时间重复”压缩。比如在上一帧找到相似的位置,记录“这个块是从上一帧的哪个位置移动过来的”(这叫运动补偿),再记录细微的变化。
3.2.1 帧内预测(I帧压缩):用“拼图”猜颜色
3.2.1.1 目标
-
消除空间冗余:同一张图内相邻区域颜色相近(比如一面白墙)。
3.2.1.2 具体步骤
-
步骤1:对每个4x4或16x16的块,用周围已编码的像素预测当前块的颜色。
-
步骤2:H.264提供9种预测模式(如水平、垂直、对角线等),选择最接近实际颜色的模式。
-
例子:如果当前块的左边像素都是红色,预测模式选“水平”,认为当前块也是红色。
-
-
步骤3:计算预测值和实际值的差异(残差),后续只压缩残差。
3.2.1.3 关键点
-
适合场景:I帧(关键帧)必须用帧内预测,保证后续帧的参考基础。
3.2.2 帧间预测(P/B帧压缩):用“找不同”省空间
3.2.2.1 目标
-
消除时间冗余:前后帧大部分内容相同(比如静止的背景)。
3.2.2.2 核心操作:运动估计与补偿
-
步骤1:运动估计(Motion Estimation)
-
对当前帧的宏块,在参考帧(已编码的前一帧或后一帧)中搜索最相似的区域。
-
找到后,记录两个信息:
-
运动矢量(Motion Vector):当前块相对于参考块的位置偏移(比如“向右移动5像素,向下移动2像素”)。
-
残差:当前块与参考块的细微差异(比如颜色变化)。
-
-
-
步骤2:运动补偿(Motion Compensation)
-
根据运动矢量,从参考帧中复制或插值生成预测块。
-
例子:如果上一帧有一个苹果在画面左侧,当前帧苹果移到右侧,H.264会说:“这个块是从上一帧的(x-5, y+2)位置搬过来的,再稍微调整颜色。”
-
3.2.2.3 高级功能
-
多参考帧:可以从前面多帧甚至后面帧(B帧)中找参考块,提升准确性。
-
子像素精度:运动矢量可以精确到1/4像素,通过插值实现更平滑的运动。
3.3 简化信息
-
变换与量化:
把预测后的误差(比如“实际颜色和预测颜色差了多少”)转换成更简单的数学形式(类似把复杂的波浪线变成几个起伏大的点),然后四舍五入,进一步减少数据量。这一步会损失一些细节,但肉眼不易察觉。
3.3.1 变换(Transform)
-
目标:将残差数据从空间域转换到频域,集中能量。
-
方法:使用整数DCT变换(类似JPEG压缩)。
-
原理:把块内的像素值转换成“频率系数”,高频对应细节(如边缘),低频对应整体颜色。
-
效果:大部分能量集中在低频,高频系数通常接近0。
-
3.3.2 量化(Quantization)
-
目标:减少系数精度,进一步压缩数据。
-
操作:将每个频率系数除以一个“量化步长”(由QP值控制),然后四舍五入。
-
例子:假设系数是100,量化步长是20,量化后变成5(100/20=5);如果步长是50,变成2(100/50=2)。
-
-
代价:量化步长越大,数据量越小,但细节丢失越多(画质下降)。
3.4 打包
-
熵编码:
用更聪明的“打包方式”把数据写进文件。比如“000000”直接写成“6个0”,类似用缩写代替长句子。
3.4.1 目标
-
对量化后的系数和运动矢量进行无损压缩。
3.4.2 两种方法
-
CAVLC(上下文自适应变长编码):
-
根据周围块的数据动态选择编码表。
-
例子:如果当前块残差很小,就用短码表示“全是0”;如果残差大,用长码表示具体数值。
-
-
CABAC(上下文自适应二进制算术编码):
-
更高效,但更复杂。
-
将数据转换为二进制流,根据概率模型动态调整编码。
-
比喻:像用摩尔斯电码,高频符号用短码,低频符号用长码。
-
3.5 修复瑕疵
3.5.1 问题
-
分块压缩会导致块边缘出现锯齿(块效应)。
3.5.2 解决
-
去块滤波(Deblocking Filter):
-
在编码环路内,对块边界进行平滑处理。
-
规则:如果边界两侧颜色差异小,就模糊处理;差异大则保留边缘(避免模糊真实细节)。
-
4 最终效果
-
压缩比极高:原本1GB的视频,用H.264可以压到10MB,甚至更小。
-
保持清晰:虽然细节有损失,但人眼几乎看不出来。
-
适应网络传输:小体积的视频适合在线观看(比如抖音、YouTube都用了H.264)。
5 实际例子
假设压缩一段“小鸟飞过蓝天”的视频
-
第一帧(I帧):
-
切成16x16宏块。
-
对每个块做帧内预测(比如天空部分用“水平预测”)。
-
变换+量化残差,熵编码后写入文件。
-
-
第二帧(P帧):
-
对每个宏块,在上一帧中搜索“小鸟的位置”。
-
找到后记录运动矢量(如“向右移动10像素”)和残差。
-
变换+量化残差,熵编码写入文件。
-
-
解码时:
-
先解码I帧,重建完整图片。
-
对P帧,根据运动矢量从I帧复制小鸟位置,加上残差修正细节。
-
去块滤波消除边缘锯齿。
-
H.264就像一个超级聪明的“视频瘦身师”,它通过:找重复(空间+时间)、预测内容、简化数据、聪明打包,把视频压缩到很小,同时让你感觉不到画质变差。这就是为什么手机能拍高清视频,也能流畅看在线电影的原因。