
FFmpeg给视频添加图片或文字水印,如何精确控制位置?
在日常的视频制作和内容分发中,给视频加上水印是非常普遍的需求。无论是为了保护版权、展示品牌Logo,还是标注时间、作者信息,水印都起到了重要作用。很多人以为必须用Premiere、Final Cut Pro这类专业软件才能完成,其实只要学会FFmpeg的命令行操作,一条命令就能搞定图片水印和文字水印,还能精确控制它们的位置、大小和透明度。本文将从基础原理讲起,逐步带你掌握FFmpeg的水印技术。
一、图片水印的叠加原理与坐标系统
1.1 overlay滤镜的工作方式
FFmpeg处理图片水印的核心是overlay滤镜。这个滤镜的作用是把一张图片“盖”在视频画面上。要实现这个效果,FFmpeg需要同时接收两路输入:一路是视频流,另一路是图片流。在滤镜图中,我们用方括号加数字来标记不同的流,比如[0:v]表示第一个输入文件(通常是视频)的视频流,[1:v]表示第二个输入文件(图片)的视频流。overlay滤镜会把第二个流绘制到第一个流之上,然后输出一个新的视频流。
位置的控制由x和y两个参数决定,默认值是0,也就是图片的左上角与视频画面的左上角对齐。如果直接写死数值,比如x=100:y=200,那么水印就会固定出现在距离左边100像素、上边200像素的位置。但这种写法有一个明显的缺点:当视频的分辨率发生变化时,水印的相对位置也会改变,很可能跑到画面中间甚至外面去。
1.2 坐标系统与动态变量
FFmpeg的坐标系统原点在左上角,向右为x正方向,向下为y正方向。为了让水印在不同分辨率下都能保持在理想位置,我们需要使用内置变量。常用的变量有:
main_w:主画面(视频)的宽度main_h:主画面(视频)的高度overlay_w:水印图片的宽度overlay_h:水印图片的高度
假设你想让水印始终位于右下角,并且距离右边和下边各20像素,那么x和y的表达式应该是:
x = main_w - overlay_w - 20
y = main_h - overlay_h - 20这样不管视频是1920×1080还是1280×720,水印都会紧贴右下角,保持相同的边距。同理,如果要放在左下角,可以写成x=20:y=main_h-overlay_h-20;放在右上角则是x=main_w-overlay_w-20:y=20。
1.3 完整命令示例
下面是一条完整的命令,将名为logo.png的图片水印添加到input.mp4的右下角,并输出为output.mp4:
ffmpeg -i input.mp4 -i logo.png -filter_complex \
"[0:v][1:v]overlay=x=main_w-overlay_w-20:y=main_h-overlay_h-20" \
-c:a copy output.mp4这里有几个要点需要说明。首先,-filter_complex后面跟着滤镜图描述,它允许我们处理多个输入流。其次,-c:a copy表示音频流直接复制,不做重新编码,这样可以大幅提高处理速度,同时保证音质无损。最后,如果水印图片是PNG格式且带有透明通道,overlay会保留透明度,水印看起来就像浮在视频上一样;如果是JPEG这种没有透明度的格式,图片的矩形区域会完全遮挡住下面的视频内容,效果就不太理想了。
二、文字水印的drawtext滤镜配置
2.1 drawtext的基本用法
文字水印不能使用overlay滤镜,而是要用drawtext滤镜。这个滤镜直接在视频帧上渲染文本,相当于在每一帧画面上写字。使用drawtext时必须指定字体文件,因为FFmpeg本身不携带字体,需要依赖系统已有的字体库。在Linux系统中,常见的字体路径是/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf;在Windows上则是C:\Windows\Fonts\arial.ttf。如果你的字体路径中包含空格或特殊字符,需要用引号括起来。
文字的内容通过text参数传入,例如text='Hello World'。也可以使用textfile参数读取外部文本文件,适合需要大量文字的场景。此外,还可以使用格式化字符串,比如%{pts:hms}表示当前播放时间(时:分:秒格式),这在录制屏幕或直播回放时非常有用。
2.2 位置控制与时间变量
文字水印的位置同样由x和y控制,并且支持更多动态表达式。除了前面提到的main_w、main_h,还有tw(文字宽度)和th(文字高度)这两个变量。例如,要让文字固定在右上角,可以写成:
x = w - tw - 10
y = 10其中w和h是当前视频帧的宽度和高度,与main_w和main_h等效。
更高级的用法是利用时间变量t(当前时间,单位为秒)实现滚动或闪烁效果。比如让文字从右向左水平滚动:
x = w - mod(t * 100, w + tw)这里的mod函数取模运算,使得文字不断循环移动。注意,在滤镜表达式中,冒号和逗号有特殊含义,如果要在文字内容中使用它们,需要用反斜杠转义,比如text='Time\: now'。
2.3 中文文字与样式美化
中文文字水印需要特别注意字体文件的支持。如果使用的字体不包含中文字形,渲染出来的就会是乱码或方框。因此建议使用像“微软雅黑”、“思源黑体”这样的中文字体。在某些环境中,还需要加上text_shaping=1参数来启用文字整形,确保复杂排版(如竖排文字)正确显示。
为了让文字在亮色背景下更清晰,可以使用box参数添加背景框。例如box=1:boxcolor=black@0.5会在文字背后绘制一个半透明的黑色矩形,大大提升可读性。字体颜色可以用fontcolor指定,支持十六进制颜色码或颜色名称,比如fontcolor=white或fontcolor=#FF0000。字体大小用fontsize控制,单位是像素。
下面是一个在视频左上角显示当前时间码的例子:
ffmpeg -i input.mp4 -vf \
"drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf:\
text='%{pts:hms}':x=10:y=10:fontsize=24:fontcolor=white:box=1:boxcolor=black@0.5" \
-c:a copy output.mp4三、多水印组合与性能优化策略
3.1 同时添加图片和文字水印
实际业务中经常需要既放Logo又加版权文字。FFmpeg允许在一条filter_complex中串联多个滤镜。思路是先对原始视频应用overlay添加图片,得到中间结果,然后再对这个中间结果应用drawtext添加文字。中间结果需要用方括号别名标记,以便后续滤镜引用。
典型的写法如下:
ffmpeg -i input.mp4 -i logo.png -filter_complex \
"[0:v][1:v]overlay=x=main_w-overlay_w-30:y=main_h-overlay_h-30[v1];\
[v1]drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf:\
text='Copyright www.bbccb.com':x=(w-text_w)/2:y=main_h-th-20:fontsize=20:fontcolor=yellow[v2]" \
-map "[v2]" -map 0:a -c:a copy -c:v libx264 -crf 20 output.mp4这条命令做了以下几件事:首先将logo.png叠加到视频右下角,输出命名为[v1];然后对[v1]添加文字“Copyright www.bbccb.com”,文字水平居中(x=(w-tw)/2),垂直位于底部上方20像素(y=main_h-th-20),输出命名为[v2]。最后用-map明确选择处理后的视频流[v2]和原始音频流0:a,避免滤镜图输出干扰默认流选择。
3.2 条件显示与动态布局
有时我们希望水印只在视频的前几秒出现,或者只在特定时间段显示。这可以通过enable表达式实现。例如,只在视频前10秒显示图片水印:
overlay=x=...:y=...:enable='lt(t,10)'lt(t,10)表示时间t小于10秒时为真。同样,drawtext也支持enable参数。
对于竖屏和横屏混合的素材,可以结合if表达式判断视频方向。比如检测到高度大于宽度(竖屏)时,将水印放在顶部中央;否则放在右下角。虽然命令行写起来有点长,但本质上就是一段脚本化的逻辑。
3.3 性能优化技巧
添加水印通常不会改变视频的分辨率和帧率,所以编码时可以尽量保持画质。推荐使用-c:v libx264 -crf 18,CRF值越低质量越高,18~22是比较平衡的范围。音频直接复制即可(-c:a copy)。
当处理4K超高清视频时,水印图片的缩放计算可能会成为性能瓶颈。解决办法是在传入overlay之前,先将水印图片缩放到合适的尺寸。例如,先用scale滤镜把logo缩小到视频宽度的10%,再叠加:
[1:v]scale=iw*0.1:-1[logo]; [0:v][logo]overlay=...另外,使用-preset veryfast可以大幅缩短编码时间,同时画质损失肉眼几乎不可察觉。如果机器性能足够,也可以用-preset medium获得更好的压缩效率。
四、常见问题与排查方法
4.1 水印位置不对或超出画面
最常见的原因是坐标表达式写错了。比如忘了减去水印自身的宽高,导致水印一部分跑到画面外面。建议先在命令行中打印出视频的宽高信息(用ffprobe),然后手动计算预期坐标,再对比实际效果。另外,注意变量名的大小写,main_w和MAIN_W是不同的。
4.2 文字显示为方框或乱码
这几乎都是字体问题。要么字体路径不正确,要么字体不支持中文字符。可以先测试一个英文字符,如果正常显示,再换成中文。确保字体文件存在且可读,必要时使用绝对路径。在Windows上,路径中的反斜杠需要写成双反斜杠或者用正斜杠。
4.3 水印闪烁或抖动
如果水印图片本身带有半透明区域,而视频又是可变帧率,可能会出现闪烁。可以尝试将水印图片转换为固定尺寸,并在overlay中加上format=rgba强制使用RGBA色彩空间。另外,确保输入视频的帧率稳定,必要时用-r参数固定输出帧率。
4.4 处理速度极慢
如果发现编码速度远低于实时,可能是因为开启了过多的滤镜或使用了高CRF值。可以尝试降低CRF到23~28,或者使用硬件加速编码(如-c:v h264_nvenc)。另外,检查是否无意中改变了分辨率或帧率,不必要的重采样会拖慢速度。
五、总结
通过本文的学习,你应该已经掌握了FFmpeg添加图片水印和文字水印的核心方法。关键在于理解overlay和drawtext两个滤镜的参数含义,以及熟练运用坐标变量实现自适应定位。多水印组合时注意滤镜链的串联写法,性能优化则围绕编码参数和预处理展开。只要多加练习,即使面对复杂的业务需求,也能用一条简洁的命令完成高质量的水印添加,无需依赖昂贵的商业软件。
FFmpegwatermarkvideo_processing修改时间:2026-08-21 00:16:32