WeCodec 知识库 · 视频编码
颜色为什么能少存一半,J:a:b 记法怎么读
人眼对亮度细节敏感,对颜色细节迟钝,所以视频把颜色存得比亮度稀疏。
4:2:2 的数据量是 4:4:4 的三分之二。4:2:0 让每 2×2 个像素共用一组颜色,数据量只有一半,DVD 和蓝光光盘都用它。
相机和屏幕用 RGB 表示颜色,但 R、G、B 三个分量里都混着亮度信息,没法只压缩颜色。所以视频系统先把 RGB 转成 YCbCr。Y 是亮度分量(luma),Cb 和 Cr 分别是蓝色差和红色差分量,合称色度(chroma)(维基百科:YCbCr)。转换只是简单的加减乘:Y 由 R、G、B 加权求和得到,色差分量由其中两个分量减去第三个得到(维基百科:Chroma subsampling)。
拆开之后就能区别对待。人眼分辨颜色的能力大约只有分辨亮度的三分之一,所以色度少采一些点,画面看起来几乎没有差别。这种做法叫色度抽样(chroma subsampling)(维基百科:Chroma subsampling)。
抽样方式写成 J:a:b。它描述的是一块宽 J 像素、高 2 像素的区域(维基百科:Chroma subsampling)。J 是区域宽度,通常是 4。a 是第一行的色度采样数。b 是第二行和第一行相比新增的色度采样数。
照这个读法,4:4:4 两行都有 4 个色度点,也就是没有抽样。4:2:2 每行 2 个点,水平方向减半。4:2:0 第一行 2 个点,第二行没有新点,直接沿用第一行,所以水平和垂直都减半。
还有一种 4:1:1,每行只有 1 个色度点,水平方向只剩四分之一,垂直不减。它的数据量和 4:2:0 一样,DV 格式用过这种方案(维基百科:Chroma subsampling)。
下图每个方格是一个亮度采样点,三种格式的亮度都是满的。圆点代表一组色度采样,浅色块是这组色度覆盖的范围,范围里的像素共用同一个颜色值。
以一块 4×2 的区域为例,数一数每种格式要存多少个采样值。亮度固定 8 个,差别全在色度。
| 格式 | Y | Cb | Cr | 合计 | 相对 4:4:4 |
|---|---|---|---|---|---|
| 4:4:4 | 8 | 8 | 8 | 24 | 100% |
| 4:2:2 | 8 | 4 | 4 | 16 | 约 67% |
| 4:2:0 | 8 | 2 | 2 | 12 | 50% |
换成一帧 1920×1080、每个采样 8 bit 的画面。4:4:4 需要 1920×1080×3 = 6,220,800 字节,约 6.2 MB。4:2:0 只要 3,110,400 字节,约 3.1 MB。编码器还没开始压缩,数据量就先少了一半。
4:2:2 省掉三分之一,和维基百科给出的结论一致(维基百科:Chroma subsampling)。
三种格式对应不同的使用环节。下表的用途都来自维基百科:Chroma subsampling。
| 格式 | 典型用途 |
|---|---|
| 4:4:4 | 高端胶片扫描、电影后期制作 |
| 4:2:2 | 专业摄像和广播格式,例如 Digital Betacam、AVC-Intra 100、ProRes 422 |
| 4:2:0 | DVD-Video、蓝光光盘 |
4:2:0 的短板出在颜色急剧变化的地方。每个 2×2 方块只有一个颜色值,一条 1 像素宽的红线会和旁边的像素共用颜色,颜色被冲淡,边缘发虚。大片平滑的画面则看不出区别。
色度抽样发生在编码之前。色度一旦抽掉,后面把码率提得再高也补不回来,所以素材格式要在拍摄和导出时就定好。
只是播放的话,4:2:0 就够了。抠像和调色会放大色度误差,这类后期素材最好保留 4:2:2 或 4:4:4。
用 FFmpeg 编 H.264 时,像素格式写作 yuv420p、yuv422p、yuv444p。档次(profile)是标准划定的功能子集,决定解码器要支持哪些特性。x264 要编 4:2:2,得用 high422 档次;要编 4:4:4,得用 high444 档次(FFmpeg Wiki:Encode/H.264)。