halfsize / ffmpeg 指定大小
ffmpeg 压到指定大小
-crf 要的是画质,文件多大它不管。当报名表写着 20 MB 时,你需要的是反过来:
先算码率预算,再两遍编码,最后确认真的塞得下。
为什么 -crf 压不准大小
CRF 是恒定画质,编码器把码率花在画面需要的地方。同样 CRF 下,一个人物访谈和一段烟花视频,文件大小能差四倍。存档时这是对的,面对有硬性上限的上传表单就是错的。
于是大多数人开始「猜一个 CRF、导出、看大小、再导一次」。这个循环能用,但每猜一次就要重编一遍,而且永远不告诉你画质付出了什么代价。
先算码率预算
编码器只认每秒多少比特,文件大小要换算过去:
视频码率 = (目标字节 × 8 ÷ 时长秒数) − 音频码率 − 容器开销
60 秒压到 20 MB(20,000,000 字节),总码率是 2.67 Mbps。减掉 128 kbps 的 AAC 音频,再留大约 1.5% 给 MP4 容器,视频流大约 2.46 Mbps。
剩下都是细节:旋转信息、HDR 标记、可变帧率,以及源音频本来就很低时,重新编码是否反而浪费码率。
两遍编码
单遍的平均码率要在编码时猜后面的画面有多复杂。两遍就不一样:第一遍把整条片子分析完,第二遍把预算花在真正需要的地方。
$ ffmpeg -y -i 输入.mp4 -c:v libx264 -b:v 2460k \
-pass 1 -passlogfile ffmpeg2pass -an -f mp4 /dev/null
$ ffmpeg -i 输入.mp4 -c:v libx264 -b:v 2460k \
-pass 2 -passlogfile ffmpeg2pass -c:a aac -b:a 128k \
-movflags +faststart 输出.mp4
Windows 下把 /dev/null 换成 NUL。两遍跑完记得删掉 ffmpeg2pass* 日志。
为什么还是会差几个百分点
- ABR 不是 CBR。 x264 追的是平均值,片段越短越难平均。10 秒的片子比 10 分钟的更容易超出。
- 容器开销。 MP4 头、moov 原子、每帧开销都不在你的码率算式里。留 1%–2%。
- 音频重编码。 直接复制原 AAC(
-c:a copy)不花码率;降到更低码率能省空间,但会偏离预算。
落在上限下方 1%–3% 才是正确结果:19.45 MB 到处能过,20.01 MB 会被同一个表单拒掉。
验证大小和画质
$ ffprobe -v error -show_entries format=duration,size \
-of default=noprint_wrappers=1 输出.mp4
$ ffmpeg -i 输出.mp4 -i 输入.mp4 -lavfi libvmaf -f null -
VMAF 是 0–100 的感知相似度。90 以上基本「看着一样」,80–90 是「轻微变软」,70–80 能看出损失。只报大小不报 VMAF 的压缩,等于多绕几步的猜。
halfsize 把这些串起来了
- 先探测时长、帧率、旋转、音频码率和 HDR 标记,再出方案。
- 算完预算后挑「每像素比特数」还撑得住的最大分辨率:能 1080p 就 1080p,撑不住就 720p 或 540p。
- 两遍编码写出临时文件,成功后才改名成正式文件。
- 测 VMAF 和 SSIM,直接给一句人话结论,而不是甩一个数字让你猜。
- 内置
--for discord、--for wechat、--for whatsapp、--for email、--for outlook、--for twitter,不用现查上限。
$ npx halfsize 输入.mp4 --to 20mb
target 20.0 MB
plan H.264 1280x720 2.46 Mbps audio 128 kbps 2-pass
scale 1920x1080 → 1280x720
output 输入.20mb.mp4
136 MB → 19.45 MB 小 7.0 倍 比目标小 2.7%
VMAF 88.3 SSIM 0.971 轻微变软
实测数据
60 秒 1080p30、源 18 Mbps,默认设置,普通笔记本:
| 目标 | 输出 | 分辨率 | 视频码率 | VMAF |
|---|---|---|---|---|
| 20 MB | 19.45 MB | 1280×720 | 2.46 Mbps | 88.3 |
| 16 MB | 15.59 MB | 960×540 | 1.94 Mbps | 84.8 |
| 10 MB | 9.77 MB | 960×540 | 1.24 Mbps | 82.9 |
| 2 MB | 1.99 MB | 960×540 | 0.25 Mbps | 79.9 |
常见问题
两遍一定比 CRF 好吗?
有硬性大小上限时是的:它是唯一能可预测地花完预算的模式。只在意画质时 CRF 更快也更好,不会把码率浪费在不需要的场景上。
直接用 -fs 20M 不行吗?
-fs 是写到上限就停,可能在高帧组中间截断,文件大小对了、结尾却播不了,而且完全不管画质怎么分配。
H.265 值得吗?
同画质大约省 30%–50%,可以把分辨率留得更高。代价是兼容性:老 Windows、部分浏览器和剪辑软件解不了。要保证到处能播,还是 H.264。
为什么 10 秒的片子更容易超?
片段短,码率控制器能平均的空间小,容器开销占比也更大。多留 5% 余量,或者手动把码率调低一点。
「指定大小」有多准?
一般在上限下方 1%–3%。编码器没法在开始前承诺精确字节数,留一点余量是故意的。