📹 第四章 H.264/H.265视频编码并存储
📄 一句话概括

分辨率和码率是两个独立的旋钮,很多人当成一个。 分辨率决定「细节上限」,码率决定「这点细节保得住多少」。

📝 本节和前面几节的关系

上一节只用了默认质量。这一节把两个旋钮分别拧一遍,各自量出影响。 PSNR 的定义在 26 课,这里只把它当「客观画质分」用。

一、两个旋钮各管什么

旋钮 影响 典型取值
分辨率 细节上限 1920×1080、1280×720
码率/质量 这个细节保得住多少 CRF 18~28

举个不精确但好记的比方:分辨率是「画布多大」,码率是「颜料给多少」。 画布大而颜料少,就是一片糊;画布小而颜料多,就是清晰但只能看一小块。 两者不能互相替代——720p 配高码率永远不会变成 1080p。

二、只拧质量:CRF 台阶

CRF 是「恒定质量」模式:编码器自己决定用多少字节,你只负责说「要多清楚」。 数值越小越清楚,18 到 28 是常用区间。

CRF 文件大小 码率 PSNR
18 12.4 KB 102 kbps 46.9 dB
23 10.4 KB 85 kbps 42.2 dB
28 8.3 KB 68 kbps 38.8 dB
35 6.4 KB 52 kbps 32.7 dB

CRF 每降 5 档,文件涨两三成,PSNR 涨三到四 dB。这是台阶, 不是线性——因为 CRF 本身就是量化步长的对数值。

PSNR 怎么读:40 dB 以上肉眼基本看不出差别;35 dB 左右能看出轻微模糊; 30 dB 以下就开始糊了。 这个门槛是经验值,不同内容差别很大——但用来判断「还能不能降」够用。

三、只拧分辨率:像素减半,文件也减半

把源缩到不同尺寸再编,质量参数不动:

分辨率 帧字节 编码后 码率
320×240 115200 10.4 KB 85 kbps
240×180 64800 7.5 KB 62 kbps
160×120 28800 5.1 KB 42 kbps

像素少一半,文件大约少一半,因为细节总量就少一半,能压的也就少一半。 注意它比 CRF 的杠杆更硬:CRF 降 5 档只省两三成,分辨率砍一半直接省三成多, 而且编码耗时会跟着掉(像素少了,搜索也少了)。 所以「带宽不够」时,先降分辨率往往比降质量划算。

四、命令行怎么写

想要 参数 注意
恒定质量 -crf 23 文件大小不可控
恒定码率 -b:v 1000k 复杂画面会糊
限峰值 -maxrate 1500k -bufsize 3000k 两个要给,只给一个没用
改尺寸 -vf scale=640:480 必须偶数,否则编码报错

-crf 和 -b:v 同时给时,-crf 优先——x264 会进 CRF 模式,把 -b:v 当上限参考。 想测码率就只给 -b:v。

-vf scale 的宽高必须是偶数,因为 yuv420p 两个色度平面各是宽高的一半,奇数除不尽。 报错信息是「width not divisible by 2」,看到就知道是这个。

五、动手 Demo:码率和分辨率,两个旋钮各管什么

Demo 分两段:先只拧 CRF(18/23/28/35),再只拧分辨率(320/240/160)。 PSNR 是解回来跟源逐像素比出来的,不是查表。

def enc(crf=None, w=320, h=240):
    c = av.open("t.h264", "w", format="h264")
    s = c.add_stream("libx264", rate=30)
    s.width, s.height, s.pix_fmt = w, h, "yuv420p"
    if crf is not None:
        s.options = {"crf": str(crf)}
    else:
        s.bit_rate = 400000      # 恒定码率
    ...
def psnr(a, b):
    mse = ((a.astype("f8") - b.astype("f8")) ** 2).mean()
    return 10 * math.log10(255.0 ** 2 / mse)

实跑输出:

--------------------------------------------------------------------
码率和分辨率,两个旋钮各管什么
--------------------------------------------------------------------
**分辨率和码率是两个独立的旋钮,很多人以为是一个。**

  旋钮           影响                   典型取值
  -------------------------------------------------------------
  分辨率         细节上限               1920×1080、1280×720
  码率/质量     这个细节保得住多少     CRF 18~28

**先用同一份源,只拧「质量」这个旋钮(CRF 越小质量越高):**

  CRF     文件大小     码率         PSNR
  ---------------------------------------------
  18      12.4 KB      102 kbps     46.9 dB
  23      10.4 KB      85 kbps      42.2 dB
  28      8.3 KB       68 kbps      38.8 dB
  35      6.4 KB       52 kbps      32.7 dB

  **CRF 每降 5 档,文件涨两三成**,PSNR 涨 3 到 4 dB。这就是 x264 的「质量台阶」,不是线性的。
  **PSNR 到 40 dB 以上,肉眼基本看不出差别**;35 dB 左右能看出轻微模糊;**30 dB 以下就开始糊了**。

**再拧分辨率这个旋钮**(把源缩到不同尺寸再编,质量参数不变):

  分辨率      帧字节     编码后      码率
  ----------------------------------------------
  320×240     115200     10.4 KB     85 kbps
  240×180     64800      7.5 KB      62 kbps
  160×120     28800      5.1 KB      42 kbps

  **像素少一半,文件大约少一半**——因为细节总量就少一半。
  **这两个旋钮的组合决定画质**:1080p 配低码率会糊,720p 配高码率不会变回 1080p。
  **所以「想要清楚」的第一件事是提分辨率,第二件才是提码率。**

PSNR 公式里那个 255 是 8 位像素的最大值,换成 10 位就是 1023。 这个数写错,PSNR 会差 12 dB,很容易看出来,但也容易糊过去。 分辨率那一段是把源先缩再编, 所以「帧字节」那一列也跟着变了——这是缩放带来的,不是编码器带来的,两者要分清。

30 秒实验

  1. 把 CRF 设成 51(最大),看 PSNR 掉到多少,还认不认得出画面。
  2. 用 -b:v 85k 复现第一张表的 85 kbps 那一行, 看 PSNR 差多少——这就是恒定码率和恒定质量的差别。
  3. 把 scale 的宽改成 641,看报错原文。

常见误区

  1. 以为高码率能补回分辨率。 720p 编得再清楚也不是 1080p, 分辨率是细节上限,码率只能决定保住多少。
  2. 以为 CRF 和码率是同一件事的两种写法。 CRF 是「按质量给字节」,码率是「按字节给质量」, 方向正好相反。
  3. 以为 PSNR 高就一定好看。 PSNR 是逐像素平均差, 对「整体偏色」不敏感,对「局部糊」也不敏感,只能当参考。
自测三问(点开对答案) 1. 为什么 CRF 每降 5 档文件只涨两三成,而不是翻倍? —— CRF 是量化步长的对数值,降 5 档是把步长减半, 而码率和步长不是线性关系——**大部分比特花在少数难编的块上**。 2. 带宽不够时,先降分辨率还是先降码率? —— 先降分辨率。**它省得更多(像素减半文件减半),而且编码更快**;降码率会把所有细节一起糊掉。 3. `-crf` 和 `-b:v` 同时给会怎样? —— `-crf` 优先,进 CRF 模式,`-b:v` 退化成参考上限。**想测恒定码率就只给 `-b:v`。**

下一节拧第三个旋钮:多久给一次完整画面(GOP)。

相关笔记