php调用ffmpeg添加水印或字幕的关键是正确处理编码、路径、坐标和错误捕获:windows下中文需iconv转gbk,字体路径须gbk且存在;overlay坐标用w/h与w/h区分大小写;srt须utf-8无bom;exec必须捕获stderr并检查returncode。

PHP 调用 FFmpeg 添加水印或字幕,本质是拼对命令、转对编码、防住乱码和注入——不是写 PHP 逻辑,而是把 shell 命令跑通、跑稳、跑安全。
drawtext 添加文字水印时中文显示为方块或乱码
根本原因是 FFmpeg 在 Windows 下默认不识别 UTF-8 编码的命令行参数,且字体文件路径/文字内容若含中文,未做编码转换就会失效。
- Windows cmd 默认编码通常是
GBK(chcp查看),而 PHP 文件和 Web 请求多为 UTF-8;直接传入中文字符串会解码失败 - 必须用
iconv('UTF-8', 'GBK', $text)将水印文字转成 GBK,再拼进命令;否则drawtext=text="中文"中的中文部分会被截断或乱码 -
fontfile路径也需是 GBK 编码(如C:\Windows\Fonts\simhei.ttf),不能用 Unicode 路径或带空格未转义的路径 - 推荐在 PHP 中先验证字体文件存在:
file_exists($fontPath),避免因路径错误导致静默失败
overlay 添加图片水印时位置错乱或不显示
常见于坐标计算误用变量名,或未正确引用视频/水印尺寸符号,FFmpeg 滤镜里大小写和作用域很敏感。
-
W和H表示输入视频宽高(大写),w和h表示水印图宽高(小写);写成W-h或w-H会导致负坐标,水印被裁掉 - 右下角固定偏移应写为
overlay=W-w-10:H-h-10,不是overlay=main_w-w-10:main_h-h-10(后者仅在某些滤镜上下文有效) - 如果水印 PNG 无透明通道,叠加后会有白底;务必用支持 alpha 的 PNG,并确认其实际含透明层(可用
ffprobe -v quiet -show_entries stream=codec_name -of default input.png辅助判断) - 叠加前建议加
format=rgba强制色彩空间,避免 YUV/RGB 混合导致颜色异常:[1]format=rgba[wm];[0][wm]overlay=...
添加字幕(SRT)时时间轴错位或不渲染
FFmpeg 不会自动将 SRT “烧录”进视频,必须显式指定字幕流处理方式;且 SRT 文件编码、换行、时间格式稍有偏差就会失败。
- 用
-vf subtitles=xxx.srt是最简方式,但要求 SRT 文件为 UTF-8 无 BOM,且每段时间格式严格匹配00:01:23,456 --> 00:01:25,789 - 若 SRT 含中文,同样要确保文件本身编码是 UTF-8(Notepad++ 可查),不能是 ANSI/GBK,否则字幕显示为空或乱码
- 不推荐混用
mencoder(如旧资料中出现的),它已淘汰;坚持用 FFmpeg 原生命令:ffmpeg -i video.mp4 -vf "subtitles=sub.srt:force_style='FontName=SimHei,FontSize=24'" -c:a copy out.mp4 -
force_style中的FontName必须是系统已安装字体名(非文件名),Windows 下可用SimSun、Microsoft YaHei等,不能填simhei.ttf
exec() 执行失败但没报错,或返回空数组
这不是 PHP 报错,而是 FFmpeg 进程崩溃、路径错误、权限不足或输出被重定向导致的“假成功”。
- 永远不要只靠
exec($cmd),必须捕获完整输出:exec($cmd . ' 2>&1', $output, $returnCode);$returnCode !== 0才是真失败 -
$output数组里第一行往往是关键错误,如No such file or directory(路径错)、Unable to find a suitable output format(扩展名或编码器问题)、fontconfig error(字体加载失败) - Linux 下注意 PHP 运行用户(如
www-data)是否有权读取字体文件、写入输出目录;Windows 下 IIS/Apache 用户可能无权访问C:\Windows\Fonts,建议把字体复制到项目目录并用相对路径 - 命令中所有文件路径必须用
escapeshellarg()包裹,尤其是用户上传的文件名,否则空格、单引号、分号会引发命令注入或截断
真正卡住人的从来不是语法,而是 Windows 的编码、Linux 的权限、字体名和文件名的细微差别、以及 FFmpeg 错误输出被吞掉——每次执行前,先在服务器终端手动跑一遍命令,确认它能出结果,再挪到 PHP 里封装。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











