1. 为什么要在 Windows 上折腾 MinGW/MSYS2 编译 FFmpeg很多做音视频开发的同行第一次接触 FFmpeg 都是在 Windows 上直接下载官方预编译包解压、配环境变量、跑个ffmpeg -version感觉一切都很美好。但真正到了项目里问题就来了预编译包默认开启的编码器、封装格式、协议栈跟你实际需求对不上比如你需要某个特定版本的 x264、需要把 fdk-aac 静态链进去、需要裁掉一堆用不上的模块来减小体积这时候官方包就完全不够用了。更别提有些场景下你还得改 FFmpeg 源码里的某个滤镜参数或者打一个社区补丁那就必须自己动手编译。在 Windows 上编译 FFmpeg主流路线其实就那么几条一是用 MSVC vcpkg二是用 MinGW-w64 配合 MSYS2 环境三是直接在 WSL 里按 Linux 那套来。MSVC 那条路对 C99 支持一直不太友好FFmpeg 里大量用了 C99 特性编译时经常冒出一堆警告甚至报错虽然新版 MSVC 改善了不少但踩坑概率依然偏高。WSL 那条路本质上是 Linux 编译产物是 ELF 格式没法直接在原生 Windows 程序里调用。所以如果你要的是原生 Windows 可执行文件或 DLL同时又要完整的 GCC 工具链支持那 MSYS2 MinGW-w64 基本就是最稳的选择。MSYS2 本质上是一个在 Windows 上模拟 POSIX 环境的软件发行版它自带 pacman 包管理器可以很方便地装 gcc、make、pkg-config、nasm、yasm 这些编译 FFmpeg 必需的工具。MinGW-w64 则是真正的编译器目标平台它生成的是原生 Windows PE 格式的二进制。两者配合起来你在 MSYS2 的 shell 里敲./configure make出来的就是能在 Windows 上双击运行的 exe。这套流程我前前后后在不同机器上跑过不下几十次从最早的 32 位 mingw32 到现在的 mingw64坑基本都踩遍了下面把完整思路和实操细节摊开讲。这篇文章适合三类人看第一类是刚接触 FFmpeg 编译、想搞清楚整套流程的新手第二类是编译老失败、想找排查思路的中间开发者第三类是需要定制化构建、要静态链接第三方库的老手。我会从环境搭建一路讲到产物验证把每个环节的“为什么”都讲清楚而不是只丢几条命令让你抄。2. 环境搭建MSYS2 安装与工具链选型2.1 MSYS2 的安装与初始配置MSYS2 的安装包在官网直接下载即可安装路径强烈建议不要带空格和中文比如C:\msys64就是最经典的路径。带空格的路径会在 configure 阶段引发一堆诡异的引号转义问题我见过太多人卡在这里排查半天才发现是路径里有个空格。安装完成后第一次启动会看到三个不同的快捷方式MSYS2 MSYS、MSYS2 MINGW32、MSYS2 MINGW64。这里有个关键点很多人搞混——编译 64 位 FFmpeg 必须用 MSYS2 MINGW64 这个 shell不是 MSYS2 MSYS。前者环境变量里 PATH 优先指向/mingw64/bin后者指向/usr/bin用错了会导致编译器版本和目标平台全乱。启动 MINGW64 shell 后第一件事是更新包数据库和基础包pacman -Syu这条命令跑完可能会提示你关闭终端重新打开因为 msys2-runtime 自身更新了。重新打开后再跑一次pacman -Su确保全部更新完毕。这个步骤不能省老版本的 MSYS2 里 pacman 的密钥环可能过期直接装包会报签名错误。2.2 编译 FFmpeg 必需的工具链清单更新完之后装下面这一组包。我把它分成“必需”和“可选”两类必需的不装编译一定失败可选的按需装# 必需编译器与构建工具 pacman -S mingw-w64-x86_64-gcc pacman -S mingw-w64-x86_64-make pacman -S mingw-w64-x86_64-pkg-config pacman -S mingw-w64-x86_64-nasm pacman -S mingw-w64-x86_64-yasm # 可选常用第三方库 pacman -S mingw-w64-x86_64-x264 pacman -S mingw-w64-x86_64-x265 pacman -S mingw-w64-x86_64-fdk-aac pacman -S mingw-w64-x86_64-lame pacman -S mingw-w64-x86_64-opus pacman -S mingw-w64-x86_64-libvpx这里解释几个关键点。nasm 和 yasm是汇编器FFmpeg 里大量 SIMD 优化代码是用汇编写的没有它们 configure 会直接报错说找不到汇编器或者退化成纯 C 版本导致性能暴跌。pkg-config是用来探测第三方库的FFmpeg 的 configure 脚本靠它来定位 x264、fdk-aac 这些库的头文件和链接库路径。make在 MinGW 环境下装的是mingw32-make但 MSYS2 的包会同时提供make别名直接用make就行。注意不要混用 MSYS2 的/usr/bin下的工具和/mingw64/bin下的工具。比如你如果装了 MSYS2 版的 gcc包名是gcc而不是mingw-w64-x86_64-gcc那编译出来的东西依赖 msys-2.0.dll根本没法在普通 Windows 环境跑。判断方法很简单which gcc看输出路径是不是/mingw64/bin/gcc。2.3 验证工具链是否就位装完之后跑一遍验证确保每个工具都能正常输出版本gcc --version make --version pkg-config --version nasm --version yasm --version如果gcc --version输出的目标平台里带有x86_64-w64-mingw32字样说明工具链正确。我遇到过有人装完发现 gcc 指向的是 MSYS 版本结果编译出来的 ffmpeg.exe 双击报错缺 dll这就是工具链选错的典型症状。另外pkg-config --version如果报 command not found多半是 PATH 没刷新关掉终端重开一次即可。3. FFmpeg 源码获取与 configure 参数深度拆解3.1 源码下载与目录规划FFmpeg 源码建议从官方 git 仓库克隆这样方便后续切分支或者打补丁git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg cd ffmpeg如果网络条件不允许也可以下载 release 版本的 tar.xz 包解压。我个人习惯把源码放在/home/你的用户名/src/ffmpeg下编译产物单独放一个 build 目录这样源码目录保持干净重新编译时直接make distclean就行。目录规划这件事看着小但当你需要同时维护多个不同配置的构建时清晰的目录结构能省下大量时间。3.2 configure 参数逐项解析configure 是整个编译过程里最核心的一步参数写错了后面全白搭。下面给出一套我常用的、兼顾功能完整和体积可控的配置./configure \ --prefix/mingw64 \ --archx86_64 \ --target-osmingw32 \ --enable-gpl \ --enable-nonfree \ --enable-libx264 \ --enable-libx265 \ --enable-libfdk-aac \ --enable-libmp3lame \ --enable-libopus \ --enable-libvpx \ --enable-shared \ --disable-static \ --disable-debug \ --enable-small \ --extra-cflags-O2 -pipe \ --extra-ldflags-Wl,--nxcompat -Wl,--dynamicbase逐项说清楚每个参数背后的逻辑。--prefix/mingw64是安装路径装到 MSYS2 的 mingw64 目录下这样后续其他项目通过 pkg-config 就能直接找到。--target-osmingw32这个参数名字有迷惑性实际上 64 位 MinGW 也是用这个值FFmpeg 内部靠--arch来区分位数。--enable-gpl和--enable-nonfree是因为 x264、x265、fdk-aac 这些库的许可证分别是 GPL 和 nonfree不开这两个开关 configure 会拒绝链接它们。--enable-shared --disable-static生成动态库产物是 dll 加导入库。如果你要做的是单文件绿色版工具那就反过来用--enable-static --disable-shared但要注意静态链接时第三方库也必须是静态的否则运行时会缺 dll。--enable-small会牺牲一点性能换取更小的体积适合对体积敏感的场景如果追求极致性能就去掉它。--extra-cflags里的-O2是优化等级-pipe让编译过程用管道代替临时文件能稍微快一点。--extra-ldflags里的两个参数是 Windows 的安全特性--nxcompat启用数据执行保护兼容--dynamicbase启用 ASLR 地址空间随机化这两个建议保留。3.3 configure 输出解读与常见报错configure 跑完会输出一大段总结重点看这几行Enabled programs: ffmpeg ffplay ffprobe Enabled libraries: libavutil libavcodec libavformat ... External libraries: libx264 libx265 libfdk_aac ...如果某个你想要的库没出现在 External libraries 里说明它没被探测到。最常见的原因是 pkg-config 找不到对应的 .pc 文件这时候用pkg-config --cflags --libs x264手动验证一下如果报错就说明库没装好或者 PKG_CONFIG_PATH 不对。另一个常见报错是nasm/yasm not found回去确认汇编器装没装。还有C compiler test failed这种八成是 gcc 路径不对或者被杀毒软件拦截了编译临时文件把源码目录加进杀软白名单能解决。4. 编译、安装与产物验证全流程4.1 make 编译过程与并行加速configure 成功后直接make -j$(nproc)-j后面跟并行任务数nproc会自动读取 CPU 核心数。我实测在 8 核机器上全量编译 FFmpeg 大概 5 到 8 分钟单核跑要半小时以上并行加速效果非常明显。但要注意内存每个编译任务大概吃 300 到 500MB 内存如果你核心多但内存小比如 16 核配 8G 内存那-j16可能会因为内存不足被系统杀掉进程这时候降到-j8更稳。编译过程中如果报错中断先别急着改参数往上翻找到第一个 error。FFmpeg 的编译错误经常是连锁的第一个错误修好了后面可能就顺了。常见的错误类型有头文件找不到第三方库没装全、符号未定义链接顺序问题、汇编语法错误nasm 版本太老。我印象最深的一次是编译某个滤镜时提示undefined reference to av_xxx查了半天发现是之前 configure 时开了--disable-avutil之类的裁剪参数把基础库给关了这种就是参数自相矛盾的典型。4.2 安装与 pkg-config 注册编译通过后make install产物会装到/mingw64/bin、/mingw64/lib、/mingw64/include下。装完之后验证一下which ffmpeg ffmpeg -version如果ffmpeg -version能正常输出版本号和配置参数说明基本成功。这时候你可以把/mingw64/bin加到 Windows 的系统 PATH 里这样在 cmd 或 PowerShell 里也能直接调用。但要注意动态链接版本需要把依赖的 dll 一起带上用ldd ffmpeg.exe可以列出所有依赖把这些 dll 和 exe 放同一个目录就能绿色分发。4.3 产物功能验证清单光跑-version不够得实际验证编码器和封装格式是否可用# 查看支持的编码器 ffmpeg -encoders | grep -E x264|x265|fdk # 查看支持的封装格式 ffmpeg -formats | grep mp4 # 实际转码测试 ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4如果-encoders里能看到 libx264、libx265、libfdk_aac说明第三方库链接成功。实际转码测试能跑通说明运行时依赖也没问题。我建议每次编译完都跑一遍这个清单因为有时候 configure 显示启用了某个库但实际链接时因为版本不匹配导致运行时崩溃只有实际调用才能暴露。5. 踩坑实录与常见问题速查5.1 编译期典型问题排查表问题现象根本原因解决方法nasm/yasm not found汇编器未安装或不在 PATHpacman -S mingw-w64-x86_64-nasmC compiler test failedgcc 路径错误或被杀软拦截确认which gcc指向 mingw64加白名单undefined reference to xxx链接顺序或库缺失检查 configure 参数确认库已安装pkg-config not foundpkg-config 未安装pacman -S mingw-w64-x86_64-pkg-configconfigure 卡住不动杀软扫描临时文件关闭实时防护或加排除目录Permission denied目标目录无写权限用管理员权限运行或换 prefix5.2 运行期典型问题排查表问题现象根本原因解决方法双击 exe 报缺 dll动态链接依赖未打包用 ldd 列出依赖全部拷贝转码时崩溃第三方库版本不匹配统一用 pacman 安装的库版本编码速度极慢汇编优化未启用确认 nasm 已装且 configure 检测到输出文件无声音频编码器未启用检查-encoders里是否有对应编码器内存占用暴涨并行任务数过高降低 make 的 -j 参数5.3 几条用血泪换来的实操心得第一条永远保留一份 configure 成功的命令记录。我习惯把 configure 命令写成一个build.sh脚本放在源码目录这样下次重新编译直接跑脚本不用回忆参数。参数一多手敲很容易漏掉某个--enable-xxx导致编译出来的东西功能不全。第二条第三方库的版本要和 FFmpeg 版本匹配。FFmpeg 的 API 变动很频繁用太新的 x264 配太老的 FFmpeg或者反过来都可能编译失败。用 pacman 统一管理的好处就是版本相对协调但如果你手动编译第三方库就要特别注意版本对应关系。第三条静态链接时注意许可证传染性。GPL 库静态链接进你的程序你的程序也得按 GPL 发布这是法律问题不是技术问题。商业项目里如果不想开源就得避开 GPL 库用 LGPL 的替代方案或者动态链接。这个坑很多人编译时不在意等到产品要发布才被发现返工成本极高。第四条编译前先make distclean。如果你改过 configure 参数重新编译一定要先清理否则旧的 config.h 和 object 文件会干扰新配置导致一些莫名其妙的链接错误。这个习惯能帮你省下大量排查时间。6. 进阶裁剪体积与交叉编译思路6.1 按需裁剪减小产物体积默认编译出来的 FFmpeg 动辄几十 MB如果你只需要特定功能可以通过--disable-everything配合--enable-xxx来精确控制。比如只做 MP4 转码./configure \ --disable-everything \ --enable-decoderh264,aac \ --enable-encoderlibx264,aac \ --enable-demuxermov \ --enable-muxermp4 \ --enable-protocolfile \ --enable-libx264 \ --enable-gpl这样编出来的体积能压到几 MB。裁剪的核心逻辑是先全部关掉再按需打开。但要注意依赖关系比如开了 h264 解码器可能还需要对应的 parser 和 bitstream filterconfigure 一般会自动处理依赖但偶尔需要手动补。裁剪完一定要跑功能测试确认你要用的功能没被误关。6.2 交叉编译到其他架构的思路MSYS2 除了 x86_64 还有 i686 的包装mingw-w64-i686-gcc就能编译 32 位版本。流程和 64 位一样只是 shell 要换成 MSYS2 MINGW32prefix 改成/mingw32。如果你要编译 ARM 版本那就不是 MSYS2 的范畴了得用专门的交叉编译工具链思路类似但工具链配置更复杂。交叉编译的核心是--host和--target参数的正确设置以及确保交叉工具链的 sysroot 里有目标平台的库。我个人在实际操作中的体会是MSYS2 编译 FFmpeg 这套流程第一次跑通可能要花大半天但把 configure 脚本固化下来之后后续重新编译就是几分钟的事。真正耗时的不是敲命令而是理解每个参数背后的含义以及遇到报错时知道往哪个方向排查。把上面这些坑都踩过一遍之后你会发现这套工具链其实相当稳定值得花时间掌握。