返回文章列表

第十三章|基础专题二:压缩所需的数学基础

用信息熵、预测、残差、DCT、量化、熵编码、率失真优化、PSNR、SSIM 和 VMAF 串起音视频压缩所需的数学基础。

第十三章|基础专题二:压缩所需的数学基础

原稿学习节奏:第 2 周。

建议投入:8~10 小时 前置知识:第一周的像素、位深、RGB/YCbCr、平面格式与原始帧 本周主线:相关性 → 预测 → 残差 → 变换 → 量化 → 符号概率 → 熵编码 → 率失真选择 → 质量评价


本周总览

压缩不是“把文件变小”的单一算法,而是一组相互配合的数学操作:

原始像素或参考帧

预测:尽量猜中当前像素/块

残差:只保留“猜错了多少”

变换:把残差换到更适合压缩的频率坐标系

量化:降低精度,让大量系数变成 0

熵编码:给高概率符号更短的表示

码流

编码器还要反复回答一个工程问题:

多花一些比特换更高质量,是否值得?

这就是率失真优化(Rate-Distortion Optimization,RDO)的核心。

本周不要求推导完整信号处理理论,而是要求做到:看懂公式、能够手算小例子、知道公式位于编码器或解码器的哪一步,并能把它用于 Web 视频工程判断。


一、学习目标

学完本周后,你应当能够:

  1. 解释自信息、信息熵、条件熵分别在衡量什么。
  2. 手算一个 2~4 个符号的离散信源熵。
  3. 解释为什么“概率集中”比“符号种类少”更接近压缩本质。
  4. 用具体像素序列计算预测值和残差,并判断预测器是否有效。
  5. 解释 DCT 为什么有利于压缩,同时明确 DCT 本身并不直接压缩数据
  6. 看懂一维与二维 DCT 公式,解释 DC、AC、低频与高频。
  7. 手算一个小型量化与反量化例子,并指出误差从哪里产生。
  8. 使用 (J=D+\lambda R) 比较多个编码候选方案。
  9. 计算 MSE 与 PSNR,并解释为什么 PSNR 高不一定主观质量更好。
  10. 说明 SSIM 与 VMAF 相比逐像素误差指标增加了什么信息。
  11. 区分“标准规定的解码过程”与“编码器实现使用的 RDO 策略”。
  12. 把这些数学概念映射到 AI 视频网页和在线 Web 视频编辑器中的码率、质量、代理视频、预览与导出决策。

二、概念地图

2.1 这些数学位于系统的哪一层

原始媒体层
RGB / YCbCr / YUV420P / VideoFrame


编码工具层
预测、残差、变换、量化、熵编码、率失真优化


编码标准层
JPEG、H.264/AVC、H.265/HEVC 等规定可解码的语法与重建过程


编码器实现层
libjpeg、x264、x265、硬件编码器如何搜索模式、估算码率和控制复杂度


基础码流层
JPEG scan、H.264/H.265 NALU


容器层
MP4、MOV、WebM:轨道、样本、时间戳、索引


浏览器 API 层
HTMLVideoElement、MSE、WebCodecs、Canvas、WebGPU

2.2 必须严格区分的边界

对象它是什么它不是什么
信息熵对概率分布不确定性的度量某个文件必然能达到的压缩率
预测利用邻域或参考帧估计当前数据有损操作;预测本身可以完全可逆
DCT坐标变换与能量重分布工具文件格式或熵编码器
量化降低系数精度的映射单纯的数据类型转换
Huffman/算术编码无损地编码符号序列主要画质损失来源
RDO编码器搜索方案的代价函数H.264/H.265 解码器必须执行的步骤
MSE/PSNR/SSIM/VMAF质量评价指标对所有内容都一致可靠的“绝对质量真值”
MP4容器DCT、预测或视频编码算法

关键结论:

  • 标准通常规定码流语法和解码后应如何重建。
  • 编码器如何搜索运动矢量、如何设置 (\lambda)、搜索多少候选模式,通常属于实现策略。
  • WebCodecs 提供编码和解码接口,但通常不会把宏块模式、量化系数、CABAC 上下文或内部 RDO 搜索直接暴露给 JavaScript。

三、直觉解释

3.1 压缩的本质:不要重复描述已经能猜到的信息

假设一行灰度像素为:

100, 101, 101, 102, 103, 103, 104

直接记录每个 8-bit 像素,需要 7 个字节。若使用“左边像素预测当前像素”,除第一个像素外,只需记录:

+1, 0, +1, +1, 0, +1

原始值分布在 100~104,残差则高度集中在 0 和 1。后者通常更容易被熵编码器赋予短码。

预测没有凭空删除信息。解码时执行:

当前像素 = 预测值 + 残差

即可恢复。

3.2 DCT 的直觉:换一套“描述图案”的坐标

逐像素坐标在回答:

每个位置分别是多少?

DCT 坐标在回答:

这个块由多少“平均亮度”、多少“缓慢渐变”、多少“快速交替纹理”组成?

平滑图像块通常可以用少量低频成分描述;高频成分较小。变换后,量化器就可以:

  • 对低频保留较高精度;
  • 对高频使用更粗的步长;
  • 把许多小系数量化为 0。

需要注意:自然图像能量集中在低频是统计倾向,不是对任意图像的数学保证。 棋盘格、细文字和噪声都可能包含大量高频能量。

3.3 量化的直觉:把刻度尺变粗

原系数是 23,量化步长是 8:

23 / 8 = 2.875 → 四舍五入为 3

解码端反量化:

3 × 8 = 24

误差为 1。这个误差通常无法由解码器恢复,因此量化是有损压缩中的主要损失来源。

3.4 RDO 的直觉:同时看质量和价格

候选方案 A 误差小,但需要 500 bit;候选方案 B 误差稍大,只需 100 bit。编码器不能只比较误差,也不能只比较码率,而要计算:

[ J=D+\lambda R ]

其中 (D) 是失真,(R) 是码率,(\lambda) 决定当前更偏向质量还是体积。

3.5 质量指标的直觉

  • MSE:平均每个像素“错了多少平方”。
  • PSNR:把 MSE 转成对数分贝尺度,数值越高通常误差越小。
  • SSIM:比较局部亮度、对比度和结构。
  • VMAF:融合多个感知特征,并使用主观数据训练的模型预测视频观看质量。

它们都是工具,不是最终裁判。视频卡顿、音画不同步、AI 人物形变、时序闪烁等问题,不能仅靠单帧 PSNR 判断。


四、数学原理

4.1 自信息:一个结果有多“意外”

事件 (x) 的自信息定义为:

[ I(x)=-\log_2 p(x) ]

其中:

  • (p(x)):事件 (x) 的概率;
  • (I(x)):观察到该事件时获得的信息量,单位为 bit;
  • 以 2 为底,是因为二进制系统中信息量通常用 bit 表示。

例子:

事件概率自信息
(1)(0) bit
(1/2)(1) bit
(1/4)(2) bit
(1/8)(3) bit

