必须先确认php是否真调用到ffmpeg 9.0:执行shell_exec('which ffmpeg 2>&1')看是否返回有效路径,若为空则说明web进程找不到该版本;再运行shell_exec('/path/to/ffmpeg -version 2>&1')验证输出含“9.0”字样,避免终端可用但php调用的是旧版。

确认 FFmpeg 9.0 是否真的被 PHP 调用到
PHP 本身不直接执行 FFmpeg,而是通过 exec()、shell_exec() 或 proc_open() 调用系统命令。报错时第一反应不该是“水印参数写错了”,而是“PHP 找没找到 FFmpeg 9.0”。常见现象:command not found、ffmpeg: command not found 或空输出。
- 在 PHP 中加一句
echo shell_exec('which ffmpeg 2>&1');,看是否返回有效路径(如/usr/local/bin/ffmpeg);若为空或报错,说明环境变量对 PHP(尤其是 Web 进程如 www-data 或 nginx 用户)不可见 - Web 服务用户通常没有
$PATH中的常用路径(比如 Homebrew 安装的/opt/homebrew/bin/ffmpeg),必须写绝对路径:/opt/homebrew/bin/ffmpeg -i ... - FFmpeg 9.0 是较新版本(2023 年底发布),很多系统默认源仍为 4.x/5.x;运行
ffmpeg -version确认输出里真有ffmpeg version 9.0,而非你本地终端能跑、但 PHP 调用的是另一个旧版
水印命令在 FFmpeg 9.0 中的语法变化
FFmpeg 9.0 移除了部分长期标记为 deprecated 的滤镜参数,最典型的是 movie 滤镜(用于加载水印图)已被彻底弃用,改用 stream_loop + lut 或更推荐的 overlay 直接配合 -i 输入。旧写法会直接报错:Unknown input filter: 'movie'。
- ❌ 错误示例(FFmpeg ffmpeg -i input.mp4 -i logo.png -filter_complex "movie=logo.png[wm];[0:v][wm]overlay=10:10" out.mp4
- ✅ 正确写法(FFmpeg 9.0 推荐):
ffmpeg -i input.mp4 -i logo.png -filter_complex "[0:v][1:v]overlay=10:10" -c:a copy out.mp4 - 如果水印需缩放,用
scale子滤镜:[1:v]scale=100:-1[wm];[0:v][wm]overlay=10:10,注意这里不用movie,第二输入流直接用[1:v] - 务必加
-c:a copy(除非要重编码音频),否则 FFmpeg 9.0 默认可能尝试重编码音频,导致耗时陡增甚至失败
PHP 执行时权限与路径问题比想象中更顽固
即使命令在终端能跑通,PHP 调用仍常因权限或路径崩掉,错误信息却常被吞掉(比如只返回 null 或空字符串)。关键不是“怎么写命令”,而是“PHP 进程以谁的身份、在哪种工作目录、访问哪些文件”。
- PHP 工作目录默认是 Web 入口脚本所在目录,不是你测试时的 home 目录 —— 所有
-i和输出路径必须用绝对路径,例如/var/www/html/uploads/input.mp4,不能写./uploads/input.mp4 - Web 用户(如
www-data)通常无权读取用户 home 下的图片,也无权写入系统临时目录(如/tmp)以外的路径;检查 logo.png 权限:ls -l /path/to/logo.png,确保组/其他用户有读权限(chmod 644) - 用
proc_open()捕获完整 stderr:php $descriptors = [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], // stderr ]; $proc = proc_open($cmd, $descriptors, $pipes); if (is_resource($proc)) { $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]); proc_close($proc); var_dump($stderr); // 这里才能看到 FFmpeg 真实报错 }
FFmpeg 9.0 对硬件加速和 alpha 通道更敏感
如果你的水印是 PNG(带透明背景),FFmpeg 9.0 默认行为更严格:若输入视频不含 alpha、而水印含 alpha,overlay 可能静默失败或输出黑边。这不是 bug,是格式协商更严谨了。
- 检查水印是否真有 alpha:
identify -format '%[channels]' logo.png(ImageMagick),输出含a才算真正带透明通道 - 强制保留 alpha 通道:在 overlay 后加
format=rgba,例如:[0:v][1:v]overlay=10:10:format=rgb(注意不是 rgba,overlay 默认 rgb,设 rgba 可能反而出错) - 避免用
-hwaccel auto:FFmpeg 9.0 的某些硬件加速后端(如 vaapi)对 overlay 支持不稳定,报错类似Failed to configure output pad on 'Parsed_overlay_1';先去掉硬件加速参数,纯 CPU 跑通再优化 - 加个
-y参数防止交互式覆盖提示卡住(PHP 进程无 TTY,会永久挂起)
movie、以及 PHP 进程能否真正读写那些文件——这些点比水印位置偏移之类的问题更容易卡死整个流程。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











