坐电脑前帮人排查FFmpeg编译问题,前前后后少说也有几十次了。每次群里有人发截图说“configure报错”“make失败了”,我扫一眼基本就能猜到缺哪个依赖。说真的,Ubuntu 20.04 编译安装 FFmpeg 这件事,难点不在命令有多复杂,而在于很多人不知道每个步骤到底在干嘛,一旦报错就抓瞎。这篇就把整个流程从头到尾拆开讲清楚,你照着操作,顺便把原理也搞明白,以后再遇到类似开源项目编译,思路都是通的。
废话不多说,直接进入正题。这篇内容适合刚接触Linux、第一次碰FFmpeg源码的初学者,也适合那种“项目需要自定义编解码器,被迫自己编译FFmpeg”的老哥参考。
1. 为什么源码编译而不是直接 apt install
1.1 发行版自带 FFmpeg 的局限
很多人的第一反应是:Ubuntu 不是有 apt 吗?sudo apt install ffmpeg一条命令不就搞定了?
确实能装,而且能用,但这里有几个很实际的问题。
第一,版本旧。Ubuntu 20.04 的软件源里默认是 FFmpeg 4.2.x,这是 2020 年左右发布的版本。放到现在,很多新编码器、新滤镜、新的封装格式支持都没有。比如你项目里想用 AV1 编码,或者想用新版 libvpx 的 VP9 性能优化,apt 装的老版本基本指望不上。第二,编解码器不全。FFmpeg 本身是“壳”,真正的编码能力很大程度依赖外部库,比如 libx264、libx265、libfdk-aac 这些。Ubuntu 出于许可证和发行政策的原因,官方源里的 FFmpeg 默认关掉了一批功能,尤其是--enable-nonfree这类选项在 apt 版本里是看不到的。你可以跑一下ffmpeg -buildconf看看系统里那个 FFmpeg 的编译配置,会看到大量--disable-xxx,这就是被裁剪过的证据。
第三,也是最容易被忽略的一点:如果你是做开发,想在自己写的程序里调用 FFmpeg 的库,那 apt 源里的libavcodec-dev、libavformat-dev版本同样偏老。第三方项目往往要求比这更新的接口,结果就是编译时头文件找不到符号,特别闹心。
所以结论很简单:只是偶尔用命令行转个码,apt 完全够;一旦涉及自定义编译选项、新版特性、或者要基于 FFmpeg 做二次开发,老老实实源码编译是绕不开的路。
1.2 源码编译到底在做什么
源码编译这事听起来高大上,其实本质就三步:configure检查环境、make编译、make install安装。
configure的作用是探测你的系统里有哪些工具链、哪些外部库,然后根据你传入的参数生成对应的 Makefile。如果你开了--enable-libx264,但它发现系统里没装 libx264 的开发头文件,就会直接报错退出。这一步很多人第一次跑不通过,基本都是缺依赖。make就是真正拿着 Makefile 去调用 gcc,把几万个源文件编译成可执行文件和动态库,耗时看机器性能,通常几分钟到十几分钟。make install则把编译好的二进制和库文件复制到指定目录,默认是/usr/local/bin和/usr/local/lib。
理解了这个流程,后面再遇到问题你就能自己定位了——报错在哪个阶段,就往哪个方向排查。
2. 编译前的依赖准备
2.1 基础工具链
开始之前,先把基础工具链装齐。这一步别偷懒,后面所有坑的 70% 都能靠这一条命令提前规避。
sudo apt update sudo apt install -y build-essential cmake git pkg-configbuild-essential包含 gcc、g++、make 等核心编译工具。pkg-config是专门用来查找库头文件和链接参数的,FFmpeg 的 configure 在检测外部库时主要就靠它。
这里有个特别容易踩的坑:汇编器。FFmpeg 里面大量使用汇编优化,x264、x265 这些库也离不开汇编器,所以系统里必须装了 nasm 或 yasm,版本还不能太老。Ubuntu 20.04 的源里两个都有,建议直接一起装上:
sudo apt install -y nasm yasm我见过不止一个人,明明 libx264-dev 装了,configure 还是报yasm not found,最后发现汇编器压根没装。这类问题一次装全,后面省心很多。
2.2 编解码库怎么选
FFmpeg 是一个框架,真正的编码和解码能力是通过外部库来扩展的。我在实际项目里最常用的是下面这批,你按需选择,不用全装。
# H.264/H.265 视频编码,最常用的两个 sudo apt install -y libx264-dev libx265-dev # VP8/VP9,WebM 生态常用 sudo apt install -y libvpx-dev # 音频编码 sudo apt install -y libmp3lame-dev libopus-dev libfdk-aac-dev # 字幕和滤镜相关 sudo apt install -y libass-dev libfreetype6-dev # ffplay 播放器需要 SDL2 sudo apt install -y libsdl2-dev # AV1 编码器,可选但体积比较大 sudo apt install -y libaom-dev每个库对应什么场景,我简单说一下,方便你自己判断要不要装:
- libx264:H.264 编码器的业界标准,几乎所有视频处理项目都要用,强烈建议装。
- libx265:H.265/HEVC,压缩率比 H.264 高,但编码速度慢。做视频存档、高压缩比转码场景才需要。
- libvpx:Google 的 VP8/VP9 编码器,Web 视频常用,浏览器兼容性好。
- libmp3lame、libopus:音频编码,MP3 和 Opus 格式,普通转音频必备。
- libfdk-aac:AAC 编码器,质量好,但它用的是非自由许可证,所以 configure 的时候必须额外加
--enable-nonfree,很多发行版源里默认不带这个。 - libaom:AV1 编码器,新一代标准,但是编码极其耗时,编译也慢。不是搞前沿编码研究的话,建议先跳过。
需要注意一点:Ubuntu 20.04 的某些版本默认没有启用 universe 源,libfdk-aac-dev在这个源里。如果上面装包时报“无法定位软件包”,先确认一下源:
sudo add-apt-repository universe sudo apt update3. 下载源码与配置参数
3.1 下载源码
源码获取主要有两种方式:下载压缩包,或者 git clone。
我推荐用 git clone 的方式,因为后续如果想更新版本、切换分支比较方便;而且很多第三方库(比如 x264)本身就是 git 仓库,习惯 git 工作流会更顺手。
cd ~ git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg cd ffmpeg如果你想用稳定版而不是 master,可以切到 release 分支的 tag。比如 4.4.2 在当时是非常稳的版本,很多生产环境都在用:
git checkout n4.4.2当然,下载压缩包也可以:
wget https://ffmpeg.org/releases/ffmpeg-4.4.2.tar.bz2 tar xjf ffmpeg-4.4.2.tar.bz2 cd ffmpeg-4.4.2这里有个实际经验:尽量用 release 版本而不是 master。master 虽然功能最新,但偶尔会有编译不过或者行为不稳定的情况,做项目讲究的是可复现,固定版本至少能保证同一条命令在别人机器上也能编译通过。
3.2 configure 参数逐个说明
configure 是整个编译过程中最关键的一步。参数决定了你最终得到的 FFmpeg 支持哪些功能。我直接给一份我实际项目里常用的配置:
./configure \ --prefix=/usr/local \ --enable-gpl \ --enable-nonfree \ --enable-libx264 \ --enable-libx265 \ --enable-libvpx \ --enable-libmp3lame \ --enable-libopus \ --enable-libfdk-aac \ --enable-libass \ --enable-libfreetype \ --enable-ffplay \ --enable-sdl2逐个解释一下:
--prefix=/usr/local:安装目录。默认其实也是/usr/local,但显式写出来有个好处:以后想卸载,删这个目录就行。如果你不想污染系统目录,也可以改成--prefix=/opt/ffmpeg,然后把/opt/ffmpeg/bin加进 PATH。--enable-gpl:开启 GPL 许可证支持。libx264、libx265 这些库都是 GPL 的,不开这个选项,configure 会明确拒绝启用这些库。--enable-nonfree:开了之后才能链接 libfdk-aac 这类非自由许可证库。代价是你的二进制不能公开发布,只能自己用。--enable-libx264等:显式启用对应的外部库。库装了但这里不开,等于白装。--enable-ffplay:编译出 ffplay 播放器,可以用来快速预览视频。不然默认只编译 ffmpeg 和 ffprobe。--enable-sdl2:ffplay 依赖 SDL2 窗口库,这行要跟上面配合。
跑完 configure 之后,最后几行会输出一个“Enabled”和“Disabled”的列表,建议养成习惯在这里扫一眼,确认你要的功能都在 Enabled 列表里,再去继续 make。这一步被很多人跳过,结果编译装完才发现 x264 没启用,又得回头重来。
3.3 make 编译与安装
configure 通过之后就是编译。命令很简单,但有几个细节值得说:
make -j$(nproc)$(nproc)是获取 CPU 逻辑核心数,-j指定并行任务数。比如 8 核的机器就是make -j8。如果你的机器内存比较小,比如 2GB,建议保守点,用make -j2或者make -j4,不然并行编译可能把内存吃满,直接卡死。
编译过程会有大量输出,看到ERROR字样不要慌,往上翻几屏找到第一条错误信息,那才是根因。如果 make 中途失败,修好问题之后重新跑make就好,它会接着编译,不需要从头开始。
编译完成之后安装:
sudo make install sudo ldconfigldconfig这行往往被人忽略,但它实际上很重要。FFmpeg 编译出来的动态库默认安装到/usr/local/lib,如果这个路径不在动态链接器的搜索范围内,运行时就会出现“找不到 libavcodec.so.58”之类的错误。Ubuntu 的/etc/ld.so.conf.d里通常会包含/usr/local/lib,但不同环境有差异,手动跑一下ldconfig是最稳妥的做法。
装完之后,如果你之前已经用 apt 装过 FFmpeg,bash 的 hash 缓存可能会让你输入ffmpeg时仍然调用旧版本。解决方法是:
hash -r which ffmpeg如果which ffmpeg显示的还是/usr/bin/ffmpeg,说明/usr/local/bin没在 PATH 前面,或者被 hash 缓存干扰了。正常 Ubuntu 系统里/usr/local/bin优先级高于/usr/bin,hash -r 之后应该会指向/usr/local/bin/ffmpeg。
4. 安装后验证与动态库问题
4.1 验证是否真正装好
安装完成别急着跑项目,先确认一下这次编译到底有没有生效。
ffmpeg -version正常输出会包含版本号、编译配置信息。版本号是ffmpeg version n4.4.2这种,代表你用的是编译的版本。然后看这一行:
ffmpeg -buildconf | grep x264能看到--enable-libx264才算真正把这功能打开了。同理可以检查libx265、libfdk-aac等。
再进一步,ffmpeg -encoders可以列出当前所有可用的编码器:
ffmpeg -encoders | grep x264 ffmpeg -encoders | grep fdk看到libx264和libfdk_aac就说明外部库已经链接进去了。到这一步,编译安装才算真正成功。
4.2 运行时报找不到 .so 文件的处理
我最常遇到的问题就是,编译安装完,敲ffmpeg -version直接报:
ffmpeg: error while loading shared libraries: libavcodec.so.58: cannot open shared object file: No such file or directory原因很简单:程序找到了,但运行时动态链接器不知道去哪儿找 FFmpeg 的库文件。解决方式有两种。
第一种,把/usr/local/lib加进 ldconfig 配置:
echo '/usr/local/lib' | sudo tee /etc/ld.so.conf.d/ffmpeg.conf sudo ldconfig第二种,临时设置环境变量:
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH第二种只对当前终端窗口生效,如果你想长期用,可以写进~/.bashrc。但我个人推荐第一种,一劳永逸,干净利落。
5. 常见错误速查与排障思路
5.1 典型报错对照表
我把这些年遇到过的高频报错整理成一张表,你对着查就行。
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
nasm not found或yasm not found | 汇编器未安装 | sudo apt install -y nasm yasm |
ERROR: libx264 not found | 未装 libx264-dev,或没开--enable-gpl | 装libx264-dev,确保 configure 加了--enable-gpl --enable-libx264 |
ERROR: libx265 not found | 未装 libx265-dev | sudo apt install -y libx265-dev |
ERROR: libfdk_aac not found | 未装 libfdk-aac-dev,或没开--enable-nonfree | 先装包,再确保 configure 加了--enable-nonfree |
C compiler test failed | 缺少 gcc/make 基础工具链 | sudo apt install -y build-essential |
ERROR: x265 not found using pkg-config | pkg-config 找不到库的 .pc 文件 | 检查是否安装libx265-dev,运行pkg-config --modversion x265验证 |
运行 ffmpeg 报.so文件找不到 | 动态链接器未找到/usr/local/lib | sudo ldconfig或配置/etc/ld.so.conf.d/ffmpeg.conf |
make中途卡死或无响应 | 并行任务太多,内存不足 | 按内存减小-j参数,比如make -j2 |
| configure 重新运行时出现奇怪报错 | 之前的 Makefile/config 缓存干扰 | 运行make distclean清理之后再重新 configure |
编译后ffmpeg仍显示旧版本 | bash hash 缓存或 PATH 顺序问题 | 执行hash -r,检查which ffmpeg |
5.2 排障的几个通用思路
除了具体报错,我有几个通用排障习惯,非常管用。
第一,configure 报错时,往上看前几条输出。FFmpeg 的 configure 检测外部库是逐个探测的,比如check_lib x264失败了,可能会连带影响后面所有跟 x264 有关的检测。你看到的最终错误往往是“连锁反应”,真正的根源在最早那一行。
第二,每次改完 configure 参数重新跑之前,先make distclean。这个命令会把之前生成的 Makefile 和编译中间文件清理干净。很多人改完参数直接重新 configure、make,时不时会冒出来一些莫名其妙的缓存问题。虽然多数情况不清理也能过,但养成了这个习惯,能省很多不必要的排查时间。
第三,确认外部库是否安装完整,不要只看包名。dev 包和运行包是两回事,比如你要编译链接 libx264,就得装libx264-dev,只装libx264-xxx运行库是不行的。判断方法很简单:dpkg -l | grep x264看有没有dev结尾的包。
6. 进阶体验:编译参数定制与卸载
6.1 如何卸载源码安装的 FFmpeg
源码编译不像 apt 那样有集中的包管理系统,卸载靠两条路。
如果你 configure 的时候指定了--prefix,并且目录是独立的,比如/usr/local/ffmpeg,那直接删目录就行:
sudo rm -rf /usr/local/ffmpeg如果你用的默认/usr/local,文件散落在里面的 bin、lib、include、share 下,那就稍微麻烦点。但在源码目录里还有 Makefile 的情况下,可以尝试:
sudo make uninstall这个命令会根据之前编译时的安装记录把文件删掉。但前提是你还没有make distclean,而且 configure 的配置和生产环境时的保持一致。如果源码目录已经删了、Makefile 也没了,就只能手动删除二进制和库。
所以当年第一次在服务器上编译的时候,我就养成了写一个小脚本记录安装文件的习惯:make install之前make -n install > install_files.txt,把将要安装的文件列表留存下来,后面真要卸载直接对照着删。
6.2 进一步定制编译
前面给的 configure 参数是通用型,实际项目里通常还会按需裁剪。给你列几个我觉得比较实用的场景。
需要把小体积的 FFmpeg 放到嵌入式设备,或者和其它程序一起打包分发时,可以考虑静态编译:
./configure --prefix=/opt/ffmpeg-static --enable-static --disable-shared ...这样编出来的 ffmpeg 二进制不依赖一堆.so文件,拷到别的机器直接能跑。缺点是体积大,而且 GPL 库静态链接之后,二进制的许可证问题更敏感,自己内部用没事,对外发布要小心。
开发调试时,建议保留 debug 符号。默认的编译配置已经带了-g,如果你想深入排查崩溃问题,可以在 configure 后面加:
--enable-debug=3 --disable-optimizations这样 gdb 能显示出比较完整的调用栈。生产环境可别这么干,性能会有明显下降。
如果确实对文档没需求,可以加一个--disable-doc,省一点编译时间。编解码器模块也可以裁剪,比如你只做 H.264 转 H.265,可以把其他编码器禁用掉,但裁剪的时候要谨慎,解封装、滤镜这些基础模块别乱删,宁可多留也不要少留,不然跑起来才发现缺模块更痛苦。
6.3 与 apt 版本混用的几个坑
最后聊聊源码版和 apt 版混用这件事。
我在自己的开发机上就吃过这个亏:系统里有 apt 的 FFmpeg,后来又源码编译装了一份新版,命令用/usr/local/bin的新版没问题,但某个 GUI 程序调用的却是 system 里 apt 的动态库。版本不匹配,接口一变,程序崩溃都找不出原因。
所以我的建议是:如果你决定源码编译 FFmpeg,并且要长期用于自己的项目,最好把 apt 版的 FFmpeg 显式卸载掉:
sudo apt remove ffmpeg libavcodec-dev libavformat-dev libavutil-dev当然,这么做之前确认一下系统里其它软件不依赖这些包。一旦出问题,再sudo apt install ffmpeg也随时能装回来,不算风险操作。
如果不想卸 apt 版,那就从始至终明确自己用的是哪一份。编译项目的时候,通过 pkg-config 指定用/usr/local/lib/pkgconfig下的.pc文件,避免链接到 apt 版本的头文件和库。
最后分享一个我的个人体会。很多人第一次编译 FFmpeg,光看到 configure 那一大堆参数就头大,觉得这东西太复杂。其实核心逻辑就一条:你想要的每个能力,都需要对应的外部库,而外部库装好了要明确告诉 FFmpeg“我装好了,你用吧”。把这个心智模型建立起来,别说 FFmpeg,以后再编译 OpenCV、GStreamer,甚至其它 C/C++ 开源项目,思路都是一样的。
编译 FFmpeg 这件事,我第一次花了将近一下午,全耗在缺依赖和报错排查上。现在熟了,一套标准流程下来十分钟不到。你踩过的坑越多,对它的理解就越深。这次照着走一遍,相信下次你就可以不看教程直接出门右转了。