FFmpeg视频水印与分辨率调整:从入门到组合实操
搞视频处理的人不管是做短视频运营、在线教育录课还是自己折腾NAS里的家庭录像迟早都会撞上两件事给视频加水印以及跟分辨率较劲。水印是为了打上自己的标记、防止素材被白嫖分辨率则直接决定成片画质、文件大小甚至推流时候会不会卡顿。而这两件事用 FFmpeg 一条命令就能一起解决。FFmpeg 这个命令行工具在音视频圈子里几乎是“神级”存在它的强大之处不在于某个花哨界面而在于你能用一行命令精确控制每一个像素和每一帧画面。这篇文章我打算把水印和分辨率这两块彻底讲透文字水印怎么加、图片 Logo 怎么叠、位置怎么精确控制到“九宫格任意一格”分辨率怎么查看、怎么指定、录音录像时怎么选最后再给几个能直接抄作业的组合命令顺便把我踩过的坑和已经验证过的排查技巧一起放出来。全文以实操为主命令会逐条拆解。没接触过 FFmpeg 的小白照着重现就行有基础的也能在位置计算和滤镜组合上拿到一些新思路。1. FFmpeg给视频加水印的两条路drawtext文字水印与overlay图片叠加1.1 文字水印drawtext一条命令搞定“我的频道名”文字水印是使用频率最高的一种适合在视频角落放上频道名、账号ID、拍摄日期之类的内容。FFmpeg 里对应的滤镜叫 drawtext工作流程可以简单理解为解码视频帧 - 在帧上把文字画上去 - 再重新编码输出。最基础的一条命令长这样ffmpeg -i input.mp4 -vf drawtexttextMyChannel:fontsize48:fontcolorwhite:x10:y10 -c:a copy output.mp4这里面的参数逐个拆开看textMyChannel要显示的文字内容。如果包含空格或特殊符号一定要用引号包起来。fontsize48字号单位是像素。做全屏水印建议小一点角落水印可以设到36到64之间。fontcolorwhite文字颜色。常见的还有black、yellow也可以写成十六进制颜色值比如0xFF0000表示红色。x10:y10文字左上角锚点的坐标单位是像素。后面章节我会详细说这个坐标怎么算。有一件事我必须放在最前面提醒在 Windows 环境下drawtext 的参数里冒号:和命令行参数分隔符冲突很容易解析出错。建议在 Windows 下用双引号把 filter 串包住并且尽量避免空格。Linux 和 macOS 下相对宽容但养成统一写法的习惯能省掉很多麻烦。再补充一个重点如果需要显示中文必须指定中文字体文件。否则即使系统里有中文字体FFmpeg 也可能找不到水印就会变成方块。指定字体的命令是这样的ffmpeg -i input.mp4 -vf drawtexttext测试水印:fontfileC\:\\Windows\\Fonts\\msyh.ttc:fontsize48:fontcolorwhite:x10:y10 -c:a copy output.mp4Windows 下路径里的反斜杠需要转义成\\冒号前面也要加\这是不少新手第一次使用 drawtext 时会卡住半小时的细节。Linux 下则简单得多ffmpeg -i input.mp4 -vf drawtexttext测试水印:fontfile/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf:fontsize48:fontcolorwhite:x10:y10 -c:a copy output.mp41.2 图片水印overlay给视频盖上Logo如果不想用文字而是想把一张带透明通道的 PNG Logo 叠加到视频上那就用 overlay 滤镜。它的效率比 drawtext 高一些因为不需要每次渲染文字轮廓直接做图片合成。ffmpeg -i input.mp4 -i logo.png -filter_complex overlay10:10 -c:a copy output.mp4这条命令的输入有两路-i input.mp4是主视频-i logo.png是水印图片。overlay10:10表示把第二路输入叠加到第一路输入上坐标是左上角10, 10。注意叠加滤镜放在-filter_complex里而不是-vf因为它同时操作两个输入流。overlay 里有个很实用的坐标变量体系W和H主视频的宽和高w和h水印图片的宽和高所以“右下角留 10 像素边距”就可以写成overlayW-w-10:H-h-10意思是水印的左上角放在“主视频宽度减去水印宽度再减 10”的位置上。这条表达式逻辑稍后在水印位置章节会反复用到建议直接背下来。对于准备长期使用的号主我强烈建议把 Logo 做成一角透明的 PNG尺寸控制在 200 到 300 像素范围内。PNG 的透明通道能让水印显得既不突兀又能一直存在而 JPG 白底图叠上去会直接毁掉画面。1.3 进阶多行多列文字水印与动态时间戳很多教程讲到这里就停了但实际上 drawtext 还能做多行多列水印和动态水印。所谓多行多列一般是重复绘制多个文字块铺满画面或者做成栅格。比如要在画面里铺一个 3x3 的频道名水印栅格可以叠加多个 drawtextffmpeg -i input.mp4 -filter_complex \ drawtexttextMyChannel:fontsize36:fontcolorwhite0.3:x50:y50,\ drawtexttextMyChannel:fontsize36:fontcolorwhite0.3:x(w-tw)/2:y50,\ drawtexttextMyChannel:fontsize36:fontcolorwhite0.3:xw-tw-50:y50 \ -c:a copy output.mp4这里的white0.3是颜色透明度语法0.3表示 30% 不透明度适合做那种“存在但不打扰”的满屏水印。tw是文字实际渲染后的宽度后面讲坐标时会详细展开。动态时间戳的做法也很有意思。给录屏、监控录像打上拍摄时间是 drawtext 的另一个高频场景ffmpeg -i input.mp4 -vf drawtexttext%{localtime\:%Y-%m-%d %H\\:%M\\:%S}:fontsize24:fontcoloryellow:xw-tw-20:yh-th-20 -c:a copy output.mp4%{localtime:...}是 drawtext 内建的时间展开语法它会在每一帧刷新时重新渲染当前系统时间。注意里面的冒号也需要转义成\\:不然会跟参数分隔符冲突。这条命令我用来给家里的摄像头录像做时间水印跑了一年多没有出过问题。2. 水印位置不求人坐标规则、九宫格速查与跑马灯效果2.1 FFmpeg水印坐标体系原点、方向和常见坑先明确坐标原点FFmpeg 画布左上角是 (0, 0)x 轴向右增大y 轴向下增大。这和你在学校学的平面直角坐标系在 y 轴方向上是反的很多第一次接触的人会下意识把 y 往大写结果水印直接跑出画面底部。drawtext 滤镜里可用的变量如下w、h主视频画面的宽和高。tw、th等价写法text_w、text_h实际渲染出来的文字宽度和高度由字号和内容决定。overlay 滤镜里可用的变量略有差异W、H主视频画面的宽和高。w、h水印图片的宽和高。所以你会发现drawtext 里靠tw、th计算文字自身尺寸overlay 里靠w、h计算图片自身尺寸。这两个体系搞混是水印位置翻车的最常见原因。举个例子你要把文字水印放在右下角离边距 20 像素。正确写法是drawtexttextMyChannel:xw-tw-20:yh-th-20我第一次写的时候用了xW-tw-20结果 W 这个变量在 drawtext 里并不存在准确说是主视频的另一个别名但在部分版本中不会被解析水印直接没有显示。正确理解变量所属的滤镜上下文能少走很多弯路。另外需要注意坐标的计算时机。FFmpeg 的滤镜表达式是逐帧求值的也就是说只要视频分辨率在流水线中发生变化水印位置会自动跟着新分辨率重新计算。这算是 FFmpeg 的贴心之处但前提是你用了w、h这样的相对变量而不是写死一个数字。2.2 九宫格水印定位速查表为了方便日常使用我把最常见的水印摆放位置整理成了一张速查表。文字水印套用drawtext把tw/th换成文字自身宽高图片水印套用overlay把tw/th换成w/h。实际操作时水印的定位可以用这几个公式直接套用位置drawtext 文字水印坐标overlay 图片水印坐标左上角x20:y20x20:y20上边居中x(w-tw)/2:y20x(W-w)/2:y20右上角xw-tw-20:y20xW-w-20:y20左边居中x20:y(h-th)/2x20:y(H-h)/2画面正中x(w-tw)/2:y(h-th)/2x(W-w)/2:y(H-h)/2右边居中xw-tw-20:y(h-th)/2xW-w-20:y(H-h)/2左下角x20:yh-th-20x20:yH-h-20下边居中x(w-tw)/2:yh-th-20x(W-w)/2:yH-h-20右下角xw-tw-20:yh-th-20xW-w-20:yH-h-20这张表里的20都可以换成任意边距值。你会发现规律非常统一左右看w-tw还是(w-tw)/2上下看h-th还是(h-th)/2只要记住“自身尺寸放在表达式里”这个原则任何分辨率都能自动居中或靠边。2.3 动态水印跑马灯效果与分辨率自适应动态水印听起来高大上其实也只是在坐标里放了一个随时间变化的表达式。drawtext 的坐标支持表达式求值而表达式里有一个内置变量t表示当前播放时间单位是秒。跑马灯效果也就是水印从左上角缓慢移动到右下角可以用这样一条命令ffmpeg -i input.mp4 -vf drawtexttextMyChannel:fontsize36:fontcolorwhite0.5:xmod(50*t\,wtw):ymod(40*t\,hth) -c:a copy output.mp4mod(50*t, wtw)的意思是把随 t 线性增长的值映射到 0 到 总宽度的循环区间里水印就会循环移动。50和40分别是水平和垂直方向的移动速度单位是像素/秒。逗号在滤镜参数里是分隔符出现在坐标表达式内部时必须转义成\,否则 FFmpeg 解析会提前截断。这种跑马灯水印适合防搬运场景虽然稍微有点干扰观看但盗视频的人很难通过简单裁剪把水印去掉。如果你担心影响观看体验可以把移动速度调慢到 20 以下或者像我上面写的那样把透明度降到 0.5 以下观感会舒服很多。3. 分辨率三件事怎么查看、怎么指定、录音录像时怎么选3.1 快速查看视频分辨率的三个方法在加水印、转码、推流之前第一步永远是搞清源视频的分辨率。FFmpeg 提供了几种查看方式按使用场景选即可。第一个方法最简单直接用-i参数让 FFmpeg 输出媒体信息报错也没关系信息照样会打印出来ffmpeg -i input.mp4看输出里的这一行Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9]1920x1080就是分辨率。第二个方法用 ffprobe这是 FFmpeg 套件里专门查媒体信息的工具输出干净适合脚本化调用ffprobe -v error -select_streams v:0 -show_entries streamwidth,height -of defaultnoprint_wrappers1 input.mp4输出会是这样width1920 height1080第三个方法适合批量处理时用直接将分辨率写入文件ffprobe -v error -select_streams v:0 -show_entries streamwidth,height -of csvsx:p0 input.mp4输出1920x1080。这个写法我经常放在 shell 脚本里配合变量做下一步判断。3.2 指定输出分辨率的姿势-s、scale与等比例缩放指定输出分辨率主要有两种写法-s参数和scale滤镜。很多新手喜欢用-s因为它短但它的短板很明显直接拉伸不会保持宽高比。4:3 的视频被强行压到 16:9 的画面人物会变成“矮胖子”这个效果在录制讲座、PPT 视频时尤其明显。不推荐的做法ffmpeg -i input.mp4 -s 1920x1080 -c:a copy output.mp4推荐的做法是用 scale 滤镜配合等比例控制ffmpeg -i input.mp4 -vf scale1280:720 -c:a copy output.mp4如果源视频是 1080p 想降到 720p等比缩放一行代码搞定ffmpeg -i input.mp4 -vf scale1280:-1 -c:a copy output.mp4-1表示另一个维度按照源视频比例自动计算。这样既固定了宽度高度也自动完成等比不会变形。如果想让输出的宽高严格等于目标值同时又不裁剪画面内容可以用force_original_aspect_ratiodecrease先等比缩放到目标尺寸以内ffmpeg -i input.mp4 -vf scale1280:720:force_original_aspect_ratiodecrease -c:a copy output.mp4这个写法的效果是等比缩放并保证目标尺寸内完整显示可能留出黑边。如果不想有黑边就需要“放大 裁剪”组合拳这个放在第四部分实操里展开。3.3 录音录像时分辨率选择的实际考量录音录像时怎么定分辨率要看三样东西摄像头支持什么分辨率、目标平台建议什么分辨率、你的编码性能能不能跑得动。FFmpeg 调用本地摄像头采集画面Windows 上典型命令是ffmpeg -f dshow -list_devices true -i dummy先列出可用的设备名然后开始录制ffmpeg -f dshow -i videoUSB Camera -f dshow -i audio麦克风 (USB Audio) -c:v libx264 -s 1280x720 -c:a aac -t 60 output.mp4Linux 上通常走 v4l2列出设备格式用这条命令ffmpeg -f v4l2 -list_formats all -i /dev/video0然后以 720p 30 帧录制ffmpeg -f v4l2 -framerate 30 -video_size 1280x720 -i /dev/video0 -f alsa -i default -c:v libx264 -preset veryfast -c:a aac output.mkv这里-video_size必须放在-i前面因为它不是滤镜而是摄像头采集参数。很多人在 Linux 下录了半天发现分辨率没生效就是这个参数位置的问题。关于分辨率选多大我给一个参考表格适用于大多数视频平台和录制场景目标场景分辨率建议码率手机观看、短视频1280x7202-4 Mbps主流网站成片1920x10804-8 Mbps大屏/高清素材2560x14409-14 Mbps4K 播放/后期精剪3840x216020-40 Mbps码率太低画面会出现明显的块状模糊尤其在高动态场景下码率太高文件体积直线上升而且上传平台也会二次压缩。上面这个表格是基于我自己的录制经验整理出来的不同场景可以微调但不要跨档乱跳。另一个需要重视的问题是电脑的编码性能。如果用的是软件编码 libx2641080p 30fps 录制时 CPU 占用会直线飙升风扇起飞是常态。此时有两个选择一是降低分辨率到 720p二是加上-preset veryfast或-preset ultrafast牺牲压缩率换编码速度。如果硬件支持还可以考虑硬件编码。NVIDIA 显卡用-c:v h264_nvencIntel 核显用-c:v h264_qsvAMD 用-c:v h264_amf。这些编码器同样有对应的-preset p1/p2之类的参数具体在命令行里敲ffmpeg -h encoderh264_nvenc就能看到。4. 组合实操一次搞定“分辨率转换水印”的完整命令4.1 从原始命令到可用命令的拆解很多教程只教单独的水印命令或单独的分辨率命令但实际处理视频时两件事往往是同时发生的。比如你从手机导出一段 4K 素材想压成 1080p同时在右下角打上自己的频道名这就是典型的“一次滤镜链、多重效果”的需求。一条完整的组合命令如下ffmpeg -i input.mp4 -vf scale1920:1080:force_original_aspect_ratiodecrease,drawtexttextMyChannel:fontsize36:fontcolorwhite0.7:xw-tw-30:yh-th-30 -c:v libx264 -preset medium -crf 18 -c:a aac -b:a 192k output.mp4逐个拆解scale1920:1080:force_original_aspect_ratiodecrease先把视频等比缩放到不超过 1920x1080 的范围。如果源视频本身就是 4K 横屏视频它会缩到 1920x1080 附近画面上没有黑边比例也正确。drawtext在缩放后的画面上画水印。因为滤镜链是顺序执行的水印的坐标参考是缩放后的画面所以xw-tw-30里的w已经是 1920水印自动位于缩放后画面的右下角。-crf 18libx264 的质量控制参数数值越低质量越高18 是视觉无损级别。日常网络发布不建议低于 18否则文件会大得毫无意义。-preset medium压缩速度和压缩率的平衡档。这里我特别说明一下force_original_aspect_ratiodecrease的作用。它有两种模式decrease是“等比缩小到不超出目标框”适合保证裁剪安全increase是“等比放大到完全盖住目标框”适合配合crop做去黑边处理。需要铺满屏幕且不留黑边时用下面这条“裁切版”ffmpeg -i input.mp4 -vf scale1920:1080:force_original_aspect_ratioincrease,crop1920:1080,drawtexttextMyChannel:fontsize36:fontcolorwhite0.7:xw-tw-30:yh-th-30 -c:v libx264 -preset medium -crf 18 -c:a aac -b:a 192k output.mp4scale先把画面放大到超出 1920x1080然后crop1920:1080从画面正中心截取一块 1920x1080 的内容。最后画水印。这个流程就是各大视频平台“封面占满”效果的标准实现区别只是平台后端用的编码器不同而已。配合第 2 节的九宫格公式水印位置可以随意切换。比如要放在正中间防止盗用把xw-tw-30:yh-th-30换成x(w-tw)/2:y(h-th)/2即可。4.2 竖屏短视频的处理思路短视频平台的竖屏视频默认是 1080x1920也就是宽 1080、高 1920。从横屏素材转竖屏时如果你直接把scale1080:1920套上去画面会被严重拉伸变形。正确的处理思路跟上面类似先等比放大再裁切ffmpeg -i input_horizontal.mp4 -vf scale1080:1920:force_original_aspect_ratioincrease,crop1080:1920,drawtexttextMyChannel:fontsize48:fontcolorwhite:x(w-tw)/2:yh-th-80 -c:v libx264 -preset medium -crf 20 -c:a aac output_vertical.mp4这条命令会把横屏素材放大到完全覆盖 1080x1920然后从中间裁出竖屏范围。水印放在竖屏画面中下方贴近短视频的使用习惯。缺点是画面上下部分会被裁掉不少如果原视频的关键信息在左右两侧裁切会直接丢内容。这种场景更适合“背景模糊 居中完整画面”的方案那个属于滤镜链的高级玩法这里先不展开。4.3 几个值得养成习惯的FFmpeg小参数组合命令用得顺手之后有几个参数我会建议你固定写进去它们能避免很多莫名其妙的问题。第一个是-y。FFmpeg 默认在输出文件已存在时会进入交互询问脚本化执行时直接卡住。加上-y表示无条件覆盖省心很多。第二个是-c:a copy的判断。如果只处理视频画面、不动音频直接-c:a copy拷贝音频流速度飞快而且不会引入二次音频压缩损失。只有需要改变音频采样率或者码率时才用-c:a aac重编码。第三个是-movflags faststart。这个参数只对 MP4 有效作用是把播放需要的索引信息从文件末尾移到文件开头。没有它从网页直接播放 MP4 时要等整个文件下载完才能拖动进度条加上它浏览器一打开就能秒播。我处理所有要上传到网站的视频都会加这个参数。ffmpeg -i input.mp4 -vf scale1280:720 -c:v libx264 -crf 20 -preset medium -c:a aac -b:a 128k -movflags faststart -y output.mp45. 常见问题与排查技巧实录5.1 常见问题速查表在使用 FFmpeg 过程中踩过不少坑这里整理成一张速查表都是能一两句话解决的典型问题现象原因解决方案水印完全没有显示fontfile 路径错误或 drawtext 参数被转义截断检查字体路径Windows 下注意反斜杠和冒号转义先输出一帧静帧测试中文水印显示成方块没有指定中文字体用fontfile指定系统中文字体文件比如微软雅黑 msyh.ttc分辨率变了但水印位置偏了坐标写死了具体像素改用w/tw/h/th表达式变量让水印随分辨率自适应输出画面变形、人物被拉宽直接用-s强制拉伸改用scale滤镜加force_original_aspect_ratio输出时提示会覆盖文件FFmpeg 默认交互确认命令开头加-y转码速度极慢默认编码参数过于保守加-preset veryfast或用硬件编码器h264_nvenc/h264_qsv视频无法拖动进度条MP4 索引在文件尾部加-movflags faststart这张表里的问题我几乎每一条都真实遇到过一次以上。尤其是第一条“水印完全没有显示”我在给朋友远程排障时见过太多次十有八九是 Windows 下滤镜参数里的冒号没有正确转义或者是字体路径少了转义符号。5.2 排查技巧先测静帧再跑全片这是我认为对新手最有价值的一条排查思路不管你的命令最终要处理多长的视频在正式跑全片之前先把输出限制成一张静帧。这样做的好处是一张图只要零点几秒就能出来而跑全片可能要几分钟甚至几十分钟。命令写错了跑全片就是浪费大把时间。做法很简单在滤镜链末尾加上-frames:v 1并输出成 PNGffmpeg -i input.mp4 -vf scale1280:720,drawtexttextMyChannel:fontsize36:xw-tw-30:yh-th-30 -frames:v 1 test.png打开test.png看一眼水印位置对不对、字号大不大、颜色清不清楚。一切满意后再把-frames:v 1删掉正式输出视频。这个习惯我坚持了很多年它能让你在动手写一条复杂命令时不断试错成本极低。如果水印位置不对改动的也只是坐标表达式重新跑静帧验证再正式编码效率会提高一个数量级。定位问题最忌讳的就是拿一个十分钟的视频反复试所有时间都耗在等待上了。5.3 关于去水印合法场景与delogo滤镜用法热词里大量出现“去水印”需求这里必须补充说明。FFmpeg 确实提供了delogo滤镜作用是去除视频画面中指定区域的 Logo 水印原理是读取水印区域周围的像素值用插值方式把水印区域重新填充。命令长这样ffmpeg -i input.mp4 -vf delogox100:y100:w120:h40 -c:a copy output.mp4x/y/w/h四个参数圈定水印所在区域。注意这个滤镜对动态水印无效因为水印位置变化后区域就不准了对透明半透明叠印在复杂纹理上的水印效果也一般插值补出来的画面会有较明显的涂抹感。它更适合那种位于纯色背景或静态画面上的固定水印。但使用这个功能前请务必确认素材的版权归属只能处理自己拥有版权的视频或者去除平台自动叠加的标记。拿别人的版权内容去水印再传播既违反平台规则也触碰法律红线。技术本身是中性的使用边界得自己把握好。结尾的一些个人经验最后分享一个我自己的小习惯凡是涉及水印和分辨率组合的命令我都会把滤镜链的关键部分写成一个脚本文件而不是每次敲一长串。比如处理 YouTube 和 B 站视频两套分辨率预设和水印文案往往不同我就会写两个脚本参数化处理一行命令调用既不担心手误也能保证长期一致的输出风格。多试几次之后你会发现FFmpeg 的滤镜链就像搭积木水印和分辨率只是最基础的两块。当你熟练了 drawtext 的坐标表达式理解了 overlay 和 scale 的变量体系再去碰剪切、拼接、转场、字幕、音画同步这些功能时会顺手很多。希望这篇内容能帮你在处理水印和分辨率问题时少走几段弯路把那点折腾命令的时间省下来用到更值得的地方去。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →