
做音视频处理这几年我电脑里最离不开的工具反而是这个黑乎乎的终端程序——FFmpeg。不是剪辑软件不是播放器就这一个命令行工具替我扛下了绝大多数和视频转码、格式封装、流媒体推拉流、参数调优相关的活儿。身边不少朋友第一次碰FFmpeg都会卡在同一个地方这玩意儿到底怎么装装完之后命令行敲下去那一长串参数是什么意思为什么别人给的命令在我电脑上报错如果你也在这些问题上打转那这篇文章基本就是为你准备的。我会按照我自己从零开始的实际使用路径来写从安装配置讲起到常用的转码命令、格式转换、区域裁剪、响度调整、推流延迟排查一条一条拆开说尽量让你看完就能直接上手用。1. 安装和配置环境变量绕不开的三件事1.1 官网下载还是第三方编译版先说结论去官网找下载入口其实也够用。FFmpeg官网只在ffmpeg.org进入之后找到Download按钮它会跳转到各个平台的编译发布页。Windows用户通常会在两个地方二选一gyan.dev发布的版本以及BtbN在GitHub维护的构建版本。这两个都是社区公认的可靠来源区别在于gyan.dev的包默认启用了大量第三方库而BtbN的构建更贴近上游更新频率也高适合需要追新功能的人。我最初下载的时候特别纠结“完整版”和“精简版”。实际上这两个词在Windows构建里指的是“包含额外库的数量”完整版带了x264、x265、libvpx、opus、aac等一大堆编码器精简版只保留基础能力比如H.264和AAC。如果你只是单纯截图、转个格式精简版也能干活但只要你碰过视频压制、推流、录制这类操作还是直接上完整版省心不然用到一个编码器发现没编译进去又得换包折腾两次就烦了。macOS用户最省事的方案还是Homebrewbrew install ffmpeg这条命令会把常用的编码器全部带上没特殊需求就不用再折腾别的了。Linux这边分发行版Ubuntu或Debian用户执行sudo apt update sudo apt install ffmpegCentOS或Rocky系需要先启用EPEL源再执行yum install。CentOS默认源里那套ffmpeg版本老得能当古董功能缺失严重所以切记先配EPEL。1.2 环境变量配置的常见误解Windows解压完ffmpeg会拿到一个文件夹里面是bin目录这个bin目录里躺着ffmpeg.exe。很多人卡在“为什么我打开cmd输入ffmpeg提示不是内部或外部命令”其实就是环境变量没配好或者配完没生效。操作路径是这样的右键“此电脑”进“属性”选“高级系统设置”点“环境变量”在下方的“系统变量”里找到Path双击编辑新建一行填入你的bin目录的完整路径。保存之后关掉所有已打开的cmd窗口再重新打开输入ffmpeg -version测试。那个老掉牙的问题是我明明配好了还是提示找不到。大多数情况是Path变量有多行但新路径追加在最后而cmd还没来得及刷新还有些人图省事选的是用户变量而不是系统变量权限范围不一样也会导致命令识别异常。还有一点容易被忽略Windows下的ffmpeg.exe如果是从压缩包直接解压的路径里尽量不要带中文和空格。虽然现代版本已经不怎么挑路径了但“C:\Program Files\ffmpeg\bin”这种带空格的路径在某些批处理脚本拼接命令时容易出引号问题。我自己的习惯是放到“D:\Tools\ffmpeg\bin”干净利落后续写脚本也不用担心转义。1.3 安装后建议立刻验证的几件事配置完环境变量不要急着处理视频先跑三项检查。第一项版本和编译选项ffmpeg -version这会显示版本号、构建配置和启用的库列表。重点看有没有libx264、libx265、libmp3lame这些字样。第二项编码器列表ffmpeg -encoders这个列表很长输出会先显示V.....表示视频编码器A.....是音频编码器。如果你发现x264没在里面说明这个包没带H.264编码器后面压制视频会非常被动。第三项设备拾取能力ffmpeg -devicesWindows系统下这里会出现dshow和gdigrab一个是DirectShow音视频采集一个是屏幕录制这两个在你后续做直播推流、录屏时会用到。检查完这三项环境才算真正准备好。2. 高频转码命令背后的参数逻辑2.1 一条最基础的转码命令拆解很多人第一次用的命令很可能是这样的ffmpeg -i input.mkv output.mp4这条命令能跑通但它本质上没做多少优化FFmpeg会默认选择一个编码器用内置的默认参数去做转换压制速度和质量都不受控制。真正干活的时候我一般会把命令拆成几条关键信息输入文件、视频编码参数、音频编码参数、输出封装格式。拿一个最常见的场景举例把一个MKV转成适合网络传输的MP4ffmpeg -i input.mkv -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k output.mp4这里-c:v指定视频编码器为libx264-c:a指定音频编码器为AAC。AAC是目前MP4容器兼容性最好的音频编码128kbps的码率能满足大多数场景的听感。输出文件扩展名是mp4FFmpeg会自动选择对应的复用器这点很智能不用你手动指定格式。2.2 CRF、码率与preset的权衡编码参数里最值得花时间理解的是CRF和preset。CRF的全称是Constant Rate Factor恒定质量因子数值范围通常是0到51数值越低画质越好文件也越大。libx264常用的取值范围在18到2818接近无损观感23是默认值属于质量和体积比较平衡的一个点28开始画质损失就比较明显了。如果你处理的视频主要是放到手机上随便看看CRF 26到28能省不少空间如果做了后期还要再处理建议18到20起步。这里有一个反直觉的点CRF调整的是“质量”不是“码率”所以它的输出文件大小是不可预测的。真要做码率上的硬控制比如平台明文要求视频码率不能超过4000kbps那就得换成目标码率模式ffmpeg -i input.mkv -c:v libx264 -b:v 4000k -maxrate 4500k -bufsize 8000k -c:a aac -b:a 128k output.mp4-b:v设置目标码率-maxrate限制峰值-bufsize让编码器在控制峰值时有一定缓冲余地这样不容易出现瞬间码率爆表的情况。很多人压低码率后抱怨画质糊成一片原因多半是只设置了-b:v而没有设置-maxrate和-bufsize编码器为了控制平均码率在快速运动的帧上瞬间质量崩塌观感就会变得很难受。preset则是速度和压缩率的平衡杆。它对画质影响不大影响的主要是压缩效率。preset越慢编码器思考时间越久单位码率里能保留的细节越多文件体积越小。日常处理我常用medium或fast批量处理大量素材时会用veryfast给机器减负。两小时的原片从veryfast换到slow导出时间可能是两倍以上所以不要迷信慢速预设先评估自己的等待成本。2.3 硬件加速参数与libx265的取舍现代CPU和显卡都有专门的硬编单元FFmpeg提供了对应的接口。NVIDIA显卡用h264_nvenc或hevc_nvencIntel核显用h264_qsv或hevc_qsvAMD用h264_amf。硬件编码的优势是速度快实时性高推流和录屏场景基本是首选但缺点是同等码率下的画质尤其是低码率时和libx264相比有明显差距。如果你压制的是需要长期留存的视频还是走软件编码路线更稳妥。libx265的争议一直不小。同样画质下它对码率的利用确实更高效HEVC比H.264低个30%到40%码率很常见。但x265编码非常慢家用电脑处理1080p素材时速度预设用medium可能都压不到实时速度。我现在的原则是本地备份资源用x265网络传输、平台上传、临时剪辑素材统一用x264。很多人上来就把所有视频转成x265转完之后发现播放器不兼容、剪辑软件不识别最后又转回来白白浪费了时间。3. 几个高频实战场景直接打包拿走3.1 截取片段和免重编码切割处理长视频时最常遇到的第一个需求就是截取某一段。举个例子你想从input.mp4的第1分30秒开始截取30秒内容ffmpeg -ss 00:01:30 -t 30 -i input.mp4 -c copy segment.mp4这里-ss放在-i前面意思是先跳转到指定时间点再开始处理。FFmpeg在读取时会直接定位关键帧附近速度极快。关键是-c copy意思是视频和音频流都不重新编码直接把原始数据复制到新文件里所以几乎秒完成。但这里有个非常经典的坑-c copy模式下切割点会落到最近的关键帧上你如果精确到帧级别去卡时间点会发现开头多了一点或者少了一点。如果需要精确到毫秒级就得牺牲速度重新编码ffmpeg -ss 00:01:30 -t 30 -i input.mp4 -c:v libx264 -c:a aac segment.mp4另外一刀双段的操作也很实用比如把视频切成前后两半ffmpeg -i input.mp4 -t 00:10:00 -c copy part1.mp4 ffmpeg -i input.mp4 -ss 00:10:00 -c copy part2.mp4注意第二段命令里-ss放在输出位置前这样起点定位会很准。如果放在-i前面定位精度取决于关键帧间隔有时会多出几秒重复内容。3.2 调整响度避免音量忽大忽小视频响度问题是很多后期从业者的痛点。不同来源的视频音量标准千差万别有的安静得像蚊子叫有的开篇炸耳朵。FFmpeg有一个loudnorm滤镜专门做响度标准化参考的是EBU R128标准这也是目前主流平台采用的响度规范。我的习惯是先用一行命令分析当前响度ffmpeg -i input.mp4 -af loudnormprint_formatsummary -f null -这行命令不会生成文件只是把分析结果打印到屏幕上。重点看三个值Input Integrated综合响度、Input True Peak真实峰值、Input LRA响度范围。拿到这些值之后再执行标准化调整ffmpeg -i input.mp4 -af loudnormI-16:TP-1.5:LRA11 output.mp4这里I-16是目标综合响度-16 LUFS是多数网络视频平台的标准TP-1.5限制真实峰值不超过-1.5dBTP给后续的编码留出余量LRA11表示压缩响度范围让整段视频音量更平均。用这套参数处理过的视频体感上会比直接调音量平滑很多。不过要提醒一句loudnorm是动态处理它会根据整段音频的响度分布调整增益。如果你只是想让某一小段变大声而不是整体标准化更适合用volume滤镜配合表达式。我自己踩过的坑就是拿到一个广告片只改了片尾几十秒的音量用loudnorm一跑整段音乐底噪全起来了后来改回volume才解决。3.3 只截取画面中的部分区域从视频里“取一块区域”这个需求做监控视频分析、直播画面切片、去字幕水印的都会遇到。FFmpeg的crop滤镜可以精准完成。假设你有一个1920x1080的视频只想保留正中间一块720x720的画面ffmpeg -i input.mp4 -vf crop720:720:600:180 output.mp4crop参数的格式是crop宽:高:x:yx和y是裁剪区域左上角坐标。1920x1080画面中间720x720区域x坐标是(1920-720)/2600y坐标是(1080-720)/2180。实际使用中坐标计算往往要参考画面内容才能定。有一次我要从一段会议录屏里截取PPT区域视频左上角是摄像头画面右侧是聊天窗口中间那一小块PPT区域只有约800x500。用播放器暂停画面后放大凭像素数坐标反而容易出错我后来是用图像查看器打开视频单帧标注区域之后再代入crop参数。如果你处理的是一批固定布局的录屏坐标和尺寸确定一次后可以批量套用效率非常高。3.4 调整播放速度、静音和环绕声处理倍速处理在短视频二次创作里用得很多。保留音调不变的倍速播放要用atempo滤镜ffmpeg -i input.mp4 -vf setptsPTS/1.5 -af atempo1.5 output.mp4-setptsPTS/1.5让视频时间轴压缩到原来的三分之二atempo1.5让音频加速到1.5倍同时保持音调不变。注意atempo滤镜支持的倍速范围是0.5到2.0你要加到2.5倍速就得串联两次atempoffmpeg -i input.mp4 -vf setptsPTS/2.5 -af atempo1.25,atempo2.0 output.mp4静音处理稍微冷门但很实用。比如去掉某段视频的音频只保留画面可以这样ffmpeg -i input.mp4 -an output.mp4-an的意思是禁用音频流输出文件不再包含声音。如果只是想静音某个时间段可以用volume滤镜配合enable表达式ffmpeg -i input.mp4 -af volumeenablebetween(t,5,10):volume0 output.mp4这条命令把5到10秒之间的音量拉到了0。用它做片头片尾的静音非常方便不用剪辑软件里对音频轨道一顿操作。4. m3u8流媒体转换与下载别再走弯路了4.1 为什么m3u8转换会失败m3u8是HLS流媒体协议的索引文件现在大量在线视频都是基于HLS分发的。把m3u8转成mp4核心就是把成百上千个.ts分片拼成一个完整的MP4文件。最简单的命令长这样ffmpeg -i https://example.com/path/index.m3u8 -c copy output.mp4理论上很完美实际上踩坑率极高。最常见的失败原因是网络不稳定下载过程中某个分片读取超时FFmpeg直接报错退出。第二个原因是部分m3u8文件带有加密信息索引文件里会有EXT-X-KEY标签需要对应的密钥才能解密没有密钥文件转出来的视频是花的或者直接黑屏。第三个原因也是很多人没意识到的m3u8可能不是一个单一码率的索引而是一个主索引里面套了多个不同清晰度的子索引直接喂给FFmpeg它可能只取默认的那一路。4.2 加参数提高成功率我的建议是一旦涉及在线流媒体转换就把重试参数加上别用默认配置裸奔ffmpeg -i https://example.com/path/index.m3u8 -c copy -rw_timeout 10000000 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 10 output.mp4-rw_timeout单位是微秒10000000即10秒意思是单个分片超过10秒没读完就重试一次。-reconnect和-reconnect_streamed启用断线重连策略-reconnect_delay_max设置最大重连延迟间隔。这套参数组合对弱网环境非常有用我用它拉过超过两小时的会议录像中途网络抖动过几次FFmpeg自己就恢复了整段视频完整落盘。下载下来的ts分片如果混杂在临时目录里网络中断后残留了大量碎片文件这种情况可以考虑本地拼接。先批量下载所有分片再执行ffmpeg -i local/path/index.m3u8 -c copy output.mp4前提是你已经把整个目录结构和索引文件原样保留。这个方法在服务器上批量抓取视频时最稳不会因为单次网络抖动导致整个任务失败。4.3 本地TS文件批量转码的思路有时你会拿到一个文件夹里面全是没有索引的.ts分片文件名是数字序号。这种场景下可以先用文本工具生成一个分片列表文件for f in *.ts; do echo file $f list.txt; doneLinux和macOS可以直接跑这个shell命令Windows用户可以在PowerShell里用类似逻辑或者更简单手动创建一个list.txt一行一个文件名。然后执行ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4-f concat告诉FFmpeg按列表顺序拼接-safe 0允许列表里出现相对路径。为什么用拼接而不是直接对单独ts转码因为如果这段视频本来就是连续分片直接拼接不重新编码既没有质量损失速度也是秒级完成这才是正确做法。直接把单个ts文件挨个转mp4再合并不仅多损失一道画质还容易在时间轴上出现卡顿。5. 推流到SRS的延迟问题逐一排查5.1 延迟从哪个环节来最近很多人在讨论把FFmpeg推流到SRS服务器时出现延迟的问题。SRS是一款流行的开源流媒体服务器大量直播场景都在用。推流命令通常是这样的ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://your-server/live/stream-re参数控制读取速度让FFmpeg按照视频原始帧率去读文件不然它会以最快速度把所有帧推送出去很快就会推完。加上-re之后瓶颈就在编码和网络传输上了。延迟来源大致分三块编码缓冲带来的延迟、传输缓冲带来的延迟、播放器缓冲带来的延迟。编码侧tune zerolatency是H.264编码器专门为低延迟场景准备的模式它会禁用B帧因为B帧会引入解码端的重排等待。同时它会把编码器的缓冲队列拉到极短代价是码率控制没那么精细画面细节会有一点波动。直播场景选它牺牲点画质换延迟是值得的。传输侧SRS服务器默认会有一定的缓冲设置正常情况下延迟在1到3秒之间属于合理范围。如果你发现推上去延迟超过5秒甚至10秒就要检查是不是推流分片过大或者GOP间隔太长。直播场景里GOP关键帧间隔一般不建议超过2秒也就是- g 参数设为GOP大小通常配合帧率30来设置ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -g 60 -c:a aac -f flv rtmp://your-server/live/stream-g 60的意思是每60帧一个关键帧30fps情况下刚好2秒一个关键帧。GOP太长的直接后果是播放器在切换清晰度、跳转播放时要等待下一个关键帧才能出画面观感上就是“半天出不来人”。5.2 摄像头和桌面推流时的参数细化如果你不是推文件而是推摄像头或者桌面命令会略有不同。Windows摄像头走dshow设备ffmpeg -f dshow -i videoUSB Camera -f dshow -i audioMicrophone -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://your-server/live/stream桌面录制走gdigrabffmpeg -f gdigrab -framerate 30 -i desktop -f dshow -i audioMicrophone -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://your-server/live/stream桌面推流时动态画面多码率要给够不然快速移动的窗口区域会糊成一团。我的建议是至少给到3500kbps分辨率1080p时上不封顶到6000kbps。同时桌面录制推流建议开启-x264opts keyint60:min-keyint60:scenecut-1强制关键帧间隔严格一致这对播放器低延迟出画很有帮助。5.3 排查延迟问题的顺序遇到推流延迟异常不要急着改参数先按顺序排查。第一步看推流端日志有没有丢帧、卡编码、网络断连的信息输出。第二步在服务器端查看客户端连接状态和缓冲长度SRS控制台或API能看到每个流的缓冲情况。第三步从播放端观察首屏时间和卡顿频率。我自己遇到过一种很容易误判的情况推流端延迟看起来很小但播放端延迟很大。排查之后发现是播放器默认缓冲设了5秒跟FFmpeg和SRS完全没有关系。所以遇到延迟问题先确认是哪个环节的延迟再动手调参。另外顺便一提WebRTC方案在低延迟这块天然比RTMP有优势SRS 5.0之后的版本已经支持WebRTC播放如果你的业务场景对延迟要求特别苛刻可以考虑切协议而不是死磕RTMP参数。6. 把命令行用得更舒服的几个习惯6.1 给高频命令起个别名命令行工具用得久了你会发现翻来覆去就用那么几条命令。这时候就应该给它们起别名。Linux和macOS在shell配置文件里加alias vcompressffmpeg -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k之后只需要敲vcompress -i input.mkv output.mp4Windows的PowerShell里可以用函数实现类似效果function cvid { ffmpeg -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k args }别名和函数的好处不只是省几个字符更重要的是避免你每次手敲参数时打错。我吃过一次亏某次批量压缩手敲参数时把-crf 23敲成了-crf 3结果所有视频按近乎无损的码率输出两小时的素材压出来的文件比原片还大白白浪费了一晚上时间。从那以后涉及编码核心参数的命令我基本都走别名或预设脚本。6.2 用日志级别过滤烦人的输出FFmpeg默认的输出信息非常冗长处理长视频时不断刷进度条不说还容易把真正有用的警告信息淹没。我平时会默认加一个-loglevel参数ffmpeg -loglevel warning -i input.mp4 ...-loglevel warning的意思是只输出警告和错误正常的进度信息全部省略。排查问题需要看详细执行过程时再改成info或debug。批量任务加warning级别日志文件小排查的时候也不用来回翻屏幕找关键信息。6.3 用-filter_complex处理复杂链路前面讲的滤镜都是单个滤镜直接作用但实际项目里经常出现多个操作叠加的场景。比如既要裁剪画面又要加响度标准化还要旋转画面。逐个串联滤镜效率太低应该用-filter_complex一次搞定ffmpeg -i input.mp4 -filter_complex [0:v]crop720:720:600:180,rotatePI/6[vout];[0:a]loudnormI-16:TP-1.5:LRA11[aout] -map [vout] -map [aout] output.mp4这里-filter_complex内部把视频滤镜链和音频滤镜链分别处理通过[vout]和[aout]标签作为中间变量最后用-map映射到输出文件。刚开始接触会觉得标签语法绕但这是FFmpeg里最值得花时间学习的东西。熟练之后复杂的转场、画中画、字幕叠加、多路输入合成全部可以通过filter_complex完成不再需要依赖笨重的图形化工具。6.4 不要忽视ffmpeg自带的帮助文档很多人在命令行工具上遇到问题第一反应是搜索引擎但如果参数拼写都拿不准搜索引擎只会让你更混乱。FFmpeg自带两套查询工具一套是-help参数可以查看具体某个滤镜的用法另一套是ffplay可以对视频做快速预览确认滤镜效果是否正确。调试滤镜参数时我的习惯是先截取一段5秒的素材用ffplay直接预览效果确认没问题再跑全片。这比反复用ffmpeg导出测试文件再打开播放器看效率高得多。预览命令大概长这样ffplay -i input.mp4 -vf crop720:720:600:180画面会直接弹出来实时展示裁剪效果。参数不合适改一下再执行前后也就是几秒的事。写在最后翻来覆去写了这么多说到底FFmpeg就是一个参数极其丰富的命令行工具它不像图形软件那样给你一个按钮而是把所有控制权都交给你。这几年用下来我对它最大的体会是不要指望一次记住所有参数而是要把常用命令沉淀成自己的脚本和别名让工具去适应你的工作流而不是每次都从零开始敲一遍。搜到这篇文章的读者多半也是被FFmpeg的安装、转码、推流或者m3u8转换问题绊住过。挑一个你手头最急的需求照着文中的命令跑一次再根据实际情况微调参数遇到不理解的参数先去看-help文档多半能找到答案。命令行这个东西真实跑通一次比看十篇文章都管用。