必然发生的事件不意外,因此不提供新的选择信息;低概率事件更意外,自信息更大。

4.2 信息熵:平均每个符号有多少不确定性

离散随机变量 (X) 的熵:

[ H(X)=-\sum_i p_i\log_2 p_i ]

其中:

  • (p_i):第 (i) 个符号出现的概率;
  • (H(X)):平均信息量,单位为 bit/symbol。

手算例子

符号分布:

符号概率
A(1/2)
B(1/4)
C(1/8)
D(1/8)

则:

[ \begin{aligned} H(X) &=-\left( \frac12\log_2\frac12+ \frac14\log_2\frac14+ \frac18\log_2\frac18+ \frac18\log_2\frac18 \right)\ &=\frac12\times1+\frac14\times2+\frac18\times3+\frac18\times3\ &=1.75\text{ bit/symbol} \end{aligned} ]

若使用固定长度编码,4 个符号需要 2 bit/symbol。一个可行的前缀码为:

A → 0
B → 10
C → 110
D → 111

平均码长:

[ L=\frac12\times1+\frac14\times2+\frac18\times3+\frac18\times3=1.75 ]

此例恰好达到熵。实际场景中,符号概率、上下文和有限块长都会影响结果。

两个极端

  1. 公平二元符号:(p(0)=p(1)=0.5)

[ H=1\text{ bit/symbol} ]

  1. 极不平衡二元符号:(p(0)=0.99, p(1)=0.01)

[ H\approx0.0808\text{ bit/symbol} ]

第二种分布更集中,理论上更容易压缩。

重要边界

  • 熵是概率模型的属性,不是单个文件天然携带的固定标签。
  • 对一个文件统计频率得到的是经验熵估计。
  • 理论下界通常讨论长序列与已知分布;实际码流还包含表、头部、对齐和错误恢复信息。
  • “无损压缩”不保证每个输入都变小。对接近随机的数据,压缩后可能更大。

4.3 条件熵:已知邻居后还剩多少不确定性

条件熵:

[ H(X\mid Y)=-\sum_{x,y}p(x,y)\log_2 p(x\mid y) ]

直觉:已知 (Y) 后,预测 (X) 还剩多少不确定性。

图像中,(Y) 可以是左、上、左上像素;视频中,(Y) 可以是参考帧中的匹配块。若邻域相关性强,通常有:

[ H(X\mid Y)<H(X) ]

预测编码正是在利用这种条件关系。一个好的预测器让残差分布集中;一个坏的预测器可能让残差更分散,反而增加码率。

4.4 Huffman 编码与算术编码

Huffman 编码

Huffman 编码为高概率符号分配短码,为低概率符号分配长码,并满足前缀码性质:任何码字都不是另一个码字的前缀。

优点:

  • 解码结构清晰;
  • 表驱动实现高效;
  • 对静态、有限符号表很实用。

限制:

  • 每个符号的码长必须是整数 bit;
  • 模型粒度不足时,可能离熵极限较远;
  • 需要传输或约定码表。

算术编码

算术编码把整段符号序列映射到 ([0,1)) 的一个子区间。它不是给每个符号单独分配整数长度码字,因此长序列的平均码长可以更接近理论熵。

需要准确表述:

“平均每个符号可以是 1.37 bit”并不表示码流中存在 0.37 个物理 bit,而是整段码流长度除以符号数后的平均值。

H.264 的 CABAC(Context-Adaptive Binary Arithmetic Coding,上下文自适应二进制算术编码)进一步使用上下文模型估计二元符号概率。具体上下文状态和二值化规则属于后续 H.264 课程内容。

4.5 预测与残差

预测残差:

[ r=x-\hat{x} ]

其中:

  • (x):真实样本或块;
  • (\hat{x}):预测样本或块;
  • (r):残差。

解码重建:

[ \tilde{x}=\hat{x}+\tilde{r} ]

若残差未量化,则 (\tilde{r}=r),可以无损重建;若残差经过量化,则 (\tilde{r}\neq r),产生失真。

一维例子

原始像素:

100, 102, 101, 103, 104

使用左值预测,首样本单独保存:

预测值: -, 100, 102, 101, 103
残差:  100, 2,  -1,  2,   1

除首样本外,残差集中在 (-1)~2。熵编码器通常更容易处理这种集中分布。

图像常见预测思路

  • 左像素;
  • 上像素;
  • 左上像素;
  • 左与上的平均;
  • 根据边缘方向选择角度预测。

视频常见预测思路

  • 帧内预测:从同一帧已重建邻域预测;
  • 帧间预测:从参考帧中按运动矢量取预测块;
  • 双向预测:组合两个参考方向的预测结果。

重要:编码器和解码器必须使用相同的已重建参考样本。编码器若用原始参考、解码器用量化后的参考,会产生预测漂移。

4.6 DCT:离散余弦变换

一维正交归一 DCT-II

长度为 (N) 的序列 (x_n) 的 DCT:

[ X_k=\alpha(k)\sum_{n=0}^{N-1}x_n \cos\left[\frac{\pi}{N}\left(n+\frac12\right)k\right] ]

其中:

[ \alpha(k)= \begin{cases} \sqrt{\frac1N}, & k=0\ \sqrt{\frac2N}, & k>0 \end{cases} ]

  • (k=0):DC 分量,反映平均水平;
  • (k>0):AC 分量,反映不同变化速度;
  • (k) 越大,基函数振荡越快,通常被称为更高频。

四点手算结果

给定:

x = [52, 55, 61, 66]

按上述正交归一 DCT 计算,约得到:

X ≈ [117.000, -10.770, 1.000, 0.131]

能量主要集中在 DC 和第一个低频 AC 分量,最高频分量很小。这就是“能量集中”的一个小例子。

二维 DCT

对 (N\times N) 块:

[ F(u,v)=\alpha(u)\alpha(v) \sum_{x=0}^{N-1}\sum_{y=0}^{N-1} f(x,y) \cos\left[\frac{\pi}{N}\left(x+\frac12\right)u\right] \cos\left[\frac{\pi}{N}\left(y+\frac12\right)v\right] ]

二维 DCT 可分离执行:

先对每一行做 1D DCT
再对每一列做 1D DCT

这比直接计算每个二维基函数更高效。

JPEG 与视频编码中的注意事项

  • 常见 Baseline JPEG 使用 8×8 DCT、量化与 Huffman 编码。
  • JPEG 对 8-bit 样本通常先做 level shift,即减去 128,使数据以 0 为中心。
  • H.264 的规范变换是整数变换,设计上具有 DCT 类似性质,但不能简单说成“直接执行浮点 8×8 DCT”。
  • 变换在理想精度下只是坐标变化;主要不可逆误差来自量化和有限精度处理。

4.7 量化

最简单的标量量化:

[ q_k=\operatorname{round}\left(\frac{X_k}{Q_k}\right) ]

反量化:

[ \tilde{X}_k=q_kQ_k ]

其中:

  • (X_k):原变换系数;
  • (Q_k):量化步长;
  • (q_k):需要编码的量化系数;
  • (\tilde{X}_k):解码端反量化后的近似系数。

