必须先scale再overlay,否则水印会随缩放被拉伸扭曲;需先统一视频帧尺寸并补黑边,再叠加预处理好的适配尺寸水印图,确保位置精准、透明度保留。

竖屏视频加水印时 scale 和 overlay 的顺序不能颠倒
FFmpeg 处理竖屏(如 1080×1920)视频加角标水印,最常见问题是水印被拉伸、偏移或直接不显示。根本原因常出在滤镜链顺序:如果先 overlay 再 scale,水印会按原始分辨率叠加,后续缩放会连带扭曲水印;必须先统一缩放视频帧,再叠加已适配尺寸的水印图。
实操建议:
- 水印图建议预处理为固定尺寸(如 200×80),用透明背景,避免运行时缩放
- 滤镜链写成
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,overlay=10:10",确保视频先等比缩放到目标宽高、居中补黑边,再叠加 - 若水印本身含 alpha 通道,务必确认输入 PNG 是 32 位(
file watermark.png查看是否含Alpha),否则overlay会忽略透明度
overlay 坐标在竖屏下要按“物理坐标系”理解,不是 CSS 那套
很多人习惯把左上角当 (0,0),右下角是 (w,h),但 FFmpeg 的 overlay x/y 是从视频帧左上角起算的像素偏移,且不随旋转元数据自动调整——即使视频有 rotate=90 的 metadata,overlay 仍按原始解码帧布局计算。竖屏视频若未显式旋转,解码后实际是宽 > 高的横置帧,此时 (10,10) 会贴在左上角“短边侧”,视觉上像贴歪了。
解决方法:
- 强制转为竖屏布局再加水印:
-vf "transpose=1,scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,overlay=10:10"(transpose=1表示顺时针转 90°) - 或者用
overlay的shortest=1+ 动态表达式:overlay='if(gte(iw,ih),10,10):if(gte(iw,ih),10,10)'不实用,不如明确转帧 - PHP 中拼命令时,用
escapeshellarg()包裹路径和参数,防止水印路径含空格或括号导致命令截断
PHP 调用时 shell_exec 阻塞与超时需主动控制
给一个 60 秒竖屏视频加水印,FFmpeg 实际执行可能耗时 8–15 秒(取决于 CPU 和编码 preset)。PHP 默认 max_execution_time=30,但 CLI 模式下仍可能因系统 ulimit 或 FFmpeg 内部卡住导致 PHP 进程挂起,表现为脚本无响应、日志没报错、HTTP 请求超时。
关键动作:
- 调用前设超时:
set_time_limit(120),并用proc_open替代shell_exec,可捕获 stderr 实时输出,比如监听frame=行判断是否卡死 - FFmpeg 加
-v quiet -stats减少输出量,避免 PHP 缓冲区溢出;错误重定向到临时文件:2> /tmp/ffmpeg_err_{$pid}.log - 水印 PNG 若大于 500KB,PHP
file_get_contents读取后再 base64 编码传参不现实,应直接传文件路径,确保 Web 服务器用户(如 www-data)对水印路径有读权限
角标位置适配不同竖屏比例(1080×1920 vs 720×1280)要用动态 pad + overlay
纯靠固定坐标(如 overlay=20:20)无法兼顾各种竖屏分辨率。例如 iPhone 录制可能是 750×1334,安卓可能是 1080×2220,硬编码坐标会导致水印在某些机型上太靠边或被裁切。
可靠做法是用 FFmpeg 表达式动态计算:
- 右下角角标(留 20px 边距):
overlay='W-w-20:H-h-20',其中W/H是输出帧宽高,w/h是水印图宽高 - 但前提是视频帧已通过
scale+pad统一到目标尺寸,否则W/H是原始解码尺寸,不可靠 - PHP 中可先用
ffprobe获取原始宽高:ffprobe -v quiet -show_entries stream=width,height -of csv=p=0 input.mp4,再决定是否需要transpose或 pad 策略
真正麻烦的是水印字体渲染——FFmpeg 的 drawtext 在竖屏下容易字形压扁或换行错乱,角标若含文字,强烈建议用 PNG 图片而非动态渲染。另外,Android 某些低端机录的 HEVC 视频,FFmpeg 编译时没开 libx265 支持,转码会静默失败,得提前检查 ffmpeg -encoders | grep 265。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











