
很多朋友第一次听说 FFmpeg脑子里冒出来的问题基本都一样这玩意儿到底是个工具还是门语言为什么网上教程东一个命令西一个命令看着就头疼作为一个天天跟视频打交道、被各种格式折磨过无数回的老兵我可以负责任地告诉你FFmpeg 就是整个多媒体世界的瑞士军刀几乎所有你见过的视频播放器、剪辑软件、直播平台底层都有它的影子。这篇入门教程我不打算丢给你几百条命令让你死记硬背而是从一个零基础的视角带你把这把军刀的刀柄、刀刃、用刀手法逐步摸清楚怎么下载安装、怎么选版本、怎么用最核心的命令完成转码压缩、怎么把视频推向流媒体服务器以及后面如果要搞 SDK 二次开发路该怎么走。看完这一篇你至少能独立处理掉 80% 的日常音视频需求踩过的坑我也会一并告诉你。1. FFmpeg 到底是什么零基础该怎么看待它1.1 一个命令行工具箱不是软件FFmpeg 本质上是一套开源的多媒体处理工具和底层库。它没有花哨的图形界面核心交互方式就是在命令行里敲指令。很多新手一看到命令行就发怵觉得这是程序员才会玩的东西。其实换个角度想它更像是一台自动料理机——你只需要把食材输入文件、加工方式命令参数、成品要求输出设置告诉它它就能哐哐给你做出来。命令行反而是它最强大的地方因为一旦你习惯用它效率比任何图形界面软件都高出一大截。另外要注意FFmpeg 从诞生之日起就是开源界的老前辈跨平台能力极强Windows、Linux、macOS 全覆盖。它既能处理 MP4、MOV、MKV、AVI、FLV 这些常见封装格式也能搞定 H.264、H.265、VP9、AV1 这类视频编码以及 AAC、MP3、Opus 这些音频编码。你要做格式转换、压缩瘦身、裁剪拼接、抽帧截图、提取音轨、混流推流它全都能干。1.2 三个核心成员ffmpeg、ffprobe、ffplay安装完 FFmpeg 之后你会在目录里看到三个可执行文件刚开始很容易混淆所以我一口气讲清楚它们的职责。ffmpeg主程序负责所有转码、编辑、处理工作绝大多数命令都是用它。ffprobe探测器用来查看视频文件的详细信息比如编码格式、分辨率、码率、帧率、时长、音频参数等就像给视频做一个体检。ffplay播放器直接把文件解码播放出来方便你快速预览处理结果。我平时排错最喜欢先用 ffprobe 把文件信息摸一遍再决定后续怎么处理。举个例子你拿到一个视频不知道它是什么编码、有没有音轨跑一句ffprobe input.mp4所有信息一目了然。这三个工具合起来就是一套完整的音视频处理组合拳。1.3 零基础该怎么学习 FFmpeg建议不要一开始就去背那些看着很长的命令。你先理解下面这句话FFmpeg 的命令本质上是在描述从哪读数据、用什么方式处理数据、往哪写数据这三件事。抓住了这个主干其他参数都是在这根主干上添枝加叶。我在带新人的时候通常会让他们先走通这几步会安装、会查版本、会用 ffprobe 看信息、会做一次最简单的转码。只要这几步走通了后面再复杂的操作无非是在这条主干上不断叠加需求而已。千万别上来就复制一长串命令出了问题根本不知道在改哪个参数。2. 环境准备下载、安装与版本选择2.1 官网到底能不能下载安装包很多人在搜索引擎里搜FFmpeg 下载然后兴冲冲跑到 ffmpeg.org结果发现官网居然没有现成的 Windows 安装包只有源码一下就懵了。这是新手最容易卡住的第一关FFmpeg 官网只提供源代码不直接提供编译好的二进制文件。所以你要下载可直接运行的那个ffmpeg.exe实际上是从第三方构建站点获取的。目前社区里比较主流、更新也比较及时的是 gyan.dev 和 BtbN 这两个构建源一般默默下载就行。macOS 用户直接用 HomebrewLinux 用户用系统自带的包管理器。我自己在 Windows 上一直用 gyan.dev 的 build干净、稳定、还有完整的 release notes实测没什么毛病。2.2 Windows 平台安装实操环境变量配置下载回来的 Windows 版本通常是一个压缩包解压后里面就是 bin 目录下的 ffmpeg.exe、ffprobe.exe、ffplay.exe 三个文件。首先把它们放到一个固定的目录比如D:\software\ffmpeg\bin。然后需要配置环境变量否则每次使用都得切换到该目录下才能执行命令。配置方法右键此电脑→属性→高级系统设置→环境变量在系统变量里找到 Path点编辑新增一条把D:\software\ffmpeg\bin加进去。配置完成后打开新的命令行窗口输入ffmpeg -version能打印出版本信息就算成功。这一步一定要重开终端窗口否则环境变量不会生效我经常看到有人在老窗口里折腾半天以为装失败了。2.3 macOS 和 Linux 的安装方式这两个平台装起来比 Windows 省心得多。macOS 上如果你装了 Homebrew一行命令就够了brew install ffmpeg官方仓库里的版本默认就带了 libx264、libx265 等常用编码器所以日常使用基本不用额外折腾。Debian/Ubuntu 系列 Linux 用sudo apt install ffmpegCentOS/RHEL 系列则用sudo yum install ffmpeg或者sudo dnf install ffmpeg具体看发行版。装完之后同样用ffmpeg -version验证。这里友情提醒一句仓库里预装的版本可能稍微旧一点但胜在稳定对入门来说完全够用。2.4 GPL 和 LGPL 的区别到底选哪个版本这个点炒得挺热但很多人没搞懂。简单说FFmpeg 本身是双许可证LGPL 版本更宽松不要求你开放自己的源代码GPL 版本则要求你在使用它的基础上你的代码也必须以 GPL 协议开源。问题来了像 libx264、libx265 这类最主流的编码器它们本身是 GPL 协议的。如果你编译时把这些编码器一起编进去整个 FFmpeg 就只能是 GPL 授权如果你只编那些允许 LGPL 的组件就不能用 libx264 这些编码器。所以选择起来就很简单如果只是自己做转码、压缩、推流这些内部工作不会把你的程序往外分发那就直接下载带 GPL 编码器比如 gyan.dev 的 full 版省事如果你要用 FFmpeg 的库做商业软件又想闭源发布那必须认真研究 LGPL 配置把非 LGPL 兼容的编码器全部剔除并且可能需要自己编译。想省心就直接上 GPL 版千万别后面跑命令时发现Unknown encoder libx264再回头折腾。3. 最常用的命令转码、压缩、裁剪与提取3.1 命令行的基本语法结构先记住这个框架ffmpeg [全局参数] -i 输入文件 [输入相关参数] [处理参数] 输出文件你看到的大部分命令都逃不出这个骨架。-i就是指定输入文件可以有多个输入文件输出文件写在最后。参数的位置有时候挺讲究比如放错位置可能导致读取参数的方式完全不同。新手阶段你不需要玩太多花样照着下面的经典例子照猫画虎跑通了再往里灵活套参数。3.2 视频转码与格式转换实操最基础的格式转换比如把视频从 MP4 转成 AVI 或者 MKVffmpeg -i input.mp4 output.avi这条命令不指定编码器FFmpeg 会自己对每种格式挑选它认为默认的编码器。但这里有个坑如果不做任何设置转换到 MKV视频流很可能还是原来容器里的编码只是换了个封装壳子。如果你想把 H.264 视频重编码为 H.265/HEVC换取更好的压缩率需要显式指定ffmpeg -i input.mp4 -c:v libx265 -c:a aac output_hevc.mp4-c:v指视频编码器-c:a指音频编码器。注意 libx265 编码速度明显慢于 libx264文件也未必永远更小得看码率设置和源视频画的复杂度。3.3 视频压缩与降低码率的参数详解压缩视频是日常高频需求核心思路就是限制视频码率或者提高质量参数 CRF。最简单粗暴的方式是直接限定平均码率ffmpeg -i input.mp4 -c:v libx264 -b:v 800k -maxrate 800k -bufsize 1600k -c:a aac -b:a 128k output_small.mp4-b:v是目标视频码率-maxrate限制峰值-bufsize是编码器的缓冲区大小通常设为两倍目标码率。音频码率同样用-b:a控制。这套参数适合把一段高清视频压成适合网络传输的体积。但说实话我更推荐CRFConstant Rate Factor模式固定质量让码率自己浮动画质保持更稳定ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output_crf.mp4CRF 值一般在 0~51 之间数字越小质量越高23 是 libx264 的默认值28 左右肉眼就会开始看到明显劣化。-preset是速度/压缩比权衡ultrafast最快但文件最大veryslow最慢但压缩率最好。日常推荐 medium 或 slow。3.4 截取片段、截图与音频提取截取片段时有一个非常关键的顺序问题把-ss放在-i前面是快速定位到关键帧位置再开始读取速度快但起始精度可能偏差几帧把-ss放在-i后面是解码到指定帧再截取精度高但速度慢。我实际处理时如果只是粗剪一般用ffmpeg -ss 00:01:00 -t 00:00:30 -i input.mp4 -c copy output.mp4。-t表示截取时长-c copy表示流拷贝不做重编码所以特别快。不过要注意-c copy在剪辑点不是关键帧时可能会出现开头画面卡顿或花帧要尽量避免在 GOP 中间硬切。截图的话直接指定要截取的时间点并输出一帧即可ffmpeg -ss 00:00:05 -i input.mp4 -frames:v 1 frame.jpg音频提取就更简单了ffmpeg -i input.mp4 -c:a mp3 output.mp3。如果只想拿原始音频流可以用-c:a copy完全不重编码秒导出。3.5 常用参数的速查与注意事项用表格把这几个高频参数列出来方便你随时翻参数作用常见取值示例-i指定输入文件-i input.mp4-c:v指定视频编码器libx264、libx265、copy-c:a指定音频编码器aac、mp3、copy-b:v视频目标码率800k、1M-b:a音频目标码率128k、192k-crf固定质量因子18~28-preset编码速度与压缩率权衡ultrafast、medium、slow-r输出帧率30、60-s输出分辨率1280x720、1920x1080-t处理时长00:00:30-ss起始时间点放在-i前/后效果不同新手最容易犯的错误是搞混-r和-fps其实 FFmpeg 中-r就是输出帧率。改分辨率用-s注意宽高比保持一致否则画面会被拉伸变形。处理高清视频时如果 CPU 占用率已经 100% 还嫌慢不要盲目开一堆任务先检查是不是选了太慢的 preset 或者分辨率太大。4. 实战案例用 FFmpeg 推流到 SRS 并优化延迟4.1 推流到 SRS 的场景与基础命令很多人做直播或看了网上的一些方案会把 FFmpeg 作为推流端把视频推向 SRSSimple Realtime Server这类开源流媒体服务器。什么场景下会用到比如你用 OBS 推流到自己的 SRS想转推其他协议或者你有一个视频文件想模拟一路直播流做测试再或者你需要多路输入源混流后再推出去。FFmpeg 都能干。最朴素的推流命令如下假设 SRS 的 RTMP 端口是 1935应用名 live流名是 testffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/test这里必须解释-re它的作用是按文件的原始时间戳以恒定速率读取输入文件模拟实时播放。如果不加这个参数FFmpeg 会以尽可能快的速度读完文件并推出去产生的就不是直播效果而是快进了。-f flv是指定输出封装格式为 FLV因为 RTMP 底层封装必须走 FLV。4.2 延迟从哪来关键帧、缓冲与 RTMP延迟问题的本质可以从三方面拆解编码器缓冲、GOP 结构、传输协议缓冲。RTMP 本身基于 TCPTCP 天然有累积确认机制在网络抖动时会自动缓冲数据这是延迟的重要来源之一。另外播放端通常要拿到一个关键帧关键帧、I帧也就是 GOP 的起点才能开始解码如果关键帧间隔太长加入直播时等待首屏的时间就越久。所以网上搜ffmpeg 推流到 srs 存在延迟能翻出一堆讨论其实绝大多数情况都能通过参数调优解决。核心思路就是缩短 GOP、降低编码器延迟模式、尽量少用会让封包累积的缓冲机制。4.3 延迟优化的具体参数设置经过我大量实测下面这套参数在推流到 SRS 时效果最稳定ffmpeg -re -i input.mp4 -c:v libx264 -preset ultrafast -tune zerolatency -g 50 -keyint_min 50 -sc_threshold 0 -b:v 1M -maxrate 1M -bufsize 2M -c:a aac -b:a 128k -f flv rtmp://127.0.0.1:1935/live/test拆开逐个讲-tune zerolatency主要是去掉 x264 编码器的延时缓冲让每一帧编码完尽量马上输出-g 50表示每 50 帧设一个关键帧如果视频是 25fps就相当于 2 秒一个关键帧-keyint_min 50保证最小间隔也是 50 帧-sc_threshold 0是关闭场景自动切换关键帧避免意外插入 I 帧打乱节奏。这些配合起来加上播放端也把缓冲尽量调小整体端到端延迟基本能在可接受范围内。还有一个小技巧如果你推送的是 H.264 视频流编码器参数尝试-x264-params nal-hrdcbr配合固定码率能减少因码率波动带来的缓冲抖动。我自己在局域网环境实测延迟大概能降到几百毫秒级别放在公网上主要瓶颈就变成网络质量了。4.4 验证延迟与实际效果调参之后怎么看效果我一般用 ffprobe 去拉流看实际到达的流信息是不是符合预期ffprobe rtmp://127.0.0.1:1935/live/test能正常输出视频流信息说明推流路径是通的。再用 ffplay 直接播放同一路流ffplay rtmp://127.0.0.1:1935/live/test在画面上放一个秒表或者用手机计时对比实际画面和真实时刻的偏差就是肉眼可见的延迟估算值。优化前后对比你会明显感到首屏更快了、画面卡顿少了。另外注意延迟并不只由 FFmpeg 推流端决定播放器的缓冲策略、SRS 服务器配置、网络中间设备都有很大影响。如果已经调了推流参数还是高延迟去服务端看看 chunk_size 等相关配置别只盯着推流端。5. 进阶之路FFmpeg SDK 与二次开发5.1 FFmpeg SDK 到底是什么如果你已经不满足于敲命令想在自己的程序里集成 FFmpeg 的能力那就要接触它的 SDK 部分。FFmpeg 除了一套命令行工具还提供了一堆底层库比如 libavformat 负责封装和解封装、libavcodec 负责编解码、libavfilter 负责滤镜处理、libavutil 提供辅助工具、libswscale 负责图像缩放与格式转换、libswresample 负责音频重采样。这些库加起来就是一套完整的媒体处理 SDK。你用 C 或者 C 调用它们就可以写出自己的剪辑软件、直播推流工具、音视频分析器。SDK 的下载其实就是你把 FFmpeg 的源码用特定工具链编译成静态库或者动态库然后在自己的工程里链接。网上说的ffmpeg sdk 下载一般指的就是引入编译产物或源码包。5.2 MSVC 环境下编译 libx265 的踩坑记录在 Windows 上用 MSVCVisual Studio 的 C/C 编译器编译 FFmpeg同时还要启用 libx265是我见过把很多人劝退的操作。这里我把大概步骤和坑摊开说一遍。首先你需要一个完整的 Visual Studio带 C 桌面开发组件然后下载 FFmpeg 源码。x265 的源码需要独立下载并先用 CMake 编译出静态库。CMake 的生成器要选 Visual Studio 对应版本Build 类型建议选 Release。x265 编完会产生 x265.lib 之类的东西务必记住它的输出路径。接下来编译 FFmpeg 时最痛苦的就是让configure找到 x265 库。你需要额外装一套环境来解析依赖关系常见方案是借助 MSYS2 或者手动把 pkg-config 环境变量配置好。然后 configure 时加上类似这样的参数./configure --toolchainmsvc --enable-gpl --enable-libx265 \ --extra-cflags-I/path/to/x265/include \ --extra-ldflags/LIBPATH:/path/to/x265/lib这里有个非常容易踩的坑x265 库如果用 MSVC 编译那么 FFmpeg 也必须用同一套 MSVC 工具链x265 如果用 MinGW 编译的两边链接时很容易出现 ABI 不兼容的报错。我建议全程统一用 MSVC 环境。还有一个坑是 x265 的 release 版本库名可能在libx265.lib和x265.lib之间变化你不妨在编译 FFmpeg 之前先给 x265 库写个最小测试程序链接一遍把库路径彻底验证好再继续往下走。5.3 C 封装 FFmpeg 的核心思路直接用纯 C API 写 FFmpeg 开发指针生命周期管理极其痛苦所以很多人在 C 里做一层封装。核心思路无非是用 RAII 管理 FFmpeg 的各种 Context 指针构造时分配并初始化析构时按正确顺序释放。举个例子一个最简单解码器类大概要管理这些对象AVFormatContext 负责打开媒体文件AVCodecContext 负责管理解码器配置AVPacket 和 AVFrame 负责承载压缩数据和解码后数据。释放顺序一定要先关闭解码器再关闭封装上下文否则可能崩溃。我封装时习惯写一个FFmpegInitializer单例统一在程序入口调用avformat_network_init()等初始化函数。更高级的封装思路是参考 FFmpeg 自带的doc/examples/decode_video.c这类示例先把官方示例读透再抽象出自己的解码器、编码器、转码管道类。不要一上来就照着框架抄容易封出一堆看不见的坑。5.4 从命令行到 SDK 的学习路线建议很多朋友问命令都没记熟能不能直接学 SDK我的建议是先掌握常见命令再转 SDK。因为命令行工具其实就是 SDK 的参照答案——你跑一条转码命令时背后发生的事就是 SDK 里avformat_open_input、avcodec_open2、avcodec_send_packet、avcodec_receive_frame这一套流程的封装。你把命令和参数搞清楚反过来看 API会容易理解得多。学 SDK 的路线我推荐先跑通官方的 decode 和 encode 示例再写一个最简单的avformat_open_input av_read_frame avcodec_send_packet/receive_frame读取视频帧的程序然后自己去实现一个转码流程。一旦这条链路打通你对 FFmpeg 的理解就完全不一样了。6. 常见问题与排查技巧实录6.1 命令找不到或提示无效如果在命令行输入ffmpeg提示不是内部或外部命令基本就是环境变量没配好或者你下载的压缩包还没解压、路径不对。排查时先确认 ffmpeg.exe 的实际路径然后在命令行手动切到那个目录执行一次ffmpeg -version能跑再去检查环境变量 Path 里的路径对不对。还有一种情况是下载了错误的架构版本比如 64 位系统装了 32 位构建可能在部分环境下也会奇怪地不工作。6.2 编码器找不到了怎么办输入ffmpeg -encoders可以列出当前 FFmpeg 支持的所有编码器。如果发现没有 libx264 或 libx265十有八九是下载了 LGPL 版本。解决方案就是换一个带 GPL 编码器的构建。Windows 下 gyan.dev 的 full 版就带这些Linux 下如果你是自己源码编译的configure 时确认加了--enable-gpl --enable-libx264 --enable-libx265等参数。6.3 音视频不同步音视频不同步通常有三个原因源文件本身不同步、参数设置问题、封装环节时间戳计算错误。先跑ffprobe看输入文件的音视频流时长和帧率是否正常。如果要做变速或者截取可以考虑给输出加上-vsync cfr或-fps_mode cfr强制输出恒定帧率。还有-c copy模式截取时如果改动容器但没处理时间戳也可能出现不同步尽量在转码模式下试试。6.4 推流卡顿或花屏推流时出现卡顿、花屏原因很多。先看推流日志里有没有丢帧记录再看带宽是不是不够码率设置是否合理。我之前就遇到过把-preset设成placebo导致编码速度跟不上实时推流速度于是疯狂丢帧的情况。换成veryfast或者ultrafast问题立刻消失。另外-g关键帧间隔太小也会导致花屏概率上升别一味追求低延迟就把 GOP 调到极小也要考虑编码效率。6.5 其他避坑速查表现象可能原因解决方法转码巨慢preset 太慢/CPU 太弱换faster/veryfast或降低分辨率输出文件巨大码率太高/CRF 值太小调大 CRF如 25~28或者限制-b:v画面被拉伸变形-s分辨率比例不对按原始宽高比设置或加上-aspect中文文件名/路径出错编码问题尽量用英文路径或用相对路径处理多个文件效率低没有用 batch 循环Linux/mac 用 shell 脚本Windows 用 for 循环这里单独提醒一句处理关键任务时千万别在源文件上直接覆盖输出。比如ffmpeg -i input.mp4 input.mp4这种命令可能会直接损坏文件。正确做法是输出到临时文件确认没问题再替换。7. 写在最后的一些实际操作体会玩 FFmpeg 这么久踩过最多的坑反而是太着急。每次拿到一个看似能用的命令没有先跑-version、没有用 ffprobe 查输入文件、没有在小片段上先测试就直接全量处理结果经常浪费大量时间。后来我养成一个习惯无论多简单的命令都先用-t 5截取前 5 秒处理一遍确认输出没问题再动整个文件。还有一个小经验阅读官方文档时别只看命令示例重点看参数的取值范围和默认值。很多莫名其妙的问题比如转出来画质太差、文件太大、推流延迟敏感其实多看几眼文档里对-crf、-preset、-tune这些参数的说明就能找到答案。如果你是从零开始的纯新手建议把这篇文章里涉及的每个命令都自己在电脑上跑一遍下载安装、转一次格式、压缩一次文件、截一张图、推一路流到本地 SRS。整个流程走完你就不再是零基础了。剩下的就是遇到具体需求时去围绕它查更多参数然后大胆试错。这本身也正是玩 FFmpeg 最有趣的体验。