延续四点 DCT 例子

原系数:

X ≈ [117.000, -10.770, 1.000, 0.131]

量化步长:

Q = [8, 4, 2, 2]

量化:

q = round(X / Q) = [15, -3, 0, 0]

反量化:

X̃ = q × Q = [120, -12, 0, 0]

逆 DCT 后约得到:

x̃ ≈ [52.161, 56.753, 63.247, 67.839]

原序列为:

x  = [52, 55, 61, 66]

量化使两个高频系数直接变成 0,符号更容易压缩,但产生了不可恢复误差。

量化步长的影响

  • 步长小:误差小、非零系数多、码率高;
  • 步长大:误差大、零系数多、码率低;
  • 对不同频率使用不同步长,可以利用人眼敏感度差异;
  • 量化矩阵、QP 到步长的映射及心理视觉调优,可能由标准语法和编码器策略共同决定,不能混为一谈。

4.8 率失真优化

编码器选择候选模式时常使用拉格朗日形式:

[ J=D+\lambda R ]

其中:

  • (J):总代价,越小越好;
  • (D):失真,例如 SSE、SATD 近似或其他代价;
  • (R):估计或实际需要的比特数;
  • (\lambda):码率与失真的权衡系数。

手算例子

候选失真 (D)码率 (R)
A12020
B8050
C60100

当 (\lambda=1):

候选(J=D+R)
A140
B130
C160

选择 B。

当 (\lambda=3):

候选(J=D+3R)
A180
B230
C360

选择 A。更大的 (\lambda) 使编码器更重视节省比特。

标准与实现的边界

  • 标准要求生成的码流可被符合规范的解码器正确解析。
  • 标准通常不强制编码器必须采用某个 RDO 搜索算法。
  • (\lambda) 与 QP 的具体关系、是否使用 SATD 预筛选、搜索深度和提前终止,通常属于编码器实现策略。

4.9 MSE 与 PSNR

MSE

[ MSE=\frac1N\sum_{i=1}^{N}(x_i-y_i)^2 ]

  • (x_i):参考样本;
  • (y_i):失真样本;
  • (N):样本数量。

例子:

x = [100, 102, 104, 106]
y = [101, 101, 105, 105]
误差 = [-1, 1, -1, 1]
平方误差 = [1, 1, 1, 1]
MSE = 1

PSNR

[ PSNR=10\log_{10}\frac{MAX^2}{MSE} ]

对 8-bit 样本,通常 (MAX=255)。当 (MSE=1):

[ PSNR=10\log_{10}(255^2)\approx48.13\text{ dB} ]

注意:

  • MSE 为 0 时,PSNR 趋于无穷大;工具可能显示 inf
  • 比较 8-bit 与 10-bit 内容时,必须使用正确的 (MAX)。
  • 必须明确比较的是 RGB、Y、YCbCr 各平面,还是经过缩放与色彩转换后的结果。
  • 两个视频若未对齐帧、分辨率、裁剪区域和时间戳,PSNR 没有可比性。

4.10 SSIM

结构相似性(Structural Similarity Index,SSIM)把局部比较拆为亮度、对比度和结构。常用简化形式:

[ SSIM(x,y)= \frac{(2\mu_x\mu_y+C_1)(2\sigma_{xy}+C_2)} {(\mu_x^2+\mu_y^2+C_1)(\sigma_x^2+\sigma_y^2+C_2)} ]

其中:

  • (\mu_x,\mu_y):局部均值;
  • (\sigma_x^2,\sigma_y^2):局部方差;
  • (\sigma_{xy}):协方差;
  • (C_1,C_2):避免分母接近 0 的稳定项。

SSIM 的优势是能反映结构变化,而不仅是逐像素误差;但它仍然依赖窗口、尺度、颜色通道、实现方式与聚合方法。

4.11 VMAF

VMAF(Video Multi-Method Assessment Fusion,视频多方法评估融合)是面向感知的视频质量指标,融合多个特征,并通过主观质量数据训练模型。

工程上必须记录:

  • 使用的 VMAF 模型与版本;
  • 输入分辨率、像素格式、色彩范围和缩放方式;
  • 帧率与帧对齐;
  • 池化策略;
  • 是否发生裁剪、去噪、锐化或色彩变换。

VMAF 是全参考指标,通常需要“参考视频”和“待测视频”。它不应被解释为对所有观看设备、内容类型和失真类型都绝对准确。


五、底层数据结构

本周数学最终要落到整数、符号和 bit 上。

5.1 数据从像素到 bit 的形态变化

原始样本
[52, 55, 61, 66]

变换系数(通常为有符号数)
[117.000, -10.770, 1.000, 0.131]

量化系数(整数)
[15, -3, 0, 0]

扫描后的符号序列
DC=15, AC=-3, EOB

熵编码后的 bit 串
1010...   ← 这里只是概念示意,不代表任何标准的真实语法

必须区分:

  • 变换系数是数学域中的值;
  • 量化系数是需要编码的离散整数;
  • run/level、类别、上下文二元符号是熵编码前的语法表示;
  • bit 串才是基础码流的一部分;
  • NALU、JPEG marker、MP4 box 又属于更高层结构。

5.2 为什么会出现大量 0

变换后的高频系数通常较小;量化后:

[80, 17, -6, 3, 1, 0, -1, 0]
          ↓ 量化
[10,  2, -1, 0, 0, 0,  0, 0]

扫描后会形成长零串,因此可以使用:

  • 游程长度;
  • 非零系数幅值;
  • 块结束符号;
  • 上下文概率模型。

实际 JPEG、H.264、H.265 的语法不同。本节只解释共同数学结构,不把概念示意当成标准字段。

5.3 概率表与上下文

静态模型示意:

符号计数概率估计
07000.70
11600.16
-11000.10
其他400.04

上下文模型则会进一步问:

  • 左边系数是否为 0?
  • 当前位于低频还是高频?
  • 邻块是否有非零残差?
  • 当前语法元素此前更常出现 0 还是 1?

同一个二元值在不同上下文中可能有不同概率。

5.4 有限精度

真实编解码器通常使用整数或定点运算,原因包括:

  • 保证跨平台重建一致性;
  • 避免浮点舍入差异;
  • 利于 SIMD 与硬件实现;
  • 降低功耗与复杂度。

因此教材中的浮点 DCT 是理解工具,标准中的整数变换才决定规范解码结果。


六、编码器流程

6.1 通用流程

输入原始块 x

枚举预测模式 / 运动候选

生成预测块 x̂

残差 r = x - x̂

变换 T(r)

量化 Q(T(r))

估算语法与系数比特数 R

反量化 + 反变换 + 预测,得到编码器内部重建块 x̃

计算失真 D(x, x̃)

计算 J = D + λR

选择代价最低的候选

熵编码并输出码流

6.2 为什么编码器内部必须重建

编码器不能只保存原始参考帧。解码器看到的是量化后重建结果;未来帧必须基于相同参考,否则:

编码器预测参考 ≠ 解码器预测参考

