最近在做一个视频转码的小工具,折腾 FFmpeg 折腾了两天,踩了七八个坑。干脆把过程整理出来,方便自己以后查阅,也给同样在坑里的朋友一点参考。
一、为什么还要用 FFmpeg
现在剪映、PR 满天飞,但做批量处理、服务器端转码、或者简单的水印/格式转换,FFmpeg 还是绕不开。命令行一敲搞定的事情,没必要开个几百兆的 GUI。
二、安装(顺便说说我遇到的坑)
Linux (Ubuntu/Debian)
sudo apt update
sudo apt install ffmpeg
看似简单,但 apt 带的版本通常老半年以上。我一开始没注意,结果用某些新滤镜的时候报错 No such filter。后来还是老老实实从源码编译——但其实有更简单的办法:用静态编译好的二进制包。
推荐去 johnvansickle.com/ffmpeg 下载静态构建版本,解压丢到 /usr/local/bin 就行,省事。
macOS
brew install ffmpeg
注意 brew 默认不会开启所有编解码器,比如我想用 libx265,得额外装:
brew install ffmpeg --with-libx265
# 新版brew改了,要用:
brew install ffmpeg
# 然后看提示,可能需要 brew reinstall ffmpeg --enable-xxx ?其实现在 homebrew-ffmpeg 也有额外 tap
反正我踩过:转码时提示 Unknown encoder 'libx265',才发现没装全。建议直接 brew install ffmpeg --with-* 把常用库都加上,或者跑一次 ffmpeg -encoders | grep x265 确认。
Windows
去官网下载 ffmpeg-release-full.7z,解压后把 bin 目录加到系统环境变量 PATH。记得下 full 版,不然缺库。我朋友下过 essentials 版,连 h264 都转不了。
安装完后验证:
ffmpeg -version
看到一堆配置选项(比如 --enable-libx264)就对了。
三、快速测试:一行命令转码
随便找个 mp4 文件,转成 h265 试试:
ffmpeg -i input.mp4 -c:v libx265 -preset medium -crf 28 output.mp4
如果跑通了,FFmpeg 基本可用。注意 preset 和 crf 是控制质量/速度的,后面会讲。
四、常用参数(我实际工作中用到的)
4.1 基础参数
参数 含义 例子
-i 输入文件 -i video.mp4
-y 覆盖输出文件不询问 写脚本时必加
-an 不要音频 只取视频流
-vn 不要视频 只取音频或静图
-t 时长 -t 30 只处理前30秒
-ss 起始时间点 -ss 00:01:00 从1分钟开始
-to 结束时间点 -ss 00:01 -to 00:02
4.2 视频编码参数
我常用这套组合拳:
-c:v libx264 # 用h264编码,兼容性好
-c:v libx265 # 用h265编码,文件小但编码慢
-preset faster # 可选: ultrafast, faster, fast, medium, slow, veryslow ... 越慢压缩率越高
-crf 23 # 质量,0-51,值越小质量越高,默认23,18左右视觉无损
-profile:v high # 高级profile,不写有时默认main
踩坑提醒:-preset veryfast 和 -preset slower 出来的文件大小能差一倍,但编码时间差十几倍。不一定越慢越好,我一般用 fast 或 medium。
4.3 音频编码
-c:a aac -b:a 128k # aac 码率128k
-c:a mp3 -b:a 192k
注意:如果原视频是多音轨(比如带两条评论音轨),想保留第一条:
-map 0:v:0 -map 0:a:0
五、实战:几个我常用的命令
- 压缩视频到指定大小(近似)
ffmpeg -i input.mp4 -b:v 1M -maxrate 1.5M -bufsize 2M -b:a 128k output.mp4
用 -b:v 指定视频平均码率,可以预估文件大小。但 crf 方式更智能,除非你严格需要 ≤100MB 才用这招。
- 去掉片头片尾 (30秒到1分45秒)
ffmpeg -i input.mp4 -ss 30 -to 105 -c copy output.mp4
-c copy 表示不重新编码,直接复制流,速度快到飞起。但注意切割点不精确(因为关键帧问题),如果要求精确到帧,不要用 copy,而是重新编码。
- 添加水印(图片)
ffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4
水印位置是左上角 (10,10)。想放右下角?计算视频宽高:overlay=W-w-10:H-h-10。踩坑:png 必须带透明通道,否则会挡住画面。
- 批量转码(bash 循环)
for f in *.avi; do
ffmpeg -i "$f" -c:v libx264 -c:a aac "${f%.avi}.mp4"
done
Windows 下用 for %f in (*.avi) do ffmpeg -i "%f" ...。注意文件名有空格要加双引号,我第一次忘加了,炸了一堆。
六、问题汇总(都是我真实遇到的)
- Unknown encoder 'libx264'
原因:编译时没开启 x264 支持。
解决:换完整版二进制,或者自己编译加 --enable-libx264。
检查方法:ffmpeg -encoders | grep x264
- 音视频不同步
常见场景:从网络流录制,或者用 -ss 加 -c copy 切割时。
原因:-ss 放在 -i 前面和后面行为不一样。
解法:
如果要用 -c copy 快速切割,把 -ss 放在 -i 后面:ffmpeg -i input -ss 30 -t 10 -c copy out.mp4 (但这样首帧可能不精确)
需要精确到帧,去掉 -c copy:ffmpeg -ss 30 -i input -t 10 -c:v libx264 out.mp4(慢但准)
- 转出来的视频播放器打不开,但 VLC 能开
原因:可能是 moov 原子不在文件头部。流媒体播放需要 faststart。
解决:加参数 -movflags +faststart:
ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4
- 处理速度太慢,CPU 吃满
FFmpeg 默认充分利用多核,但有些滤镜(比如 scale)是单线程的。如果想限制 CPU 占用,用 -threads 2 限制线程数。
另外 -preset ultrafast 会快很多,但文件体积飙升。
- “Buffer queue overflow, dropping frames”
原因:复杂滤镜链(比如同时缩放、加水印、调色)时,其中一个滤镜处理速度跟不上。
解决:在滤镜后面加 -max_muxing_queue_size 1024,或者简化滤镜链,分步处理。
- 从视频提取帧为图片,结果全是花屏
ffmpeg -i video.mov -vf "fps=1" out%d.png
踩坑:视频如果是非标准格式(比如某些相机拍的 H.264 编码 mov),用 -vf 之前最好先转成 yuv420p:
ffmpeg -i video.mov -pix_fmt yuv420p -vf "fps=1" out%d.png
- 合并多个视频,结果画面卡在第一个视频最后一帧
典型错误:用 concat 协议没加 -c copy,或者各视频的编码参数不一致(比如有的有 b 帧,有的没有)。
正确做法:先确保所有视频参数一致(分辨率、fps、编码格式),然后用:
ffmpeg -f concat -safe 0 -i mylist.txt -c copy merged.mp4
mylist.txt 内容:
file 'part1.mp4'
file 'part2.mp4'
七、一点小建议
每次调参数前,先用 -t 10 截一小段测试,别拿大文件硬扛。
保存常用命令为别名或脚本,比如 alias compress='ffmpeg -i "$1" -c:v libx265 -crf 24 "$1"_compressed.mp4'
FFmpeg 官方文档很全但不友好,遇到问题先搜错误信息 + “FFmpeg”,Stack Overflow 一般有答案。
最后,不要试图记住所有参数,记住 -i、-c copy、-ss、-to、-crf、-preset 这六七个就够了。其他的随用随查。
写完这篇博客,我发现我并不是「从入门到放弃」,而是「从入门到还债」——每次用一次就改一次脚本,加一个新的 -movflags。欢迎补充你遇到过的奇葩问题。