我们有一批课程屏录要压缩:1080p、PPT 讲解加屏幕操作,每个 40 分钟左右。用常规参数(H.264 CRF 23)压完,体积满意,但PPT 上的小字糊了——12px 的正文变得发虚,红色标注的文字边缘还有彩色毛边。
第一反应是码率不够,于是 CRF 降到 18(体积翻倍)——文字还是糊,只是糊得"更干净"一点。
这时我才意识到:问题不在码率,在于视频编码器的整套设计假设都是面向"自然图像"的(有噪点、有纹理、边缘柔和),而屏幕内容是高对比锐利边缘 + 大面积纯色 + 精细文字,跟自然图像完全相反。用给自然图像调的参数压屏幕内容,就像用拍风景的参数拍文档——扫描比拍照清晰得多。
这篇写清楚这件事,以及我们最后用的参数。
TL;DR:屏幕内容的三个杀手:4:2:0 色度采样(彩色文字边缘糊 + 彩色毛边)、心理视觉优化(psy)(编码器把"省下来的码率"给了它认为重要的纹理,结果把文字边缘当噪点扔掉了)、缩放(缩放一次文字就废了)。对应的解法:能接受体积就用 4:4:4(
-pix_fmt yuv444p),不能就用 4:2:0 但保持原始分辨率不缩放;-tune stillimage(x264)关掉 psy 优化;CRF 要比摄影内容更低(屏录对压缩更敏感);VMAF 对文字不敏感,验收必须人眼看。
目录
- 一、屏幕内容和自然图像的本质差异
- 二、4:2:0 对文字做了什么
- 三、心理视觉优化:好心办坏事
- 四、x264 的 tune:stillimage 是干什么的
- 五、实测:各参数对文字清晰度的影响
- 六、帧率、分辨率与"不要缩放"原则
- 七、锐化?千万别
- 八、参数模板(H.264 / H.265 / AV1)
- 九、验收:VMAF 在这里不可信
- 十、坑清单
一、屏幕内容和自然图像的本质差异
| 特性 | 自然图像(摄影) | 屏幕内容(屏录/PPT) |
|---|---|---|
| 边缘 | 柔和渐变 | 锐利、单像素级 |
| 色彩 | 连续、有噪点 | 大面积纯色、有限色板 |
| 细节 | 纹理丰富 | 精细文字 |
| 时间变化 | 连续运动 | 长时间静止 + 突然变化 |
| 原始数据 | YUV(相机采集) | RGB(显卡输出) |
| 噪点 | 有(传感器噪声) | 无(数字生成,纯净) |
编码器的所有"聪明"设计都是为左边那一列做的:
- 心理视觉优化(psy-rd、psy-trellis)假设画面有噪点和纹理,会主动保留"看起来像细节"的东西;
- 自适应量化(aq)假设暗部细节重要;
- 去块滤波假设块效应比细节损失更难看。
对屏录来说,这些假设全错了:
- 文字边缘被当成"噪点"或者被平滑掉;
- 大面积纯色区域不需要 aq 的照顾,码率被浪费;
- 去块滤波把锐利的文字边缘磨圆。
二、4:2:0 对文字做了什么
这是最根本的问题,比参数更重要。
4:2:0 意味着色度(颜色)分辨率是亮度的 1/4(水平和垂直各 1/2):
亮度:1920×1080(每个像素都有)
色度:960×540(每 2×2 个像素共用一个颜色值)
对自然图像没问题(人眼对颜色细节不敏感)。但对彩色文字是灾难:
白色背景上的红色小字(12px):
- 亮度通道:字是亮的,背景也亮 → 对比度不高
- 色度通道:红色信息只有 1/4 分辨率 → 字的边缘颜色被"抹"到周围
结果:字看起来发虚、边缘有彩色毛边
这就是为什么提高码率没用——码率再高,色度分辨率还是 1/4。这是结构性的限制,不是码率问题。
解决办法按优先级:
1. 用 4:4:4(-pix_fmt yuv444p)
-pix_fmt yuv444p # 8bit 4:4:4
# 或
-pix_fmt yuv444p10le # 10bit 4:4:4
效果立竿见影:彩色文字边缘干净锐利。但兼容性是问题:
| 平台 | 4:4:4 支持 |
|---|---|
| 电脑播放器(VLC/PotPlayer) | ✅ |
| 浏览器 | ❌(大部分不支持 H.264 High 4:4:4) |
| 手机/电视 | ❌(几乎都不支持) |
| 剪辑软件 | ✅(大部分支持) |
所以 4:4:4 只适合"本地归档/后期流转",不适合分发。
2. 折中:4:2:2(-pix_fmt yuv422p)——水平方向色度全分辨率,垂直减半。对横向排列的文字有改善,兼容性稍好但仍有限。
3. 保持 4:2:0,但从源头减轻问题:
- 避免细小的彩色文字(这是给录制方的建议:PPT 里少用红字小字,用深色或者加粗);
- 保持原始分辨率不缩放(缩放会放大色度问题);
- 提高亮度对比(文字用深色而不是红色)。
我们的做法:母版出 4:4:4(归档 + 后期),分发版出 4:2:0 但保持原始分辨率 + 用下面这套参数。
三、心理视觉优化:好心办坏事
x264/x265 默认开启了心理视觉优化(psy-rd、psy-trellis)。它的思路是:
"人眼觉得'有细节'的画面更好看,所以我保留一些看起来像细节的东西,即使它跟原图不完全一样。"
对自然图像这是对的(轻微的纹理增强让人觉得"锐利")。对文字,它会把笔画边缘的锯齿当成"细节"保留,或者反过来把细笔画当成噪点丢掉——两种都是错的。
关掉或者降低它:
# x264
-x264-params "psy-rd=0:psy-trellis=0"
# x265
-x265-params "psy-rd=0.0:psy-rdoq=0.0"
实测效果(对文字清晰度的影响):
| 配置 | 文字主观评分(1-5) | 相对体积 |
|---|---|---|
| 默认 psy-rd=1.0 | 2.8 | 100% |
| psy-rd=0.5 | 3.5 | 102% |
| psy-rd=0 | 4.4 | 105% |
体积只增加 5%,文字清晰度提升明显。这笔交易太划算了。
四、x264 的 tune:stillimage 是干什么的
-tune stillimage 是 x264 专门为"静态图像/幻灯片"设计的预设,它做的事情包括:
- 关闭 psy 优化(正是我们要的);
- 提高默认的量化精度;
- 调整去块滤波(减少边缘平滑);
- 使用更保守的码率分配。
-c:v libx264 -tune stillimage -crf 18
但它有个副作用:stillimage 会大幅提高码率(因为它对质量要求高很多)。实测同一段屏录:
| tune | 体积 | 文字清晰度 |
|---|---|---|
| 无 | 100% | 2.9 |
stillimage |
240% | 4.5 |
animation |
150% | 3.8 |
240% 的体积——如果你的屏录是以静止画面为主(大部分时间 PPT 不动),这个值可以接受(因为静止画面本身很省码率,即使 tune stillimage 也不算大)。但如果屏录里有大量动态内容(演示操作、视频播放),就不划算。
我的选择:
- 纯 PPT 讲解(大部分静止)→
-tune stillimage; - 屏幕操作演示(动态多)→ 不用 tune,改用手调
psy-rd=0+ 较低 CRF; - 动画类内容 →
-tune animation(这个适合卡通/动画,对屏录一般不适用)。
x265 没有 stillimage tune(它的 tune 只有 psnr/ssim/grain/zerolatency/fastdecode)。所以 x265 要手动关 psy:
-c:v libx265 -crf 22 -preset slow -x265-params "psy-rd=0:psy-rdoq=0:aq-mode=1:deblock=0:0"
五、实测:各参数对文字清晰度的影响
测试素材:1080p 屏录,PPT 讲解(含 12px 正文、红色标注、图表),30 秒。
清晰度评价:3 人盲评,对"12px 正文是否清晰可读"打 1~5 分。
| 配置 | 相对体积 | 文字评分 | 说明 |
|---|---|---|---|
| H.264 CRF 23 默认 | 100% | 2.6 | 基线,糊 |
| H.264 CRF 18 默认 | 195% | 3.0 | 加码率效果有限 |
| H.264 CRF 23 + psy-rd=0 | 105% | 3.9 | 性价比最高 |
| H.264 CRF 20 + psy-rd=0 | 145% | 4.3 | |
| H.264 CRF 23 + stillimage | 240% | 4.5 | 最清晰,体积大 |
| H.264 CRF 20 + psy-rd=0 + 4:4:4 | 210% | 4.8 | 归档用 |
| H.265 CRF 26 默认 | 62% | 2.4 | 比 H.264 还差(HEVC 的 psy 更激进) |
| H.265 CRF 22 + psy-rd=0 | 98% | 4.0 | 同体积下比 H.264 好 |
几个反直觉的结论:
-
"加码率"的效果远不如"关 psy" ——CRF 23→18 体积翻倍,评分只从 2.6 到 3.0;而 CRF 23 + psy-rd=0 体积只加 5%,评分到 3.9。参数比码率重要。
-
H.265 默认参数对屏录比 H.264 更差 ——因为 HEVC 的 psy 优化更激进,而且它的去块/SAO 滤波对锐利边缘的破坏更大。必须手动调。
-
4:4:4 的提升是最大的(4.3 → 4.8),但兼容性代价也最大。
六、帧率、分辨率与"不要缩放"原则
第一原则:屏录不要缩放。
屏幕内容是像素精确的——1920×1080 的屏录,每个像素对应屏幕上的一个物理像素。任何缩放都会:
- 放大 → 插值模糊;
- 缩小 → 文字细节丢失(12px 变成 8px,不可读)。
如果非要缩放,只能是整数倍(比如 1920→960 是 1/2,相对好一点),并且缩放后文字基本就废了。所以:
屏录要么保持原分辨率,要么接受文字不可读。
第二:帧率
屏录通常是低帧率的(5~15 fps 就够,因为画面变化少),但很多录屏软件会输出 30fps 的"重复帧"文件。
- 重复帧是浪费(编码器虽然能高效压缩,但仍占一点体积);
- 可以用
-vsync vfr或者 mpdecimate 去掉重复帧:
-vf "mpdecimate,setpts=N/FRAME_RATE/TB"
但要注意:去掉重复帧后,鼠标移动等关键动作可能被删掉(mpdecimate 有阈值参数)。我一般只在对体积要求极高时用,而且会抽查。
第三:关键帧
屏录的"场景切换"(翻页)是离散的,所以关键帧应该跟着翻页走(而不是固定 GOP)。默认的场景检测在这里是对的:
# 保留场景检测(不要 -sc_threshold 0),让翻页处插关键帧
-g 300 -sc_threshold 40
七、锐化?千万别
看到文字糊,很多人的第一反应是"加个锐化滤镜"。这是个陷阱。
锐化(unsharp)的原理是增强边缘的对比度(在边缘外侧加一圈更亮的、内侧加一圈更暗的)。对文字来说:
- 笔画周围会出现白边/黑边(halo);
- 编码器要额外花码率去编码这些"新增的高频";
- 最终效果:文字边缘出现振铃,看起来更"毛躁",而且体积更大。
实测:加 unsharp=5:5:0.8 之后,文字主观评分从 2.6 降到 2.3,体积增加 18%。又糊又大。
正确的做法是"不去破坏"而不是"事后修复":关 psy、保持分辨率、用 4:4:4(如果可能)。
八、参数模板(H.264 / H.265 / AV1)
H.264(分发用,兼容性最好)
ffmpeg -i screen.mp4 \
-c:v libx264 -preset slow -crf 20 \
-pix_fmt yuv420p \
-x264-params "psy-rd=0:psy-trellis=0:deblock=0:0" \
-g 300 \
-c:a aac -b:a 96k \
-movflags +faststart \
out_h264.mp4
H.264(归档/后期用,4:4:4)
ffmpeg -i screen.mp4 \
-c:v libx264 -preset slow -crf 18 \
-pix_fmt yuv444p -profile:v high444 \
-x264-params "psy-rd=0:psy-trellis=0" \
-c:a copy \
out_master_444.mp4
H.265(省体积,次之)
ffmpeg -i screen.mp4 \
-c:v libx265 -preset slow -crf 22 \
-pix_fmt yuv420p \
-x265-params "psy-rd=0:psy-rdoq=0:aq-mode=1:deblock=0:0" \
-c:a aac -b:a 96k \
out_h265.mp4
AV1(屏录收益不错)
ffmpeg -i screen.mp4 \
-c:v libsvtav1 -preset 8 -crf 28 \
-pix_fmt yuv420p10le \
-svtav1-params "tune=0:lp=8" \
-c:a libopus -b:a 64k \
out_av1.mkv
AV1 对屏录的收益比摄影内容更大(实测体积是 H.265 的 72%,而摄影内容只有 78%)——因为 AV1 对"大面积纯色 + 锐利边缘"的处理更好。
九、验收:VMAF 在这里不可信
这一条必须强调。
VMAF 的模型是基于人类对自然图像的主观评价训练的。它对文字清晰度不敏感——我们实测过:
| 配置 | VMAF | 人眼文字评分 |
|---|---|---|
| CRF 23 默认 | 92.1 | 2.6 |
| CRF 23 + psy-rd=0 | 91.8 | 3.9 |
| CRF 23 + stillimage | 93.5 | 4.5 |
注意第一和第二行:psy-rd=0 让文字清晰度从 2.6 提升到 3.9(人眼非常明显的改善),但 VMAF 反而略降(91.8 < 92.1)。
原因:psy 优化"制造"的伪细节会提高某些客观指标(因为它让图像"看起来"信息量更大),而关掉 psy 后这些伪细节消失,VMAF 略降——但人眼看到的文字是更清晰的。
所以屏录这类内容的验收方法:
- 抽帧放大看文字:抽 3~5 个有文字的帧,100% 放大看 12px 正文是否清晰;
- 盲评打分:找几个人,不看参数只看画面,对清晰度打分;
- VMAF 只做参考(可以看趋势,不能作为唯一标准)。
我现在的验收脚本会自动抽出含文字的帧(用边缘密度判断这帧有没有文字),拼成一张对比图,人看一眼就能判断。
十、坑清单
- 用给摄影内容的参数压屏录 → 文字糊。屏录要单独一套参数。
- 只靠加码率解决文字糊 → 效果有限、体积翻倍。改 psy-rd。
- 忽略 4:2:0 的结构性限制 → 彩色文字永远有毛边。归档用 4:4:4。
- 缩放屏录 → 文字直接废。保持原始分辨率。
- 加锐化滤镜 → 振铃 + 体积增大,更糟。
- H.265 用默认参数压屏录 → 比 H.264 还差。手动关 psy。
- 用 VMAF 做唯一验收标准 → VMAF 对文字不敏感,会给出错误结论。人眼验收。
- 忘了
-sc_threshold→ 如果设了 0(为了 ABR 对齐),翻页处不插关键帧,影响随机访问。屏录点播可以保留场景检测。 - 音频码率给太高 → 屏录的音频是语音,96k 甚至 64k 的 AAC/Opus 足够。省下的给视频。
- 用
-tune stillimage压动态屏录 → 体积爆炸。看内容动静比例选。 - 4:4:4 用于网页分发 → 浏览器不支持。4:4:4 只用于归档/后期。
- 录屏源本身是低质量(比如已经压过一次)→ 再怎么调参数也救不回来。源头要无损录制。
- 忽略录制端的设置 → 最好的优化是"录的时候就录好"(原始分辨率、无损或高码率、避免细小彩色文字)。给录制方一份规范比事后救火有效。
- mpdecimate 删掉了关键动作 → 阈值太激进。用后要抽查鼠标/动画部分。
- 不看原始素材直接压 → 有些屏录本身就是 720p 拉伸的,压之前要搞清楚真实分辨率。
最后说说这件事给我的最大启发:编码器的"默认优化"是有立场的,它假设你的内容是自然图像。
这个假设在 95% 的场景下是对的(视频本来就是拍出来的),所以没人觉得有问题。但当你的内容是"数字生成的"(屏录、动画、UI、游戏画面、图表)时,这些优化会朝错误的方向使劲。
类似的例子:
- JPEG 对文字/线条图效果差(它的 DCT 假设是平滑图像)→ 所以截图存 PNG;
- 音频编码器针对音乐优化,对语音要用 speech 模式(Opus 有
--speech); - VMAF 对自然图像准,对文字不准(本文)。
通用工具都有隐含假设,用之前要确认你的场景符合那个假设。 这话说起来简单,但我在屏录这件事上踩了一整轮才真正记住。
还有一点很实际:最有价值的优化往往在源头。我们后来给讲师发了一份"录屏规范"(用 1080p 原始分辨率录制、PPT 正文不小于 18px、避免细小红字、用黑色而不是彩色标注),之后的素材质量普遍提升了,压缩难度也下降了。与其在编码端绞尽脑汁,不如让源头规范一点——这是所有"事后处理"类工作的通用教训。