误差逐帧积累

预测漂移

因此视频编码器通常包含一个“本地解码环路”。

6.3 RDO 伪代码

best = null

for mode in candidateModes:
    prediction = predict(reconstructedNeighbors, mode)
    residual = original - prediction

    coeff = transform(residual)
    qcoeff = quantize(coeff, qp)

    estimatedBits = estimateSyntaxBits(mode, qcoeff, contexts)

    reconstructedResidual = inverseTransform(
        dequantize(qcoeff, qp)
    )
    reconstructed = clip(prediction + reconstructedResidual)

    distortion = sse(original, reconstructed)
    cost = distortion + lambda * estimatedBits

    if best is null or cost < best.cost:
        best = { mode, qcoeff, reconstructed, cost }

entropyEncode(best.mode, best.qcoeff)
storeAsReference(best.reconstructed)

实际编码器会使用多级搜索:先用 SAD/SATD 等较便宜指标筛选,再对少量候选做更精确的 RDO,以控制复杂度。

6.4 编码器的主要复杂度来源

并不是一次 DCT 或一次熵编码最耗时,而是:

候选块划分 × 预测模式 × 运动矢量 × 参考帧 × 变换选择 × 量化参数

搜索空间会迅速膨胀。编码 preset 的本质之一,就是在“搜索深度”和“速度”之间做取舍。


七、解码器流程

解码器通常不做全局模式搜索,只需按码流语法执行确定性重建:

读取码流

熵解码,恢复模式、运动信息与量化系数

反量化

反变换

按码流指定模式生成预测

预测 + 重建残差

裁剪到合法样本范围

环路处理(若当前标准规定)

输出帧并保存参考帧

7.1 哪些步骤有损

步骤理论上是否有损说明
预测只要残差完整保留即可恢复
变换理想精度下否整数近似与舍入需按标准分析
量化多个原值映射到同一量化级
熵编码必须精确恢复符号序列
容器封装不应改变编码样本内容

7.2 编码器比解码器复杂的原因

  • 编码器要“选择”;解码器只需“执行”。
  • 编码器要尝试多个模式并比较 (J)。
  • 编码器可能多次变换、量化、反变换同一个块。
  • 解码器通常只处理最终选中的一个路径。

这也是很多实时系统中“编码比解码更难、更耗电”的根本原因之一。


八、复杂度与性能

8.1 算法复杂度直觉

操作典型复杂度直觉主要瓶颈
统计直方图(O(N))内存带宽、并行归并
一阶预测(O(N))依赖方向与缓存局部性
直接 1D DCT(O(N^2))乘加次数
可分离二维 DCT对 (N\times N) 块约 (O(N^3))行列两遍变换
快速 DCT可进一步减少乘加固定尺寸优化、SIMD
量化(O(N))整数乘除、舍入
熵编码近似 (O(N))数据依赖、分支、上下文更新
RDO 搜索候选数 × 单候选成本通常是编码器核心瓶颈

8.2 CPU、GPU 与专用硬件

适合并行的部分

  • 多块变换;
  • 像素差、SAD、SSE;
  • 缩放、颜色转换;
  • 独立帧或 tile 级处理;
  • 大规模质量指标计算。

不容易完全并行的部分

  • 强上下文依赖的熵编码;
  • 依赖已重建邻块的帧内预测;
  • 某些严格顺序的码率控制状态更新;
  • 过细粒度任务的 GPU 调度与数据搬运。

专用硬件

硬件编解码器通常在功耗和吞吐上优势明显,但:

  • 暴露的参数可能少于软件编码器;
  • 具体模式搜索和质量策略不可见;
  • 不同设备的质量、延迟与支持能力不同;
  • Web 环境必须进行运行时能力探测,不能仅凭 codec 字符串假设支持。

8.3 内存

质量评价常需同时保留参考帧和失真帧。以 1920×1080 8-bit YUV420P 为例,一帧约 3.11 MB;若积压 60 对帧:

[ 3.11\times2\times60\approx373.2\text{ MB} ]

还未计入 stride、对齐、GPU 纹理与中间缓冲。因此浏览器中应采用:

  • 流式逐帧比较;
  • 有界队列;
  • 及时 close() 不再使用的 VideoFrame
  • Worker 分离计算;
  • backpressure,避免解码速度远高于比较与渲染速度。

九、实际场景

A. AI 生成视频网页

问题本周数学的作用工程行动
多个生成结果如何筛选SSIM/VMAF 只能评估部分视觉质量结合时序一致性、语义正确性和人工抽检
边生成边预览码率与复杂度需要平衡低延迟配置、受控 GOP、分片输出、backpressure
生成结果过大量化与 RDO 决定质量/体积选择合理质量目标,不盲目固定高码率
人脸或文字被破坏高频量化过强可能放大细节损失局部 ROI、较高质量代理、主观检查
视频闪烁单帧 PSNR 可能检测不到增加时序差分、光流一致性或专门时序指标
不同模型输出比较指标预处理必须一致固定分辨率、色彩、帧率、对齐和评估模型版本

关键判断:AI 视频中的错误可能来自生成模型、后处理、帧插值、颜色管理或编码器。不能看到块效应以外的异常就一概归因于视频编码。

B. 在线 Web 视频编辑器

问题本周数学的作用工程行动
代理视频质量用率失真思维平衡流畅和可辨识度低分辨率、较低码率、易 Seek 的 GOP
时间线缩略图不需要原始质量尺寸优先,适度 JPEG/AVIF/WebP 质量设置
帧精确剪切预览解码负载与内存受限从关键帧向前解码,按需保留少量帧
滤镜前后质量回归MSE/SSIM 可检测确定性回归统一颜色域并对齐帧后再比较
导出参数RDO 决定最终体积/质量效率质量目标、preset、码率上限与编码时间联合设置
多层合成多次缩放与颜色转换会引入误差尽量减少往返转换,统一中间工作色彩空间
浏览器内编码API 不暴露底层全部模式使用 VideoEncoder 可配置项,复杂导出交给服务端

系统设计结论:

预览链路追求低延迟、稳定帧率和低内存;最终导出链路追求更好的率失真效率。两条链路不应使用完全相同的编码策略。


十、Web 实现视角

10.1 WebCodecs 能做什么

WebCodecs 可让 JavaScript 直接处理:

  • VideoFrame:原始视频帧;
  • EncodedVideoChunk:编码视频块;
  • VideoDecoder / VideoEncoder:解码与编码接口。

但它通常不会直接暴露:

  • DCT 系数;
  • 量化矩阵或每块 QP;
  • 运动搜索候选;
  • CABAC 上下文;
  • 编码器内部 (\lambda) 与完整 RDO 过程。

若需要教学实验或自定义算法,可使用 JavaScript、WebAssembly、Worker、Canvas、WebGL/WebGPU 对原始帧自行计算;但这不等于实现了完整标准编码器。

10.2 能力探测

不要假设某个浏览器或设备一定支持某个编码配置。应在运行时调用:

