PHP 无法纯实现视频水印,必须依赖 ffmpeg:因 GD/Imagick 等扩展仅支持图像帧处理,无法解析音视频流;PHP 仅作调度器,水印逻辑由 ffmpeg 滤镜(overlay/drawtext)完成,需严格过滤参数、控制超时并校验返回码。

PHP 本身不直接支持视频水印添加,必须依赖外部命令行工具(主要是 ffmpeg),PHP 只负责拼接命令并执行。直接调用 exec() 或 shell_exec() 是最常用、最可控的方式。
为什么不能纯 PHP 实现?
PHP 的标准扩展(如 gd、imagick)仅处理图像帧,无法解析/编码/复用视频流(h.264、aac 等)。强行用 PHP 逐帧解码→加水印→重编码,效率极低且极易出错。
-
ffmpeg是工业级音视频处理工具,支持硬件加速、滤镜链、多路流同步等关键能力 - PHP 的作用只是“调度器”:构造命令、传参、检查返回值、清理临时文件
- 所有水印逻辑(位置、透明度、缩放、字体渲染)都由
ffmpeg的overlay、drawtext等滤镜完成
基础命令:图片水印叠加到视频右下角
这是最常见需求。需确保 ffmpeg 已安装且在系统 PATH 中,水印图建议为 PNG(带 alpha 通道)。
ffmpeg -i input.mp4 -i watermark.png -filter_complex "overlay=W-w-10:H-h-10" -c:a copy output.mp4
-
W-w-10表示横坐标:视频宽减水印宽再减 10 像素(右下角偏移) -
H-h-10表示纵坐标:同理 -
-c:a copy表示音频流直接复制,避免重编码失真 - 若水印需缩放,加
scale=120:-1到第二个输入:-i "scale=120:-1:flags=lanczos" watermark.png
文字水印:动态时间戳或固定文案
用 drawtext 滤镜,支持字体、颜色、阴影、时间变量。需指定 fontfile 路径(Linux 下常见于 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf)。
立即学习“PHP免费学习笔记(深入)”;
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:fontsize=24:fontcolor=white:x=w-tw-10:y=h-th-10:text='My Watermark'" -c:a copy output.mp4
-
tw和th是文字宽高,自动计算,无需手动测 - 显示当前时间戳:
text='%{localtime\:%Y-%m-%d %H\\\\\:%M\\\\\:%S}'(注意 Windows/Linux 转义差异) -
中文乱码?换用支持 UTF-8 的字体(如 Noto Sans CJK),并确认
fontfile路径无空格或中文
PHP 调用时的关键安全与稳定性控制
直接拼接用户输入进 shell_exec() 是严重漏洞。必须严格过滤、转义、超时控制。
- 使用
escapeshellarg()包裹所有路径和文本参数:escapeshellarg($videoPath) - 禁用用户控制滤镜表达式(如
x=、y=值),只开放预设位置(左上/右下/居中) - 设置执行超时:
set_time_limit(300);用proc_open()更好控制资源 - 检查
ffmpeg返回码:$output中含error或failed字样需中断 - 输出文件务必写入非 Web 可访问目录,防止未审核视频被直接下载
真正难的不是写对一条命令,而是处理不同分辨率视频下的水印比例适配、硬编解码兼容性(比如 NVIDIA GPU 加速需额外参数)、以及长时间运行时的进程僵死问题。这些都得靠日志 + 超时 + 状态轮询来兜底。











