题记与说明
- 日期:2026-10-31(夜航精读任务 knowledge-p5j2vm4l-2)
- 形式:主题研究(topic research)——先检索精读 7 个来源,再整合为可复用的个人配方手册,关键配方在本机逐条实测验证
- 本机验证环境:ffmpeg version 9.0.2-full_build-www.gyan.dev(gcc 16.2.0 / MSYS2,--enable-libx264 --enable-libx265 --enable-libsvtav1 --enable-libass --enable-fontconfig),Windows 11 x64,nproc=24逻辑核
- 实测素材:testsrc2合成彩条 1280×720@30fps ×10 s + 440 Hz 正弦音 AAC 128k(生成命令见附录 A),6,171,001 字节,总码率 4,936,800 bit/s
- 标注约定:每条配方末尾的「✅ 本机实测」表示我在本会话用本机 ffmpeg 9.0.2 实际运行并记录了输出;「📖 来源」为文献依据,引述保持英文原文
一、来源清单与阅读方式
| # | 来源 | 性质 | 读取方式 |
|---|---|---|---|
| 1 | FFmpeg 官方 Wiki《H.264 Video Encoding Guide》 | 官方编码指南(CRF/preset/tune/两遍/无损/FAQ) | trac.ffmpeg.org 有 Anubis 反爬(PoW 验证,工具直接访问返回 "Making sure you're not a bot!"),改经 Wayback Machine 2024 存档 全文读取 |
| 2 | FFmpeg 官方 Wiki《HowToBurnSubtitlesIntoVideo》 | 官方字幕烧录指南 | 同上,经 Wayback 存档 全文读取 |
| 3 | Werner Robitza(slhck)《CRF Guide (Constant Rate Factor in x264, x265 and libvpx)》(2017-02-24) | FFmpeg wiki 主要维护者之一对 CRF 原理的专文 | webReader 全文读取 |
| 4 | Werner Robitza(slhck)《Understanding Rate Control Modes (x264, x265, vpx)》(2017-03-01,含 2019-2020 更新) | 码率控制模式(CQP/ABR/CBR/两遍/CRF/VBV)决策专文,含 Big Buck Bunny / Tears of Steel 对比实验 | webReader 全文读取 |
| 5 | Bannerbear《How to Add Subtitles to a Video File Using FFmpeg》(Josephine Loo,2022-07,2024-01 更新) | 硬/软字幕实操教程(mov_text 多轨、force_style) | WebFetch 提取(命令为原文精确提取,散文部分为提取器转述,文中已标注) |
| 6 | Mux《How to compress video files while maintaining quality with FFmpeg》 | 视频平台方的压缩实操文(目标体积公式、preset 取舍数字) | WebFetch 提取(三条关键主张为页面原句摘取) |
| 7 | Brainiarc7《ffmpeg-multi-instances-xargs》(GitHub Gist) | FFmpeg wiki 资深贡献者的多实例并行批处理配方(NVENC 场景) | webReader 全文读取 |
辅助检索(结论只作旁证,未逐字精读):Video SE:veryfast preset 反而更小的已知现象、Super User / ahosting 关于并行 ffmpeg 的 CPU 超订与磁盘 I/O 讨论、Discord 压缩脚本的 0.97 安全系数写法。
二、七维提取
1. 核心问题
FFmpeg 是"天书式"工具:选项上千、参数顺序敏感、网络教程互相矛盾(尤其码率控制),普通使用者每次都要现搜现拼。这份精读要解决的是:如何把高频的转码、压缩、字幕、批处理需求,沉淀为一套参数有依据、行为经实测、拿来即用的个人配方库,并弄清每个配方背后的选择逻辑(什么时候用 CRF、什么时候两遍、硬字幕还是软字幕、批处理怎么不翻车)。
2. 主要主张
- 码率控制只有两件事值得记:官方 wiki 开宗明义——"There are two rate control modes that are usually suggested for general use: Constant Rate Factor (CRF) or Two-Pass ABR."。存档求质量用 CRF(单遍、恒定质量、体积不可预知);体积必须命中用两遍 ABR。裸 ABR(只给
-b:v)是被 x264 核心开发者点名"永远不要用"的模式。 - CRF 的算术很简单:x264 合理区间 17–28(默认 23),x265 默认 28;±6 ≈ 体积减半/翻倍。"visually lossless" 用 17–18。
- preset 是"速度换压缩率"的旋钮:"Use the slowest preset that you have patience for.";同一 CRF 下越慢体积越小,placebo 只比 veryslow 好 ~1% 却慢得多,官方直接叫别用。
- 字幕的决策只有一条分界线:要可开关/可移除/不重编码 → 软字幕(MP4 用
-c:s mov_text,MKV 直接-c:s copy);要所有播放器必显 → 硬字幕(subtitles/ass滤镜烧录,必须重编码,依赖 libass)。中文场景的关键坑是字体(fontconfig)与 SRT 的 UTF-8 编码。 - 批处理的安全要点不是转码参数而是工程细节:文件名引号、
-y/-n覆盖语义、退出码不可全信(本机 9.0.2 实测"拒绝覆盖"竟返回 0)、并行度要远小于核数(ffmpeg 单进程已多线程,-P 2这类保守并行才是 gist 推荐)。
3. 方法
- 检索:官方 wiki 两篇(trac 被反爬挡住后转 Wayback 存档全文读取)+ wiki 维护者 slhck 的两篇原理专文 + 两个平台方实操文(Bannerbear/Mux)+ 一篇并行批处理 gist,共 7 篇,覆盖"官方规范—原理—实操—工程化"四层。
- 提炼:把来源中重复出现、互不矛盾的命令模式归并为 11 条配方(R0–R10),每条标注适用场景。
- 实测:在本机 ffmpeg 9.0.2 上生成可控合成素材,对每条关键配方逐条运行:CRF 阶梯、preset 阶梯、两遍命中目标体积、中文字幕烧录(截图目检)、软字幕往返、批处理循环/覆盖保护/并行,共 10 组实验,记录真实耗时与字节数。
- 交叉验证:用实测数据检验文献声明(如 ±6 减半律、8388.608 公式、moov 原子位置),偏差如实记录(见 §六)。
4. 数据与证据
文献证据:见 §五逐条引述(含官方 wiki 的 preset 编码时间曲线数据、slhck 的 BBB/ToS 码率曲线实验、Mux 的经验数字)。
本机实测证据(ffmpeg 9.0.2,合成素材 720p/10s,详见 §六):
- CRF 23→28 体积 3.78→1.94 MiB(−48.7%,与官方"±6 减半"吻合);CRF 18/23/28/33 = 5.82/3.78/1.94/1.14 MiB。
- preset@crf23:ultrafast 8.93 MiB/0.415 s → veryslow 3.28 MiB/3.256 s(慢 7.8×,省 63% 体积);medium→slow 耗时 +64%、体积 −2.5%。
- 两遍目标 1 MiB(公式算出
-b:v 710k)→ 实得 0.978 MiB(−2.2%)。 - 硬字幕烧录 0.886 s(重编码)vs 软字幕 mov_text 封装 0.133 s、文件仅 +644 字节;往返提取文本逐字一致;烧录帧截图目检中文字形正常。
- 批处理:含空格/中文文件名循环 3/3 成功;拒绝覆盖时 ffmpeg 9.0.2 退出码为 0(陷阱);
xargs -P 2三文件并行 1.343 s。 - faststart 字节级验证:moov 原子从文件尾偏移 6,159,200 移到文件头偏移 ~36。
5. 结论
11 条配方可覆盖日常 90%+ 的 ffmpeg 需求;"CRF 存档、两遍给体积、copy 优先、字幕先问软硬、批处理管好文件名/覆盖/并行" 五句话是整本手册的压缩表示。所有配方的参数选择都有官方 wiki 或 wiki 维护者背书,行为差异(退出码、AV1 表现)以本机实测为准。
6. 局限
- trac.ffmpeg.org 只能读 Wayback 2024 存档,wiki 可能已有更新(文中标注存档日期)。
- 实测素材是合成的 testsrc2 彩条(高频细节+运动),压缩率与真实拍摄素材不可直接换算;CRF/preset 的相对趋势可信,绝对数值只对本类素材有效。
- 实测仅一台 Windows 机器(24 逻辑核、gyan full build);退出码行为在别的版本/平台可能不同(例如官方文档语义上失败应非零)。
- Bannerbear/Mux 两篇经 WebFetch 模型提取,散文部分是转述而非逐字原文(已标注;命令部分为精确提取)。
- 未覆盖直播推流、硬件编码器调优(NVENC/QSV/AMF 仅收录官方示例未实测)、字幕样式深入定制(ASS 全语法)。
7. 对我的启发
- 配方库思维:高频 CLI 工具值得沉淀成"带默认值的函数"而不是每次重搜——下一步可把 R1/R4/R6/R7/R8 写成本地 shell 函数或 PowerShell 脚本,参数只暴露 CRF/目标体积/字幕路径三个口。
- 决策树先于参数:每个 ffmpeg 问题先问"场景四选一(存档/点播/直播/设备)"再选码率控制,能避免网络教程最常见错误(裸
-b:v)。 - 信任但验证:教程(包括官方 wiki 的 Windows 提示)在本机一律先小段试编(
-ss+-t预检配方 R10);退出码这类"看似理所当然"的工程假设必须实测——本次就抓到一个 exit=0 陷阱。 - 字节级验证法可复用:faststart 是否生效、字幕是否真的烧进去(抽帧目检)、软字幕是否无损(往返提取 diff)——都可用"最小可观测证据"验证,不必依赖播放器肉眼。
三、心智模型:一条 ffmpeg 命令的解剖
ffmpeg [全局选项] -i 输入 [输入选项] -vf/-filter_complex [滤镜] [输出选项] 输出- 选项的作用域看位置:
-ss写在-i前是输入 seeking(快,关键帧对齐),写在输出前是输出 seeking(准,逐帧解码);-c:v、-crf、-b:v、-movflags都是输出选项,必须放在输出文件之前。 - 流指定符(stream specifier):
-c:v视频、-c:a音频、-c:s字幕、-c:s:0第一条字幕轨;-map 0:v:0显式选流。不加-map时 ffmpeg 只自动挑每类"最好"的一条流——多音轨/多字幕文件会被静默丢弃,批处理中要用-map 0全保留。 - 重编码只发生在必要处:
-c copy直接搬流(秒级、无损);字幕软封装全程 copy 只有字幕轨转码(mov_text)。 - 两条万能探查命令(本机实测通过):
ffprobe -v error -show_entries format=duration,size,bit_rate -show_entries stream=codec_name,width,height,pix_fmt -of default=noprint_wrappers=1 输入.mp4
ffprobe -v error -print_format json -show_format -show_streams 输入.mp4 # 给脚本用四、配方手册正文(R0–R10)
R0 · 探查配方:先看清楚再动手
ffprobe -v error -print_format json -show_format -show_streams input.mp4
✅ 本机实测:正确输出 h264/High/1280×720 等字段。脚本里用 -of json 或 -show_entries 精确取字段。
R1 · 标准转码(H.264,恒定质量,默认首选)
ffmpeg -i input -c:v libx264 -preset slow -crf 22 -c:a copy output.mkv # 官方 wiki 示例
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4 # Mux 示例
📖 来源 1(原文):"The range of the CRF scale is 0–51, where 0 is lossless (for 8 bit only, for 10 bit use -qp 0), 23 is the default, and 51 is worst quality possible. A lower value generally leads to higher quality, and a subjectively sane range is 17–28."
📖 来源 1(原文):"The range is exponential, so increasing the CRF value +6 results in roughly half the bitrate / file size, while -6 leads to roughly twice the bitrate."
📖 来源 3(原文):"For x264, sane values are between 18 and 28. The default is 23, so you can use this as a starting point.";x265 默认 28:"ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4"
✅ 本机实测 CRF 阶梯(preset medium,-c:a copy):
| CRF | 耗时 | 体积 | 相对上一档 |
|---|---|---|---|
| 18 | 0.881 s | 5.82 MiB | — |
| 23 | 0.847 s | 3.78 MiB | ×0.650 |
| 28 | 0.834 s | 1.94 MiB | ×0.513(≈官方"±6 减半") |
| 33 | 0.838 s | 1.14 MiB | ×0.585 |
何时用:归档、网盘、自己收藏——一切"体积不设上限、质量要尽量好"的场景(来源 4 的场景 1 Archival)。
R2 · 高压缩转码(H.265 / AV1)
ffmpeg -i input.mp4 -c:v libx265 -tag:v hvc1 -preset medium -crf 28 -c:a copy out.mp4
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 30 -c:a copy out.mkv
📖 来源 6(页面原句):"H.265 (HEVC) achieves approximately 50% better compression than H.264 at equivalent quality"(同质量体积约减半;编码时间 2–3×)。
📖 来源 3:VP9 恒定质量写法 -c:v libvpx-vp9 -crf 31 -b:v 0(-b:v 0 必须加,VP9 的 CRF 需要关掉默认 ABR)。
✅ 本机实测(合成素材):libx265 crf28/medium = 2.60 MiB / 2.346 s(对比 x264 crf23 的 3.78 MiB / 0.885 s:小 31%,慢 2.6×,方向与文献一致);libsvtav1 crf30 = 5.41 MiB / 1.274 s——在合成彩条上反而大于 x264 crf23。教训:CRF 数值跨编码器不可比(来源 3 原文本就说明 CRF 结果取决于源复杂度),AV1 要发挥优势需按素材重调 crf/preset。
⚠️ -tag:v hvc1 让 QuickTime/苹果系能识别 HEVC 轨。
R3 · preset 旋钮:用时间换体积
📖 来源 1(原文):"A preset is a collection of options that will provide a certain encoding speed to compression ratio. A slower preset will provide better compression (compression is quality per filesize)." 及 "Use the slowest preset that you have patience for."(速度序:ultrafast→superfast→veryfast→faster→fast→medium(默认)→slow→slower→veryslow→placebo)
📖 来源 1 FAQ 数据:medium→slow 编码时间 +40%,→slower 翻倍,→veryslow 需 280% 时间;placebo 仅比 veryslow 好 ~1%,"ignore this as it is not useful"。
✅ 本机实测(crf23):
| preset | 耗时 | 体积 |
|---|---|---|
| ultrafast | 0.415 s | 8.93 MiB(比源文件 crf18 还大!) |
| veryfast | 0.542 s | 3.37 MiB |
| medium | 0.885 s | 3.78 MiB |
| slow | 1.448 s | 3.69 MiB |
| veryslow | 3.256 s | 3.28 MiB |
- veryslow vs ultrafast:慢 7.8×,省 63% 体积。
- 反常点:veryfast(3.37) < medium(3.78)。这与检索到的 Video SE 提问现象一致——恒定 CRF 下体积并非随 preset 严格单调(CRF 按感知质量调 QP,不同 preset 的心理视觉优化不同),合成素材放大了波动。结论不受影响:ultrafast 独占鳌头地差,veryfast 是性价比拐点,slow/veryslow 用于一次编码多次观看的存档件。
R4 · 目标体积压缩:两遍 ABR(体积必须命中时)
公式(官方 wiki 版,MiB→kbit/s 用 8388.608):
📖 来源 1 原文:(200 MiB * 8388.608 [converts MiB to kBit; note: not 8192 as 1 kBit is always 1000 bit]) / 600 seconds = ~2796 kBit/s total bitrate,再减去音频码率。
# 目标 1 MiB、时长 10 s:(1*8388.608)/10 - 128 ≈ 710k 视频码率
ffmpeg -y -i input -c:v libx264 -b:v 710k -pass 1 -passlogfile /tmp/pl -an -f null /dev/null
ffmpeg -i input -c:v libx264 -b:v 710k -pass 2 -passlogfile /tmp/pl -c:a aac -b:a 128k output.mp4
📖 来源 1(原文):"In pass 1, output to a null file descriptor, not an actual file. (This will generate a logfile that ffmpeg needs for the second pass.)" Windows 提示:NUL 替代 /dev/null、^ 替代续行 \。
📖 来源 6 用简化系数 8192:(target_size_MB × 8192) / duration − 音频码率——8192 比 8388.608 少算 ~2.4%,天然留了不超标的余量,两种写法都在流传,属"精确公式 vs 保守估算"之别。
✅ 本机实测:两遍跑完得 1,025,245 字节 = 0.978 MiB(目标 1.000 MiB,偏差 −2.2%,偏小是因为 AAC 对正弦音用不满 128k 且 x264 不做填位——来源 4 原文早有言:"if you have a scene that is very easy to encode, your bitrate may always end up lower than the one you specified. Don't worry about this")。
📖 来源 1 FAQ(原文):"Will two-pass provide a better quality than CRF? No, though it does allow you to target a file size more accurately." ——两遍的意义是命中体积,不是提升质量。
补充配方(capped CRF / VBV)——既要质量导向又怕码率尖峰:
ffmpeg -i input -c:v libx264 -crf 23 -maxrate 1M -bufsize 2M output.mp4 # x264
ffmpeg -i input -c:v libx265 -crf 28 -x265-params vbv-maxrate=1000:vbv-bufsize=2000 output.mp4
📖 来源 4(原文):"A good default is to have the buffer size be twice as large as the maximum rate";并给出调 CRF 的换算法:"you encode at CRF 18 without VBV. Your clip ends up with an average bitrate of 3.0 Mbit/s. But your want your VBV setting to cap the clip at 1.5 Mbit/s, so you need to increase your CRF to about 24 to only get half the bitrate."
R5 · 兼容性配方:让文件"在哪都能放"
ffmpeg -i input -c:v libx264 -crf 23 -pix_fmt yuv420p -movflags +faststart output.mp4
📖 来源 1(原文):像素格式——"You may need to use -vf format=yuv420p (or the alias -pix_fmt yuv420p) for your output to work in QuickTime and most other players."
📖 来源 1(原文):网络播放——"You can add -movflags +faststart as an output option if your videos are going to be viewed in a browser. This will move some information to the beginning of your file and allow the video to begin playing before it is completely downloaded."
✅ 本机实测(字节级):无 faststart 时 mdat 在偏移 ~40、moov 在文件尾 6,159,200;加 -movflags +faststart -c copy 后 moov 移到偏移 ~36、mdat 在 11,936——原子序验证通过。
色调映射/高源:HDR→SDR 需另加 zscale/tonemap 滤镜链(本次未实测,未收录为配方)。
R6 · 硬字幕(烧录,不可移除,全播放器必显)
# 基本式(官方 wiki)
ffmpeg -i video.avi -vf subtitles=subtitle.srt out.avi
# 字幕已内嵌在 mkv 里
ffmpeg -i video.mkv -vf subtitles=video.mkv out.mkv
# 中文字体+字号(本机 Windows 验证过的写法)
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='FontName=Microsoft YaHei,FontSize=20'" output.mp4
# ASS 样式全控:先转 ASS 再用 ass 滤镜
ffmpeg -i subtitle.srt subtitle.ass
ffmpeg -i input.mp4 -vf "ass=subtitle.ass" output.mp4
📖 来源 2(原文):"Draw subtitles on top of input video using the libass library. This filter requires ffmpeg to be compiled with --enable-libass."(本机构建已启用,ffmpeg -filters | grep subtitles 可查)
📖 来源 2(原文,剪辑陷阱):subtitles 滤镜是独立打开字幕文件的——"if you are also Seeking in the same step, then the subtitles will start at the beginning of the subtitle file";解决法是加 -copyts 并在输出端再 -ss 同值:
ffmpeg -ss 5:00.00 -copyts -i video.avi -ss 5:00.00 -vf subtitles=subtitles.srt out.avi
📖 来源 2(原文):"Windows users will have to setup font paths to get libass to work"——Windows 的 fontconfig 需要特别设置,中文场景最稳的是 force_style 显式指字体名。
📖 来源 5(Bear Tip,提取转述):ASS 颜色是 BGR 序且以 &H 开头,与 HTML 的 RGB 相反,例如 PrimaryColour=&H0000FF 是红色。
✅ 本机实测:中文 UTF-8 SRT(od -c 验证字节为 UTF-8)+ force_style='FontName=Microsoft YaHei,FontSize=20' 烧录成功(0.886 s,含重编码);抽取 2 s 处一帧 PNG 目检,字幕"这是硬字幕测试:配方手册第一行"以微软雅黑白字黑边正确渲染、底部居中。若不指定中文字体,fontconfig 默认字体缺 CJK 字形时会渲染成方框(tofu)——这是中文硬字幕第一大坑。
- 图片字幕(PGS/dvdsub)烧录用 overlay:
ffmpeg -i input.mkv -filter_complex "[0:v][0:s]overlay[v]" -map "[v]" -map 0:a ...(来源 2;未实测)。
R7 · 软字幕(可开关,不重编码,秒级完成)
# MP4:srt → mov_text,视频音频全 copy
ffmpeg -i input.mp4 -i sub.chi.srt -c copy -c:s mov_text -metadata:s:s:0 language=chi output.mp4
# 双语双轨(来源 5 命令)
ffmpeg -i input.mp4 -i sub.en.srt -i sub.chi.srt -map 0 -map 1 -map 2 -c copy -c:s mov_text \
-metadata:s:s:0 language=eng -metadata:s:s:1 language=chi output_eng_chi.mp4
# MKV:字幕流原样塞入,连 mov_text 转码都不需要
ffmpeg -i input.mkv -i sub.srt -c copy -c:s srt output.mkv # 或 -c:s copy(若输入已有字幕流)
# 校验/回取
ffprobe -v error -show_entries stream=index,codec_name,codec_type -of default=noprint_wrappers=1 output.mp4
ffmpeg -i output.mp4 -map 0:s:0 extracted.srt
📖 来源 5(提取转述):软字幕"can be toggled on or off during playback",硬字幕"burned into the video... cannot be removed afterward";SRT 只支持 <b>/<i>/<u>/<font> 简单标记,全样式要转 ASS。
✅ 本机实测:-c copy -c:s mov_text 封装 0.133 s、文件仅 +644 字节(对比硬字幕 0.886 s 重编码,快 6.7×);ffprobe 确认新增 index=2, codec_name=mov_text, TAG:language=chi;-map 0:s:0 往返提取出的 SRT 与原文逐字一致(中文无损)。
决策一句话:给万人看的成片/社交媒体 → 硬字幕;自留/自订/要双语切换 → 软字幕(MKV 优先)。
R8 · 批处理配方:for 循环(串行,最稳)
# bash:双引号包住 "$f" 是生死线;${f%.mp4} 去扩展名
mkdir -p out
for f in *.mp4; do
ffmpeg -y -hide_banner -loglevel error -i "$f" \
-c:v libx264 -preset veryfast -crf 28 -c:a copy "out/${f%.mp4}_c28.mp4" \
|| echo "FAILED: $f"
done
# Windows cmd
for %%f in (*.mov) do ffmpeg -i "%%f" "%%~nf.mp4"
✅ 本机实测:三个文件(episode 1.mp4、episode 2.mp4、第 3 集.mp4——含空格与中文)循环转码 3/3 成功,输出名/中文完好;带 -y 幂等可重跑。
⚠️ 覆盖语义与退出码(本次实测最大的意外收获):
- 不带
-y且输出已存在时,非交互环境下 ffmpeg 打印File '...' already exists. Overwrite? [y/N] Not overwriting - exiting并Error opening output file——但本机 ffmpeg 9.0.2 实测退出码为 0(对照组:输入文件不存在时退出码 127,正常成功 0)。 - 推论:批处理脚本不能只靠
||捕获失败,要么显式-y(自己管覆盖),要么-n(存在即跳过),要么事后校验输出文件存在与大小。这是来源里没有、必须实测才知道的坑。 -hide_banner -loglevel error让批量日志只留错误;更精细可用-loglevel warning -report。
R9 · 并行批处理:xargs -P(配方的保守并行)
📖 来源 7(gist 原文命令,NVENC 双会话场景):
$ find Videos/ -type f -name \*.avi -print | sed 's/.avi$//' |\
xargs -n 1 -I@ -P 2 ffmpeg -i "@.avi" -c:a aac -c:v hevc_nvenc "@.mp4"
📖 来源 7(原文):"The noteworthy part here is the -P 2 to xargs, which starts up to two processes in parallel."
为什么是 -P 2 而不是 -P $(nproc):单个 libx264 编码进程本身已吃满多核,N 个全速进程并发会超订 CPU 并打爆磁盘 I/O;并行收益主要出现在弱多线程编码器(VP9/部分 AV1 配置)、NVENC 双会话上限、或 I/O 轻的短任务。需要抢吞吐时可给每个进程加 -threads N 分核。
✅ 本机实测:3 个 10 s 文件 find | xargs -n1 -I@ -P 2 转码 1.343 s 完成,输出文件名含空格/中文均正确(-I@ 按行替换,天然容忍空格;文件名含换行的极端情况应改用 -print0 | xargs -0)。
📖 来源 1(原文,同批一致性):"If you are encoding a set of videos that are similar, apply the same settings to all the videos: this will ensure that they will all have similar quality."——批量转码保持同一 CRF/preset 正是为此。
R10 · 预检配方:先编 30 秒看看
📖 来源 1(原文):"Encode a random section instead of the whole video with the -ss and -t/-to options to quickly get a general idea of what the output will look like."
ffmpeg -ss 00:05:00 -t 30 -i input -c:v libx264 -crf 23 -preset slow preview.mp4
(本会话所有实测均由此法先行——全部实验时长 ≤4 s/文件,几分钟跑完全部验证。)
五、来源关键数据与引述补遗
- slhck 的 CRF 原理(来源 3,原文):"Constant Rate Factor at CRF=18 will increase the QP to, say, 20, for high motion frames (compressing them more) and lower it down to 16 for low motion parts";动感知冗余的根据——"high motion 'masks' the presence of compression artifacts like blocking"。所以 CRF ≠ CQP:CRF 省下的比特花在人眼看得见的地方。同文并反对用 PSNR/SSIM 评质量:"More perceptually-based metrics like VQM or VMAF are better choices."
- slhck 的模式决策表(来源 4,原文节录):"1. Archival — CRF that gives you the quality you want. 2. Streaming — Two-pass CRF or ABR with VBV-constained bitrate. 3. Live Streaming — One-pass CRF or ABR with VBV-constained bitrate, or CBR if you can waste bits. 4. Encoding for Devices — Two-pass ABR, typically." 以及对网络教程的批评——"the most simple solution (just specifying bitrate) is one that isn't recommended at all, but the Web keeps propagating code examples using this method."
- ABR 单遍为什么烂(来源 4,原文):"Avoid using this mode! One of the main x264 developers himself says you should never use it."(编码器不知前路,开头码率乱飘。)
- Mux 的经验数字(来源 6,页面原句/提取数字):veryslow 比 fast 慢 5–10× 但同 CRF 小 10–20%;1080p→720p 缩尺寸省 50–60%;音频约占 5–10%;逐代重编码有代际损失——"each compression pass introduces additional quality loss (generation loss)"。
- x265 的两遍写法不同(来源 4,原文):pass 选项要放进私有参数——
-x265-params pass=1:vbv-maxrate=1000:vbv-bufsize=2000 -f null /dev/null,第二遍pass=2。
六、实测声明与偏差记录(诚实清单)
| # | 文献声明 | 本机实测结果 | 判定 |
|---|---|---|---|
| 1 | CRF ±6 ≈ 体积减半/翻倍(来源 1/3) | 23→28 = −48.7% | 吻合 |
| 2 | preset 越慢体积越小 | ultrafast 8.93 → veryslow 3.28 MiB 单调下降(veryfast 3.37 例外,已知现象) | 基本吻合(有已知反常) |
| 3 | medium→slow 时间 +40%(官方 FAQ) | 实测 +64%(0.885→1.448 s,短素材波动大) | 方向一致,幅度偏高 |
| 4 | 两遍可命中目标体积 | 目标 1 MiB → 0.978 MiB(−2.2%) | 吻合(偏小,不超标) |
| 5 | 软字幕秒级、硬字幕需重编码 | 0.133 s vs 0.886 s,+644 字节 | 吻合 |
| 6 | -movflags +faststart 前移 moov | 偏移 6,159,200 → 36 | 吻合(字节级) |
| 7 | x265 同质量省 ~50%(Mux) | 合成素材上 crf28 比 x264 crf23 小 31% | 方向一致(CRF 跨编码器不可比,数值不矛盾) |
| 8 | (文献未载)失败必非零退出码 | 拒绝覆盖时 exit=0(9.0.2 实测) | 文献假设被推翻,批处理须防 |
| 9 | (文献未载)AV1 crf30 应更省 | libsvtav1 crf30 = 5.41 MiB,反而大于 x264 crf23 | 合成素材+默认参数下不成立,如实记录 |
复现说明:全部实验在会话内以真实命令运行(生成素材 testsrc2=size=1280x720:rate=30:duration=10 + sine,度量用 time 关键字与 ls -l 字节数,截图用 -ss 2 -frames:v 1 抽帧目检),原始输出已在会话记录中。
七、这次学到什么
- 先把"场景"问清楚,参数自己就定了:存档/点播/直播/设备四选一(slhck 决策表),比背 20 个参数更防错。ffmpeg 教程最大的噪声源就是拿 ABR 单遍当万能药。
- "公式 + 余量"优于"精确命中":8192 vs 8388.608 之争的本质是工程余量;x264 不填位流的特性让目标体积天然偏小 1–3%,写脚本时应预期"命中±3%"而非精确值。
- 字幕是一道"软硬"单选题,决策变量只有可移除性与播放器覆盖面;中文字幕的额外一维是字体/编码——UTF-8 SRT + force_style 指定 CJK 字体是 Windows 上的可靠组合。
- 批处理的第一性风险不在转码,在文件系统:引号、覆盖、退出码、并行度。本次实测抓到的"拒绝覆盖却 exit=0"证明:每个"理所当然"的平台行为都值得一条 10 秒的对照实验。
- 验证要落到最小可观测证据:字节序(faststart)、抽帧(烧录)、往返 diff(无损)、字节数(体积命中)——用仪器思维替代肉眼播放器,是 CLI 工具配方工程化的通用方法论。
附录 A · 本次全部实测命令(可整段复现)
# 0) 环境:ffmpeg 9.0.2-full_build-www.gyan.dev / Win11 / nproc=24
mkdir -p /tmp/ffrecipe && cd /tmp/ffrecipe
ffmpeg -y -f lavfi -i "testsrc2=size=1280x720:rate=30:duration=10" -f lavfi -i "sine=frequency=440:duration=10" \
-c:v libx264 -preset medium -crf 18 -pix_fmt yuv420p -c:a aac -b:a 128k src.mp4 # 6,171,001 B
# 1) CRF 阶梯
for c in 18 23 28 33; do time ffmpeg -y -i src.mp4 -c:v libx264 -preset medium -crf $c -c:a copy crf$c.mp4; done
# 2) preset 阶梯 @crf23:ultrafast/veryfast/medium/slow/veryslow(命令同上换 -preset)
# 3) 两遍目标 1 MiB:-b:v 710k -pass 1/-pass 2 -passlogfile /tmp/ffrecipe/pl
# 4) 硬字幕:-vf "subtitles=test.srt:force_style='FontName=Microsoft YaHei,FontSize=20'";抽帧目检
ffmpeg -ss 2 -i hard.mp4 -frames:v 1 frame_hard.png
# 5) 软字幕:-c copy -c:s mov_text -metadata:s:s:0 language=chi;往返:-map 0:s:0 提取 diff
# 6) 批处理:for 循环 + 无 -y 对照 + find|xargs -P 2;退出码逐一 echo $?
# 7) faststart:-c copy -movflags +faststart 后 od -A d -c 对比 moov/mdat 偏移附录 B · 来源链接汇总
- FFmpeg Wiki: Encode/H.264 —— https://trac.ffmpeg.org/wiki/Encode/H.264 (存档:https://web.archive.org/web/2024/https://trac.ffmpeg.org/wiki/Encode/H.264)
- FFmpeg Wiki: HowToBurnSubtitlesIntoVideo —— https://trac.ffmpeg.org/wiki/HowToBurnSubtitlesIntoVideo (存档:https://web.archive.org/web/2024/https://trac.ffmpeg.org/wiki/HowToBurnSubtitlesIntoVideo)
- slhck: CRF Guide —— https://slhck.info/video/2017/02/24/crf-guide.html
- slhck: Understanding Rate Control Modes —— https://slhck.info/video/2017/03/01/rate-control.html
- Bannerbear: How to Add Subtitles to a Video File Using FFmpeg —— https://www.bannerbear.com/blog/how-to-add-subtitles-to-a-video-file-using-ffmpeg/
- Mux: How to compress video files while maintaining quality with FFmpeg —— https://www.mux.com/articles/how-to-compress-video-files-while-maintaining-quality-with-ffmpeg
- Brainiarc7: ffmpeg-multi-instances-xargs —— https://gist.github.com/Brainiarc7/2afac8aea75f4e01d7670bc2ff1afad1
- Video SE: veryfast preset 体积反常 —— https://video.stackexchange.com/questions/30095/