const result = await VideoEncoder.isConfigSupported({
  codec: "avc1.42001E",
  width: 1280,
  height: 720,
  bitrate: 2_000_000,
  framerate: 30,
});

if (!result.supported) {
  // 切换编码格式、降低配置,或交给服务端处理
}

H.265/HEVC 等配置同样应探测,不能只根据 UA、扩展名或 codec 字符串下结论。

10.3 VideoFrame 生命周期

逐帧计算质量时:

for await (const frame of decodedFrames) {
  try {
    await compareFrame(frame);
  } finally {
    frame.close();
  }
}

VideoFrame 可能持有系统或 GPU 媒体资源。等待垃圾回收可能造成队列积压甚至解码停顿。

10.4 TypeScript:经验熵

export function empiricalEntropy(values: readonly number[]): number {
  if (values.length === 0) return 0;

  const counts = new Map<number, number>();
  for (const value of values) {
    counts.set(value, (counts.get(value) ?? 0) + 1);
  }

  let entropy = 0;
  for (const count of counts.values()) {
    const p = count / values.length;
    entropy -= p * Math.log2(p);
  }
  return entropy;
}

可分别对原始像素和预测残差调用,观察好的预测器是否降低经验熵。

10.5 TypeScript:MSE 与 PSNR

export function mse(
  reference: Uint8Array,
  distorted: Uint8Array,
): number {
  if (reference.length !== distorted.length) {
    throw new Error("Input lengths must match");
  }
  if (reference.length === 0) return 0;

  let sum = 0;
  for (let i = 0; i < reference.length; i += 1) {
    const diff = reference[i] - distorted[i];
    sum += diff * diff;
  }
  return sum / reference.length;
}

export function psnrFromMse(error: number, maxValue = 255): number {
  if (error < 0) throw new Error("MSE cannot be negative");
  if (error === 0) return Number.POSITIVE_INFINITY;
  return 10 * Math.log10((maxValue * maxValue) / error);
}

这段代码只适合已经对齐、同尺寸、同颜色域的样本数组。

10.6 FFmpeg 辅助验证

计算 PSNR:

ffmpeg -i distorted.mp4 -i reference.mp4 \
  -lavfi "[0:v][1:v]psnr=stats_file=psnr.log" \
  -f null -

计算 SSIM:

ffmpeg -i distorted.mp4 -i reference.mp4 \
  -lavfi "[0:v][1:v]ssim=stats_file=ssim.log" \
  -f null -

若 FFmpeg 构建包含 libvmaf,可计算 VMAF:

ffmpeg -i distorted.mp4 -i reference.mp4 \
  -lavfi "[0:v][1:v]libvmaf=log_fmt=json:log_path=vmaf.json" \
  -f null -

实际比较前应先统一:

  • 分辨率;
  • SAR/DAR;
  • 帧率和帧数量;
  • 时间对齐;
  • 像素格式;
  • 色彩 primaries、transfer、matrix 与 range。

十一、易错点

  1. 熵低不等于文件一定小。 文件还有头部、索引、码表、对齐与封装开销。
  2. 符号种类少不等于熵一定低。 概率是否集中更关键。
  3. 单个符号的自信息不等于整个信源的熵。 熵是自信息的期望。
  4. 预测不一定降低熵。 错误预测器会使残差更分散。
  5. 残差小不等于码率必然低。 还取决于分布、扫描方式、语法和上下文。
  6. DCT 不会自动删除信息。 真正使多个值合并的是量化。
  7. 低频不等于视觉上永远更重要。 文字、边缘、纹理依赖高频。
  8. JPEG 的 8×8 DCT 不能直接套到所有视频标准。 H.264/H.265 使用规范化整数变换和多种块结构。
  9. 量化参数不是“质量百分比”。 不同编码器的质量参数含义和映射可能不同。
  10. RDO 不是解码器流程。 它是编码器寻找可选码流的一种常见实现方法。
  11. (\lambda) 大不是质量更高。 在 (J=D+\lambda R) 中,通常表示更重视码率。
  12. PSNR 高不等于主观质量一定好。 相同 MSE 可对应不同视觉结构损伤。
  13. 不同分辨率、位深和颜色域的 PSNR 不可直接比较。 必须统一评估条件。
  14. SSIM 不是只看边缘。 它结合局部亮度、对比度和结构。
  15. VMAF 分数不是跨模型永久可比的绝对刻度。 必须记录模型、版本和预处理。
  16. 逐帧指标难以覆盖时序闪烁。 视频还需时间维度评价。
  17. WebCodecs 编码输出不等于完整 MP4。 还需要时间戳组织和 mux。
  18. Canvas 截图后再比较可能混入颜色转换误差。 应明确比较域。
  19. 算术编码的“1.3 bit/符号”是长序列平均值。 不是单个符号占用小数个物理 bit。
  20. 标准与编码器实现不能混说。 标准规定可互操作语法;搜索算法、preset 和心理视觉调优多为实现策略。

十二、面试题

12.1 基础题 10 道

1. 什么是信息熵?

  • 标准回答: 熵是离散信源平均不确定性的度量,(H(X)=-\sum p_i\log_2p_i),单位为 bit/symbol。概率越均匀,熵通常越高;概率越集中,越容易使用短平均码长表示。
  • 追问: 熵为 0 的条件是什么?
  • 常见错误: “熵就是文件大小。”
  • 高级回答: 区分理论分布熵、经验熵、条件熵和实际码流开销。

2. 为什么高概率符号使用短码?

  • 标准回答: 这样可最小化期望码长;平均码长按概率加权。
  • 追问: 为什么码字必须满足前缀条件?
  • 常见错误: 只说“节省空间”,不解释平均码长。
  • 高级回答: 说明 Huffman 的整数码长限制,以及算术编码如何更接近熵。

3. 什么是预测残差?

  • 标准回答: (r=x-\hat{x}),表示真实值与预测值之差;解码通过预测值与重建残差相加恢复样本。
  • 追问: 预测器不好会怎样?
  • 常见错误: 把残差说成“被删除的像素”。
  • 高级回答: 说明残差是否易压缩取决于条件分布与上下文模型。

4. DCT 为什么适合自然图像?

  • 标准回答: 自然图像局部相关性强,DCT 往往把能量集中到少数低频系数,便于后续量化和零游程编码。
  • 追问: 是否所有图像都集中在低频?
  • 常见错误: “DCT 直接压缩掉高频。”
  • 高级回答: 强调统计能量聚集、可分离性和近似 KLT 的工程价值。

5. DC 与 AC 系数是什么?

  • 标准回答: DC 表示块的平均或零频成分;AC 表示不同空间变化频率的成分。
  • 追问: 平坦块的 AC 会怎样?
  • 常见错误: 把 DC 解释为亮度通道、AC 解释为色度通道。
  • 高级回答: 结合基函数与正交投影解释。

6. 什么是量化?

  • 标准回答: 将连续或高精度系数映射到有限离散级别,常见形式为除以步长并取整;反量化只能得到近似值。
  • 追问: 为什么量化能降低码率?
  • 常见错误: “量化就是把 float 转 int。”
  • 高级回答: 说明零区、频率加权、QP 与步长映射。

