本节摘要:FFmpeg 由六个核心库组成,分别负责管线的一段。本节逐一拆解 libavformat、libavcodec、libavfilter 等库的职责边界,并用「改封装不改编码」的实际例子说明模块化如何带来效率与灵活。
本节目标:阅读完本节,你应当能够:
-c copy 完成一次「只改容器」的秒级转换,并解释它为什么快先看一个反面教材:有人想给视频换容器格式,把 MP4 转成 MKV,写了一条「老老实实」的命令:
# 错误示范:MP4 转 MKV,连编解码都重新来了一遍 ffmpeg -i input.mp4 -vcodec libx264 -acodec aac output.mkv
这条命令能跑,但慢得离谱——10 分钟的视频可能要转十几分钟,画质还可能二次损伤。问题出在哪?它把整个管线从头到尾重跑了一遍:解码、重新编码、再封装。而 MP4 和 MKV 都是容器,里面的 H.264/AAC 数据完全可以原样搬过去。
正确姿势是只换容器,不碰编码数据:
# 正确示范:只改容器,复制编码数据 ffmpeg -i input.mp4 -c copy output.mkv
-c copy 告诉 FFmpeg「编码流原样拷贝」。这条命令几秒钟就能完成,因为整个 libavcodec(编解码)环节被绕过了,只有 libavformat(封装)在干活。这个例子把「模块化」的价值说透了:每个库只管自己的一段,你可以只动需要的部分。
FFmpeg 的核心由六个库组成,它们拼在一起覆盖了第 1 章的整条管线:
下面这张图把六个库放到管线上,一眼看清谁管哪段。

注意图中 libavutil 在最中间偏下的位置——它支撑全部库。管线主段由 format、codec、filter 三个库承担,scale 与 resample 是「换插头」的适配器。这套设计保证了「换容器不碰编解码」这类部分替换成为可能,也决定了命令行的 -f、-c、-vf 选项分别对应哪个库。
理解了库的边界,命令行就能「对症下药」:
-c copy,走 libavformat,快。-c:v libx264,走 libavcodec,慢但可控。-vf "scale=...:...",走 libavfilter,在解码后编码前插入。scale 滤镜完成。aresample 完成。实际项目里最常见的性能问题是「无谓的完整转码」——只改了个封面就整条管线重跑。判断依据很简单:数据形态变了吗? 只换容器,数据形态(压缩包)没变,-c copy;要改画面尺寸,原始帧必须变,只能解码重编码。
⚠️ 常见坑:
-c copy不是万能胶。如果源流的编码不被目标容器支持(比如把 HEVC 流塞进老旧的 AVI),拷贝会失败或产出坏文件。任何-c copy前,先确认目标容器接受源编码。
💡 关键直觉:先问「我要改的是数据形态,还是只换包装?」形态没变 → copy;形态变了 → 转码。这个判断能帮你避开 80% 的性能浪费。
六个库的职责不是纸上谈兵,每条命令的参数都对应着一个库的接口。-f 指定容器格式,走的是 libavformat;-c:v 指定视频编码器,走的是 libavcodec;-vf 写滤镜链,走的是 libavfilter。当你看到一条命令同时出现 -f mp4 -c:v libx264 -vf scale 时,其实是在同时指挥三个库协同。
反向排查也成立:报错信息里出现 Unknown format,问题在 libavformat 层;出现 Unknown encoder,问题在 libavcodec 层;出现滤镜相关的语法错误,问题在 libavfilter 层。学会把报错映射到库,排错速度会快很多——你不再对着整条命令发懵,而是直接锁定出问题的那个模块。
-f、-c、-vf 这些选项名直接指向对应的库,理解结构后参数不再是死记下一节看数据在这六个库之间到底以什么结构流动——AVPacket 与 AVFrame 的分工。