ffmpeg 9.0 中 drawtext 中文乱码本质未变,仍因 text 非 utf-8 字节流或 fontfile 缺中文字形所致;但因 meson 构建、freetype 升级及字体缓存收紧,不达标时更易直接渲染为 □ 或空白。

FFmpeg 9.0 中 drawtext 的中文乱码本质没变,但环境更敏感
FFmpeg 9.0 并没有修改 drawtext 对文本编码或字体加载的底层逻辑,所以乱码原因和旧版本一致:还是那两个硬性条件没满足——text 参数必须是 UTF-8 字节序列,且 fontfile 指向的字体文件必须包含中文字形。但 9.0 的构建方式(Meson 默认启用更多严格检查)、默认链接的 FreeType 版本升级、以及部分 Linux 发行版对字体缓存机制的收紧,会让这两个条件“不达标”时表现得更彻底:不是偶尔错位,而是直接渲染成 □ 或完全空白。
Windows 下命令行传中文 text= 仍会因 CMD 编码崩掉
在 Windows 的 CMD 或 PowerShell 中直接写 text='版权所有',哪怕字体路径正确,大概率还是乱码。因为 CMD 默认代码页是 GBK(如 chcp 936),而 FFmpeg 9.0 的 drawtext 解析器只认 UTF-8 字节流。它拿到 GBK 编码的字节,去查字体里的 Unicode 码位,自然查不到。
- 最稳做法:改用
textfile=watermark.txt,把中文内容单独存为 UTF-8 无 BOM 的文件 - 若坚持用
text=,必须先在 CMD 执行chcp 65001切到 UTF-8 模式,再运行 FFmpeg 命令(注意:PowerShell Core 7+ 默认 UTF-8,但旧版 PowerShell 5.1 不保证) - 绝对不要依赖 Notepad 保存的“UTF-8”,它默认带 BOM;用 VS Code、Notepad++ 或
iconv -f utf-8 -t utf-8 -c watermark.txt > clean.txt清除 BOM
Linux 下 fontfile 路径失效常因字体缓存未刷新
你把 simhei.ttf 放进 /usr/share/fonts/truetype/,命令里写 fontfile=/usr/share/fonts/truetype/simhei.ttf,却报 Cannot load font file 或继续乱码——大概率是字体缓存没更新,或者 FreeType 在 9.0 下对 TTC/OTF 的子集索引更严格了。
- 手动安装后务必执行
fc-cache -fv,而不是只跑fc-cache -f - 用
fc-list :lang=zh确认字体真被系统识别;如果没输出,说明字体文件损坏或路径权限不对(ls -l看是否可读) - 避免用
fontfile=simhei.ttf这种相对路径,FFmpeg 9.0 的工作目录行为在 Meson 构建下更不可控;一律用绝对路径,且路径含空格时用单引号包裹:fontfile='/home/user/Fonts/SimHei.ttf'
多行中文水印末尾出 □ 是换行符残留,不是字体问题
如果你用 text='第一行
第二行',生成视频里每行末尾都带一个方块,这不是字体缺字,而是 FFmpeg 9.0 的 drawtext 在解析
后,没剥离这个控制符就交给 FreeType 渲染——FreeType 尝试在字体里找 U+000A(换行符)的字形,找不到就画 □。
- 别信网上“把 换成 \n 或 \\n”的玄学方案,那是 shell 转义层级混乱导致的误判
- 正确解法只有两个:
textfile方式(文件里每行自然换行,FFmpeg 内部处理干净);或用drawtext多次叠加,比如drawtext=...:text='第一行':y=20,drawtext=...:text='第二行':y=60 - 如果必须单条命令多行,可用
textfile+echo -n '第一行' > tmp.txt; echo '第二行' >> tmp.txt(注意-n避免首行多空行)
FFmpeg 9.0 的水印乱码问题,核心从来不在版本本身,而在于你是否真正控制了字节流源头(文本编码)和字形供给源头(字体文件及其系统注册状态)。任何跳过这两点的“快速修复”,比如改 color 或加 shadow,都是在掩盖症状。