7. 什么是率失真优化?

  • 标准回答: 使用 (J=D+\lambda R) 联合考虑重建失真与码率,选择总代价最小的编码方案。
  • 追问: (\lambda) 增大意味着什么?
  • 常见错误: 只选择 MSE 最小的模式。
  • 高级回答: 说明实际编码器会用多级估算和提前终止降低搜索成本。

8. MSE 与 PSNR 的关系是什么?

  • 标准回答: PSNR 是 MSE 的对数变换;在相同位深下,MSE 越小,PSNR 越高。
  • 追问: MSE 为 0 时怎样?
  • 常见错误: “PSNR 是百分比。”
  • 高级回答: 指出评估域、位深与帧对齐前提。

9. SSIM 与 PSNR 有什么区别?

  • 标准回答: PSNR 基于逐样本平方误差;SSIM 比较局部亮度、对比度和结构,更接近部分感知特征。
  • 追问: SSIM 是否一定优于 PSNR?
  • 常见错误: “SSIM 完全等同人眼。”
  • 高级回答: 说明窗口、尺度、通道和失真类型会影响结果。

10. VMAF 是什么?

  • 标准回答: VMAF 是融合多种特征并基于主观数据训练的全参考视频质量指标。
  • 追问: 不同 VMAF 模型的分数能否直接比较?
  • 常见错误: “VMAF 是视频编码器。”
  • 高级回答: 强调模型版本、缩放、帧对齐、池化和内容域。

12.2 底层实现题 10 道

1. 为什么视频编码器内部也需要解码环路?

  • 标准回答: 未来预测必须使用与解码器一致的重建参考,否则会产生漂移。
  • 追问: 漂移如何累积?
  • 常见错误: “只是为了预览编码结果。”
  • 高级回答: 结合参考图像缓冲和闭环预测解释。

2. 为什么熵编码通常放在量化之后?

  • 标准回答: 量化使系数离散并产生大量 0,形成更集中的符号分布,适合无损熵编码。
  • 追问: 熵编码能否恢复量化前系数?
  • 常见错误: 把熵编码说成有损。
  • 高级回答: 说明语法二值化、扫描与上下文建模位于两者之间。

3. 为什么二维 DCT 可以分两次一维 DCT?

  • 标准回答: 二维 DCT 基函数可分离为横向和纵向基函数乘积。
  • 追问: 对复杂度有什么影响?
  • 常见错误: “因为图片有宽高两个属性。”
  • 高级回答: 用矩阵形式 (F=CfC^T) 解释。

4. 整数变换为什么重要?

  • 标准回答: 可保证跨平台重建一致性,便于定点、SIMD 和硬件实现。
  • 追问: 整数变换是否一定无误差?
  • 常见错误: “整数运算完全没有舍入。”
  • 高级回答: 区分规范逆变换、缩放因子合并与有限位宽。

5. 为什么编码器常先用 SAD/SATD,再做完整 RDO?

  • 标准回答: 完整 RDO 需要熵比特估计和重建,成本高;便宜指标可先淘汰明显较差候选。
  • 追问: 这样会不会错过最优解?
  • 常见错误: “SAD 就等于最终失真。”
  • 高级回答: 说明速度 preset 本质是搜索精度与计算预算折中。

6. 为什么熵编码难以像像素滤镜一样大规模并行?

  • 标准回答: 上下文状态和输出位置常依赖前序符号,存在串行数据依赖。
  • 追问: 标准如何提高并行性?
  • 常见错误: “熵编码不能并行。”
  • 高级回答: 可提 slice、tile、WPP 或独立熵子流,但指出存在压缩效率和边界成本。

7. 为什么量化后容易出现长零串?

  • 标准回答: 高频小系数除以量化步长后被舍入为 0;扫描顺序通常使非零低频在前、零高频在后。
  • 追问: 扫描顺序为什么重要?
  • 常见错误: “DCT 输出天然都是 0。”
  • 高级回答: 结合方向扫描和预测模式讨论。

8. 编码器估算 (R) 时必须真的写出完整码流吗?

  • 标准回答: 不一定;可用概率上下文、查表或快速模型估算,最终候选再精确编码。
  • 追问: 估算不准有什么影响?
  • 常见错误: “R 就是像素数量。”
  • 高级回答: 说明 CABAC 上下文状态复制与 rollback 的实现成本。

9. 变换跳过有什么意义?

  • 标准回答: 对某些小块、屏幕内容或特殊残差,直接量化残差可能比变换更合适。
  • 追问: 是否所有标准都支持同样的 transform skip?
  • 常见错误: “跳过变换就没有压缩。”
  • 高级回答: 强调具体语法依标准和 profile 而异。

10. 为什么解码器一般比编码器快?

  • 标准回答: 解码器执行码流指定路径;编码器需要搜索大量候选并反复估算、重建和比较。
  • 追问: 是否存在解码仍很重的场景?
  • 常见错误: “解码完全没有计算。”
  • 高级回答: 讨论高分辨率、复杂参考结构、后处理、软件解码与内存带宽。

12.3 数学题 10 道

1. 公平硬币的熵是多少?

  • 标准回答: (-2\times0.5\log_2 0.5=1) bit。
  • 追问: 硬币总是正面时呢?
  • 常见错误: 回答 2 bit,因为有两个结果。
  • 高级回答: 解释最大熵发生在均匀分布。

2. 概率为 (1/8) 的事件自信息是多少?

  • 标准回答: (-\log_2(1/8)=3) bit。
  • 追问: 概率减半,自信息增加多少?
  • 常见错误: 回答 (1/8) bit。
  • 高级回答: 说明对数把概率乘法转成信息加法。

3. 分布 ([0.5,0.25,0.25]) 的熵是多少?

  • 标准回答: (0.5\times1+0.25\times2+0.25\times2=1.5) bit/symbol。
  • 追问: 固定长度编码需要多少 bit?
  • 常见错误: 忘记负号或对数底。
  • 高级回答: 比较固定 2 bit 与可变长平均码长。

4. 原序列 [10, 12, 13, 13] 使用左值预测,残差是什么?

  • 标准回答: 首值单独保存时为 [10, 2, 1, 0]
  • 追问: 使用固定预测值 0 呢?
  • 常见错误: 写成 [0,2,1,0] 而未说明首样本处理。
  • 高级回答: 比较两个残差分布的经验熵。

5. 系数 21,量化步长 8,量化与反量化结果是什么?

  • 标准回答: (q=round(21/8)=3),反量化为 24,误差 3。
  • 追问: 不同舍入规则会怎样?
  • 常见错误: 把反量化写成 21。
  • 高级回答: 讨论负数舍入、dead-zone 和规范实现。

6. 两候选 A:(D=100,R=40),B:(D=130,R=20),(\lambda=1) 选谁?

  • 标准回答: A 的 (J=140),B 的 (J=150),选 A。
  • 追问: (\lambda=3) 呢?
  • 常见错误: 只比较 D。
  • 高级回答: 求切换阈值:(100+40\lambda=130+20\lambda),得 (\lambda=1.5)。

7. 8-bit 图像 MSE=4,PSNR 约多少?

  • 标准回答: (10\log_{10}(255^2/4)\approx42.11) dB。
  • 追问: MSE 减半,PSNR 增加多少?
  • 常见错误: 用自然对数且不乘 10。
  • 高级回答: MSE 减半增加约 3.01 dB。

8. 为什么平方误差对大误差惩罚更重?

  • 标准回答: 误差翻倍后平方项变为四倍。
  • 追问: L1 误差有什么不同?
  • 常见错误: “因为平方误差更准确。”
  • 高级回答: 讨论异常值敏感度与优化性质。

9. 常量序列的 DCT 有什么特点?

  • 标准回答: 理想正交 DCT 中只有 DC 非零,AC 为 0。
  • 追问: 叠加线性渐变后呢?
  • 常见错误: “所有系数都相等。”
  • 高级回答: 解释与基函数正交投影的关系。

10. 为什么 (H(X\mid Y)) 可能等于 (H(X))?

  • 标准回答: 当 (X) 与 (Y) 独立时,知道 (Y) 不减少对 (X) 的不确定性。
  • 追问: 什么时候条件熵为 0?
  • 常见错误: “条件熵永远更小且严格小于。”
  • 高级回答: 说明确定函数关系与互信息。

12.4 Web 实战题 10 道

1. 如何在浏览器中验证预测是否降低了熵?

  • 标准回答:VideoFrame 拷贝指定平面,计算原始样本直方图与预测残差直方图,再比较经验熵。
  • 追问: 为什么要固定颜色平面?
  • 常见错误: 直接比较压缩文件大小而不控制其他变量。
  • 高级回答: 使用 Worker、分块统计和有界队列。

2. 为什么不能直接对两个 Canvas 截图计算 PSNR?

  • 标准回答: Canvas 可能引入颜色转换、Alpha 合成、缩放和色域截断,导致比较域不一致。
  • 追问: 应如何统一?
  • 常见错误: 认为所有 ImageData 都等价于视频原始 YUV。
  • 高级回答: 统一到同一 RGB/线性光或同一 YCbCr 平面后比较。

3. WebCodecs 能否读取 H.264 的 DCT 系数?

  • 标准回答: 通常不能;WebCodecs 暴露帧与编码块接口,不提供标准内部系数级调试接口。
  • 追问: 如何做教学实验?
  • 常见错误:EncodedVideoChunk 当成解析后的宏块对象。
  • 高级回答: 使用专用码流解析器、WASM 解码器或离线工具。

4. 如何避免浏览器质量评估占用过多内存?

  • 标准回答: 逐帧处理、限制队列、及时关闭 VideoFrame、避免同时缓存整段参考与失真视频。
  • 追问: backpressure 如何实现?
  • 常见错误: 全部 decode 完再比较。
  • 高级回答: 按时间戳配对两个流并设置最大未匹配帧数。

5. 如何检测当前编码配置是否可用?

  • 标准回答: 调用 VideoEncoder.isConfigSupported() 或相应能力 API 做运行时探测。
  • 追问: 为什么 UA 判断不可靠?
  • 常见错误: 看到 .mp4 就认为 H.264/H.265 一定可编码。
  • 高级回答: 同时验证编码、解码、容器 mux 和实际首帧结果。

6. 为什么 VideoEncoder 输出还不是 MP4?

  • 标准回答: 它输出编码 chunk;MP4 还需要 sample table、时间戳、codec 配置与 box 封装。
  • 追问: B 帧会增加什么难点?
  • 常见错误: 直接拼接 chunk 字节后保存为 .mp4
  • 高级回答: 说明 DTS/PTS 与 muxer 责任。

7. WebGPU 是否一定适合做 8×8 DCT?

  • 标准回答: 不一定;小任务可能被上传、调度和同步开销抵消,需要批量处理和基准测试。
  • 追问: 哪些部分更适合 GPU?
  • 常见错误: “GPU 永远比 CPU 快。”
  • 高级回答: 对比 SIMD/WASM、WebGPU 批处理与硬件编码器。

8. 如何在线比较两个视频的 VMAF?

  • 标准回答: 浏览器原生无统一 VMAF API,可用服务端 FFmpeg/libvmaf,或在可接受成本下使用 WASM;必须先对齐视频。
  • 追问: 为什么移动端不宜长时间本地计算?
  • 常见错误: 把 MSE 函数命名为 VMAF。
  • 高级回答: 设计分段采样、服务端队列和报告缓存。

9. 代理视频应追求最高 PSNR 吗?

  • 标准回答: 不应;代理视频目标是编辑流畅、快速 Seek 和足够辨识,需综合分辨率、GOP、码率、解码复杂度与内存。
  • 追问: 文字类素材怎么办?
  • 常见错误: 与最终母版使用完全相同参数。
  • 高级回答: 内容自适应代理与局部高质量预览。

10. 为什么导出前后出现偏色时 PSNR 可能极低?

  • 标准回答: primaries、transfer、matrix 或 range 不一致会造成系统性像素偏移,即使编码器压缩本身很好。
  • 追问: 如何排查?
  • 常见错误: 立即提高码率。
  • 高级回答: 检查元数据、像素格式、Canvas/GPU 转换链和比较域。

12.5 系统设计题 5 道

1. 设计一个浏览器端视频质量回归系统

  • 标准回答: demux/decode 两路视频,按时间戳配对,统一尺寸与颜色域,逐帧计算 MSE/SSIM,聚合报告;设置 Worker、有界队列、取消和资源释放。
  • 追问: 如何处理缺帧和变帧率?
  • 常见错误: 只按数组下标配对帧。
  • 高级回答: 时间窗匹配、场景分段、异常帧抽样和服务端 VMAF 补充。

2. 设计 AI 视频多版本自动选优流程

  • 标准回答: 先做格式与时序校验,再计算编码质量、时序稳定性和生成语义指标,最后结合成本与人工抽检排序。
  • 追问: 如何避免指标奖励过度平滑?
  • 常见错误: 只按 PSNR 排名。
  • 高级回答: 建立多目标 Pareto 前沿与内容分层阈值。

3. 设计在线编辑器的预览与导出双链路

  • 标准回答: 预览使用代理媒体、低延迟解码和 GPU 合成;导出使用原始素材、完整时间线、较慢高质量编码和可靠 mux。
  • 追问: 如何保证两条链路视觉一致?
  • 常见错误: 浏览器预览参数直接当最终导出参数。
  • 高级回答: 共享颜色管理、效果参数和确定性渲染测试。

4. 设计大规模转码参数选择系统

  • 标准回答: 对代表性内容采样多个分辨率/码率/preset,计算 VMAF 与编码成本,形成每标题或每场景的码率阶梯。
  • 追问: 如何控制计算量?
  • 常见错误: 所有内容使用固定码率梯度。
  • 高级回答: 内容复杂度特征、贝叶斯/分层搜索、缓存和停止条件。

5. 设计低内存的双视频逐帧比较管线

  • 标准回答: 两路 demux/decode 按时间戳推进,每路仅缓存小窗口;匹配后立即计算并关闭帧;队列到阈值时暂停上游。
  • 追问: Seek 或用户取消怎么办?
  • 常见错误: 两个视频全部解码进数组。
  • 高级回答: generation token、AbortSignal、解码器 reset、过期任务丢弃和统计一致性。

十三、练习

练习 1:熵手算

分布为:

A: 0.5
B: 0.25
C: 0.125
D: 0.125
  1. 计算熵。
  2. 设计一个前缀码。
  3. 计算平均码长。
参考答案

熵为 1.75 bit/symbol。可用 A=0, B=10, C=110, D=111,平均码长也是 1.75 bit/symbol。

练习 2:比较预测器

原序列:

[30, 31, 32, 32, 33, 34, 34, 35]

分别使用:

  • 预测器 P0:恒定预测 0;
  • 预测器 P1:左值预测。

计算残差并比较经验分布。

参考答案

P0 残差等于原值,分布较分散。P1 在首值单独编码时,残差为 [30,1,1,0,1,1,0,1],除首值外高度集中在 0 和 1,更适合熵编码。

练习 3:量化与重建

系数:

[40, -13, 7, 2]

量化步长:

[8, 4, 4, 4]

计算量化与反量化结果,并列出系数误差。

参考答案

量化系数约为 [5,-3,2,1];反量化为 [40,-12,8,4];误差为 [0,1,1,2]。具体负数舍入需明确所用规则。

练习 4:RDO 选择

模式DR
Intra-A9070
Intra-B11040
Inter-A14015

分别在 (\lambda=0.5) 和 (\lambda=2) 时选择模式。

参考答案
  • (\lambda=0.5):代价分别为 125、130、147.5,选 Intra-A。
  • (\lambda=2):代价分别为 230、190、170,选 Inter-A。

练习 5:PSNR

8-bit 图像的 MSE 分别为 1、4、16。计算 PSNR,并观察 MSE 每增大 4 倍时 PSNR 的变化。

参考答案

约为 48.13 dB、42.11 dB、36.09 dB。MSE 每增大 4 倍,PSNR 下降约 6.02 dB。

练习 6:伪代码

实现以下流程:

输入一行灰度像素
→ 左值预测
→ 统计原始值与残差的经验熵
→ 输出两者差值

要求处理空数组和首样本。

练习 7:Debug

你用 FFmpeg 比较两个“肉眼几乎相同”的视频,PSNR 只有 18 dB。列出至少 8 个检查项。

参考答案

时间偏移、帧率、缺帧、裁剪、缩放、SAR、像素格式、色彩矩阵、full/limited range、HDR transfer、参考/失真输入顺序、去隔行、旋转元数据、Alpha 合成和不同解码路径。

练习 8:架构设计

画出一个“浏览器预览 + 服务端高质量导出”的双链路图,并在图中标出:

  • 哪一步使用原始帧;
  • 哪一步发生有损量化;
  • 哪一步进行 mux;
  • 哪一步做 backpressure;
  • 哪一步计算质量指标。

十四、本章速查表

14.1 核心公式

名称公式一句话解释
自信息(I(x)=-\log_2p(x))越罕见越意外
(H(X)=-\sum p_i\log_2p_i)平均不确定性
残差(r=x-\hat{x})只编码预测没猜中的部分
量化(q=round(X/Q))降低精度,制造更多 0
RDO(J=D+\lambda R)同时考虑质量和码率
MSE(\frac1N\sum(x_i-y_i)^2)平均平方误差
PSNR(10\log_{10}(MAX^2/MSE))对数化的误差指标
SSIM亮度×对比度×结构局部结构相似性

14.2 核心流程

编码:预测 → 残差 → 变换 → 量化 → 熵编码
解码:熵解码 → 反量化 → 反变换 → 预测重建

14.3 面试结论

  • 预测利用相关性,变换集中能量,量化制造可压缩的离散分布,熵编码无损地缩短平均表示。
  • DCT 不是压缩格式;量化才是主要有损环节。
  • 编码器靠 RDO 选方案,解码器按码流执行,不重复搜索。
  • PSNR 必须在同位深、同颜色域、同尺寸、同时间对齐条件下比较。
  • SSIM/VMAF 更关注感知,但仍不能替代时序指标和主观评估。
  • WebCodecs 不等于完整编码器内部调试接口,也不等于 MP4 muxer。

14.4 本周时间安排

学习日内容建议时间输出
Day 1自信息、熵、Huffman1.5 h手算 3 组分布
Day 2条件熵、预测、残差1.0 h比较两个预测器
Day 31D/2D DCT2.0 h手算并画频率基函数直觉图
Day 4量化与反量化1.0 h完成 3 组量化题
Day 5RDO1.0 h完成模式选择表
Day 6MSE、PSNR、SSIM、VMAF1.5 h用 FFmpeg 比较两段视频
Day 7Web 映射、面试与复盘1.0~2.0 h画编码器/解码器流程图

14.5 通过标准

你能够在不看资料的情况下完成:

  1. 计算四符号熵与平均码长。
  2. 对一行像素生成预测残差。
  3. 解释 DCT 的 DC/AC 和能量集中。
  4. 完成量化、反量化与误差计算。
  5. 用两个不同 (\lambda) 完成 RDO 选择。
  6. 计算 MSE 和 8-bit PSNR。
  7. 解释 SSIM/VMAF 的价值与边界。
  8. 画出编码器闭环和解码器流程。
  9. 说明浏览器逐帧质量评估的内存与 backpressure 方案。
  10. 明确说出哪些是标准规定,哪些是编码器实现策略。

十五、参考资料

  1. Claude E. Shannon, A Mathematical Theory of Communication:信息熵与信源编码理论基础。 https://people.math.harvard.edu/~ctm/home/text/others/shannon/entropy/entropy.pdf
  2. JPEG Committee, JPEG 1:JPEG 1 的 DCT、Huffman、算术编码、无损与分层编码概览。 https://jpeg.org/jpeg/
  3. ITU-T, H.264: Advanced video coding for generic audiovisual services:H.264/AVC 规范入口。 https://www.itu.int/rec/t-rec-h.264
  4. Z. Wang, A. C. Bovik, H. R. Sheikh, E. P. Simoncelli, Image Quality Assessment: From Error Visibility to Structural Similarity:SSIM 原始论文。 https://www.cns.nyu.edu/pub/lcv/wang03-preprint.pdf
  5. Netflix, VMAF — Video Multi-Method Assessment Fusion:VMAF 官方开源实现与文档。 https://github.com/Netflix/vmaf
  6. W3C, WebCodecsVideoFrameVideoDecoderVideoEncoder 等接口规范。 https://www.w3.org/TR/webcodecs/
  7. FFmpeg Documentation:PSNR、SSIM、libvmaf 与媒体处理工具文档入口。 https://ffmpeg.org/documentation.html