用MinGW-w64从源码编译FFmpeg DLL:32位与64位双架构完整指南

发布时间:2026/10/19 10:45:43
用MinGW-w64从源码编译FFmpeg DLL:32位与64位双架构完整指南 在 Windows 上接 FFmpeg 的 DLL看起来是个再普通不过的“下载个 zip 解压引用”流程但真到项目要交付的时候你大概率会卡在位数、ABI、链接库格式这三座大山上。这篇文章整理的是我用 MinGW-w64 从源码把 FFmpeg 编出 32 位和 64 位两套 DLL 的完整过程包括环境搭建、configure 参数拆解、常见坑和发布经验给需要在 Windows 下自建 FFmpeg 库的开发者做个参考。1. 为什么放着现成的 FFmpeg 不用非要自己用 MinGW 编1.1 预编译库的“方便”与“不方便”在很多项目的 README 里FFmpeg 集成方式都写着“去官网下载预编译包”。下载解压后确实能拿到 avcodec.dll、avformat.dll 之类的文件但真正用起来的时候你会发现预编译包的槽点比想象中多。最典型的是位数不齐全。不少预编译分发只维护 64 位版本32 位要么没有要么停在老版本而有些产品需要兼容旧环境或者需要以 32 位进程方式加载 DLL这时候只能自己动手。其次预编译包背后的编译配置很难确认开没开 GPL 库、用了什么线程模型、裁剪了哪些 component你在使用第三方发布包的时候都是被动的。还有版本对齐问题你需要某次 FFmpeg 更新中的 bugfix但发布者不跟进整个项目就得被迫留在旧版本上。更麻烦的是一些发行包把 DLL 扔进系统目录或者连导入库格式都带得不明不白。等你想做一次干净的部署根本分不清哪些 dll 是 FFmpeg 自己的哪些是依赖来的。自己编译一次这些问题基本都能清零。1.2 MinGW-w64 生成的 DLL 到底有什么特点MinGW-w64 是 Windows 平台上比较通用的 GCC 工具链对 FFmpeg 这种“configure make 一条路走到黑”的开源项目来说适配性相当好。FFmpeg 源码里对 mingw 目标的支持声明也一直维护得很及时只要工具链版本不是太老基本能做到一次通过。用 MinGW-w64 编出来的 DLL 是 Windows 原生 PE/COFF 格式可以被任何遵守 DLL 加载规范的进程使用。FFmpeg 对外 API 本质是 C 接口导出表规范这使得跨语言的调用比如 C#、Node 的 native binding也可以基于这组 DLL 来做。不过需要注意MinGW 构建默认生成的是 GNU 风格的导入库.dll.aVisual Studio / MSVC 的 linker 并不能直接消费这种文件这点我在后面专门说。1.3 同时需要 x86 和 x64 DLL 的场景现在不少交付场景里32 位和 64 位库必须一起提供主程序是 64 位进程追求更好的内存和性能需要 x64 DLL。老设备或某些受限环境系统本身是 32 位或者运行着 32 位版本的运行时只能加载 x86 DLL。有些进程本身就固定以 32 位方式运行比如常见的脚本扩展、浏览器插件进程它们调 FFmpeg 时只能配对 32 位版本。所以与其等发布方慢慢补版本不如自己把两套构建流程吃透。MinGW-w64 里两套工具链天然区分前缀非常契合这个需求。2. 编译环境的搭建与双架构编译器验证2.1 用 MSYS2 一次配好两套 MinGW-w64 工具链推荐直接用 MSYS2 作为编译环境原因很现实它自带包管理能一次性把 GNU make、pkg-config、nasm 等构建 FFmpeg 需要的工具全部装好不需要去各个官网拼凑环境。而且 MSYS2 把“64 位环境”和“32 位环境”分开隔离这对双架构编译来说是很舒服的设计。安装 MSYS2 后按下面的步骤操作# 更新核心包 pacman -Syu # 基础工具git 用来拉源码或者你用 release 包就不需要这一步 pacman -S --needed base-devel git然后在“MinGW64”环境开始菜单里选对应的 Shell安装 64 位工具链pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-nasm mingw-w64-x86_64-pkgconf再进入“MinGW32”环境安装 32 位工具链pacman -S mingw-w64-i686-toolchain mingw-w64-i686-nasm mingw-w64-i686-pkgconfMSYS2 的这套逻辑很好记包名里有x86_64的是给 64 位目标用的有i686的是给 32 位目标用的。两个环境彼此独立PATH 不互相污染这在后面同时编两套库时非常重要。2.2 验证两套编译器能否正常工作编译 FFmpeg 前强烈建议先花两分钟验证工具链。configure 报错有一半以上都来自“工具链没配好或者路径混了”这类低级问题。在 MinGW64 环境里执行x86_64-w64-mingw32-gcc --version echo int main(){return 0;} /tmp/t.c x86_64-w64-mingw32-gcc /tmp/t.c -o /tmp/t64.exe objdump -f /tmp/t64.exe | grep architecture同理在 MinGW32 环境里执行i686-w64-mingw32-gcc --version i686-w64-mingw32-gcc /tmp/t.c -o /tmp/t32.exe objdump -f /tmp/t32.exe | grep architecture64 位环境下输出的 architecture 应当是x86-6432 位环境下则看到i386。这里确认清楚后面就不会对着一个编出来却不知道是啥架构的 DLL 发呆。2.3 交叉前缀和 PATH 混乱的坑很多人第一次看到--cross-prefixx86_64-w64-mingw32-会觉得奇怪明明就在 Windows 上编译为什么还叫“交叉”其实 FFmpeg 的 configure 是从“目标系统描述”出发的它只关心目标环境是mingw32再配合前缀来调用编译器。指定--cross-prefixx86_64-w64-mingw32-后configure 会自动拼出x86_64-w64-mingw32-gcc、x86_64-w64-mingw32-ar等命令来找工具。实际开发中 PATH 混乱也容易出问题。如果你机器上装过其他带了 GCC 的开发工具比如某些老式 IDE 自带编译器MSYS2 的 configure 在检测时可能选中错误版本。安全做法是在对应的 MinGW64 / MinGW32 Shell 里输入which gcc确认指向的是 MSYS2 里mingw64/bin或mingw32/bin下的编译器而不是别处的。3. configure 核心参数与 64 位 DLL 的完整编译流程3.1 源码获取与 configure 逐项拆解源码推荐下载正式 release 包而不是随时变动的 master 分支。给项目交付用稳定版本是基本素养出问题也好回溯。假设你下载了 FFmpeg 7.1 的源码包解压到C:/ffbuild/ffmpeg-7.1下面开始构建。为每个架构单独建一个 build 目录这是避免编译残留互相干扰的关键习惯mkdir -p /c/ffbuild/build64 cd /c/ffbuild/build64 ../ffmpeg-7.1/configure \ --cross-prefixx86_64-w64-mingw32- \ --target-osmingw32 \ --archx86_64 \ --enable-shared \ --disable-static \ --enable-w32threads \ --disable-doc \ --disable-debug \ --enable-small \ --enable-pic \ --disable-programs \ --prefix/c/ffbuild/install64逐个说下这些参数在干什么--cross-prefixx86_64-w64-mingw32-告诉 configure 用它调用 GCC 工具链。MSYS2 里装了对应 package 后这个前缀正好能匹配到x86_64-w64-mingw32-gcc。--target-osmingw32目标系统是 Windows 的 MinGW 环境。注意这个单词里的“32”是历史遗留它不代表目标是 32 位编译 64 位库时同样写它。--archx86_64目标 CPU 架构这个才是真正控制位数的参数。64 位写x86_6432 位写x86。--enable-shared --disable-static明确只要 DLL不产静态库.a。这个搭配很重要FFmpeg 默认可能同时生成静态库体积大且没意义。--enable-w32threads使用 Windows 原生线程接口。FFmpeg 在 Windows 上可以用 win32 线程或 pthread 适配层原生接口更直接少一层封装。--enable-pic生成位置无关代码。虽然 DLL 本身加载时就要重定位但打开 PIC 对后续把对象文件用在其他场景更安全。--enable-small --disable-debug压缩体积。发布版足够了调试用的符号一般也用不上。--disable-doc跳过文档生成剩下不少构建时间。--disable-programs不生成 ffmpeg.exe、ffprobe.exe 这些命令行工具。如果你后面想拿命令行验证功能就不要加这一条只是做库的话建议跳过。如果你是在 Linux 上做 Windows 交叉编译还需要额外加--enable-cross-compileMSYS2 这种同系统不同架构的情况不用。3.2 make 编译与产物验证configure 顺利通过后直接开始啃编译时间make -j8 make install-j后面的数字根据 CPU 逻辑核心数调整初次编译大约几分钟到十几分钟不等取决于机器配置和裁剪范围。编译完成后查看产物find /c/ffbuild/install64 -name *.dll以 FFmpeg 7.1 为例你会看到类似这样的 DLLavcodec-61.dll avformat-61.dll avutil-59.dll avdevice-61.dll avfilter-11.dll swscale-8.dll swresample-5.dll文件名中带主版本号是 FFmpeg 进入 5.x 之后的常规行为主版本号还代表了 ABI 兼容边界升级大版本时需要注意接口变化。DLL 旁边还会有对应的libavcodec.dll.a、libavformat.dll.a这类导入库文件这是给 MinGW/GCC 链接时用的后面接进自己程序时全靠它们。再确认一下 PE 架构防止出现“以为编了 64 位结果实际是 32 位”的乌龙objdump -f /c/ffbuild/install64/bin/avcodec-61.dll | grep architecture输出应为x86-64。确认无误后64 位这套就算达标了。4. 32 位 DLL 编译切换 i686 工具链再走一遍4.1 32 位 configure 与 make 的操作差异32 位流程和 64 位结构完全一样区别只在两个参数交叉前缀和架构。直接在 MinGW32 环境里新建一个 build 目录mkdir -p /c/ffbuild/build32 cd /c/ffbuild/build32 ../ffmpeg-7.1/configure \ --cross-prefixi686-w64-mingw32- \ --target-osmingw32 \ --archx86 \ --enable-shared \ --disable-static \ --enable-w32threads \ --disable-doc \ --disable-debug \ --enable-small \ --enable-pic \ --disable-programs \ --prefix/c/ffbuild/install32这里--archx86指的目标是 32 位 x86i686-w64-mingw32-前缀则让 configure 去调用 32 位的编译器、汇编器和归档器。然后同样执行make -j8 make install完成后检查 install32 下的 DLL架构应为i386。有几个细节值得强调。第一32 位构建尽量放在 MinGW32 Shell 里做不要强行在 MinGW64 环境去配 32 位交叉编译虽然理论上也能配但 PATH、pkg-config 和 nasm 的版本会更容易出岔子。第二MSYS2 中 32 位工具链的 nasm 也要选mingw-w64-i686-nasm平台不对的汇编器在编译内联汇编时会产生大量诡异报错。4.2 32 位与 64 位 DLL 共存时的文件组织32 位和 64 位编译出来的 DLL 文件名是一样的都是avcodec-61.dll这种格式。如果你把两套库解压到同一个目录它们会直接同名冲突而且加载器根本区分不了谁是谁。我的项目里通常按这样的目录结构管理dist/ x64/ avcodec-61.dll avformat-61.dll avutil-59.dll ... include/ // 头文件 lib/ // .dll.a 导入库和 pkgconfig x86/ avcodec-61.dll avformat-61.dll avutil-59.dll ... include/ lib/强烈建议不要用“同一个目录放 32/64 DLL靠 PATH 顺序暂时区分”的方式。Windows 进程加载 DLL 时会优先搜索程序所在目录但 PATH 搜索顺序并不总是可控。一旦 64 位程序在 PATH 里先找到了 32 位版本就会报“应用程序无法正常启动 0xc000007b”。分开目录最安全。4.3 32 位构建中依赖库也要配对如果 configure 里启用了外部库比如 libx264、libvpx、libmp3lame那么这些库也要分别编译出 32 位和 64 位版本并在 configure 时用对应的 include/lib 路径。可以用 pkg-config 来统一管理这些依赖路径。每个架构的 pkgconfig 目录要分开比如export PKG_CONFIG_PATH/c/ffbuild/install64/lib/pkgconfig # 编64位 export PKG_CONFIG_PATH/c/ffbuild/install32/lib/pkgconfig # 编32位混用 pkg-config 路径是双架构编译翻车的高发区。你明明编的是 64 位库结果 pkg-config 指向的是 32 位的依赖库链接阶段会出现一堆“file format not recognized”之类的错误。5. 把 DLL 接进自己的程序链接、运行时依赖与发布清单5.1 MinGW/GCC 消费方如何链接 FFmpeg DLL自己编库的目的终究是给程序用。如果你的主程序是用 MinGW/GCC 体系编译的链接非常简单install 目录里的libavformat.dll.a等导入库会被 gcc 自动识别。示例命令64 位主程序x86_64-w64-mingw32-gcc -o player.exe main.c \ -I/ffbuild/install64/include \ -L/ffbuild/install64/lib \ -lavformat -lavcodec -lavutil -lswresample -lswscale-lavformat会让链接器去找libavformat.dll.a这个文件里记录了 DLL 的导入表和必要符号地址引用。生成的可执行文件拿到目标机器上运行时需要 DLL 和主程序在同目录或者能被系统搜索到。如果你习惯用 pkg-config 管理编译参数也可以这样export PKG_CONFIG_PATH/c/ffbuild/install64/lib/pkgconfig x86_64-w64-mingw32-gcc main.c $(pkg-config --cflags --libs libavformat libavcodec libavutil)这套方式在写 CMake 或 Makefile 时更省心。5.2 运行时 DLL 依赖完整清单很多人以为把 FFmpeg 的 av*.dll 拷贝过去就完事了结果在客户机器上跑起来还是缺东西。原因在于 MinGW 工具链编译出来的 DLL 还依赖两个运行时库libgcc_s_seh-1.dll64 位和libwinpthread-1.dll。32 位版本则可能是libgcc_s_dw2-1.dll或libgcc_s_sjlj-1.dll这类不常见的名字具体看工具链的异常模型。发布时把这些运行时 DLL 一并拷贝到 bin 目录。可以从工具链目录直接复制find /mingw64/bin -maxdepth 1 -name libgcc* -o -name libwinpthread* | xargs -I{} cp {} /c/ffbuild/install64/bin/对一个典型的 FFmpeg 转码程序来说运行时最少需要这些东西文件来源avcodec-61.dllFFmpegavformat-61.dllFFmpegavutil-59.dllFFmpegswscale-8.dllFFmpegswresample-5.dllFFmpegavfilter-11.dllFFmpeg按需libgcc_s_seh-1.dllMinGW 运行时libwinpthread-1.dllMinGW 线程库实际上 Windows 加载器在程序启动阶段就会尝试解析所有导入表涉及的 DLL而不是等到你调用某个转码函数才加载。所以哪怕你只用到 avformat只要导入表里有 avcodec 的引用相关 DLL 仍然必须都在。5.3 MSVC 程序调用 MinGW DLL 的兼容边界如果你的主程序是用 Visual Studio 编译的那么情况会稍微啰嗦一些。FFmpeg 的 API 是 C 接口MSVC 编译器本身可以链接调用外部 DLL 的导出函数但 MSVC 的 linker 不识别 GCC 风格的.dll.a导入库。直接把libavformat.dll.a丢给 Visual Studio通常会得到“LNK1104 无法打开文件”或者“unrecognized file”的报错。可选方案有三个运行时动态加载用LoadLibrary/GetProcAddress手动获取函数指针。只依赖avformat-61.dll本身绕开导入库格式问题。转换导入库用dlltool或相关工具生成 MSVC 兼容的.lib文件操作繁琐但可行。直接用 MSVC 工具链重新编译 FFmpeg这是“相同 ABI 体系”下的最终方案缺点是前期编译配置成本又上来了。我个人的习惯是如果产品本身就是 MSVC 工程那就干脆用 MSVC 体系编一份如果只是临时工具或者脚本调用直接用 LoadLibrary 会更省事。MinGW 编 DLL 的这套流程最适合 GCC/MinGW 生态、Qt 工程以及各类跨平台构建体系。6. 编译中的常见报错与排查记录6.1 configure 阶段报 “C compiler cannot create executables”这是新手最容易撞上的报错原因不外乎几类。先检查--cross-prefix对应的编译器是否存在。在 Shell 里直接执行x86_64-w64-mingw32-gcc -v如果提示找不到命令说明工具链没装到位。其次检查是不是在源码根目录直接 configure 了。FFmpeg 虽然支持在源码目录内构建但反复重新 configure 容易受 config.log、config.mak 残留影响。建议每次都用一个干净 build 目录。最后检查有没有装齐 MinGW 头文件包MSYS2 的mingw-w64-x86_64-toolchain本身就是完整集合不太会缺如果是手动下载的散装 MinGW-w64则可能漏了头文件。6.2 make 中报错与汇编器相关现代 FFmpeg 对 x86 架构的汇编处理离不开 nasm/yasm。如果在 MinGW64 环境里没有安装mingw-w64-x86_64-nasmconfigure 也能通过但编译某些对象文件时会报“Unknown option”或 syntax 错误。直接在对应的环境补装 nasm 即可pacman -S mingw-w64-x86_64-nasm32 位同理安装mingw-w64-i686-nasm。这里要特别注意“对应环境装对应包”的原则在 MinGW64 环境装 32 位 nasm 是没用的因为路径不在一起或者会被 configure 扫到错误版本。6.3 运行时报 0xc000007b 或找不到 DLL0xc000007b 这个错误码在 Windows 下基本就等于“位数不匹配”。用 64 位主程序去加载 32 位 DLL或者反过来都会触发它。排查时用 objdump 逐个检查 av*.dll 以及依赖的 libgcc/libwinpthread 的架构确保全部对齐。如果是“找不到指定的模块”那多半是依赖 DLL 缺失。最直接的验证办法就是打开 Windows 的“加载依赖”工具或者在命令行跑一次程序看 LoadLibrary 报错位置。把 libgcc_s_seh-1.dll、libwinpthread-1.dll 这类运行时库和 FFmpeg 的 DLL 一起放进主程序目录能解决绝大多数启动失败。6.4 双架构编译互相污染的问题同时编 32 位和 64 位最危险的操作就是两个 build 目录或两个 install 目录合并。比如第一次make install装到dist/第二次又装到同一个dist/结果 32 位 DLL 把 64 位同名文件覆盖了架构混在一起怎么排错都查不出来。我的做法是建立两条完全独立的流水线build64/ - install64/ - dist/x64/ build32/ - install32/ - dist/x86/每次发布前用脚本把对应目录打包不带错文件。这样即使客户环境有问题也能根据 DLL 架构快速定位是哪一份包出了问题。6.5 自编译文件被安全软件误报的问题自编译的 ffmpeg.exe 或某些 DLL 有时会被 Windows Defender 或第三方安全软件当成未知程序拦截。这不是 FFmpeg 本身有什么问题而是因为未签名的自定义构建本来就在 SmartScreen 的“少见文件”判断范围内。处理方式看场景内部工具可以让使用者加信任目录对外分发时考虑给可执行文件做代码签名或者至少提供一份构建记录说明。不要用加壳、加密的手段去规避那样反而更容易触发误报。7. 沉淀下来的构建习惯与推荐操作这套流程反复用了几轮之后我给自己定了一些固化的习惯。源码固定 release 版本不用 latest 分支。我在构建项目里把 FFmpeg 版本号写到脚本注释里每个版本对应一份构建记录将来出了问题能快速定位是源码问题还是配置问题。32 位和 64 位的 configure 参数写成两份独立脚本比如build-x64.sh和build-x86.sh内容差异只有前缀、arch 和安装路径。避免每次手动敲 configure 时敲错参数。发布目录里除了 DLL还会把include/和lib/一起打进去。这样下游开发者拿到压缩包后既可以直接复制 DLL 运行也可以自行链接开发。最后分享一个调试技巧编完第一版后先写一个最小的测试程序只调用 avformat 的初始化和打开文件接口分别在 32 位和 64 位下跑通再去接其他复杂逻辑。这一步能隔离出绝大多数环境问题省去后面拿整个项目排查的麻烦。希望这篇记录对正在折腾 MinGW FFmpeg DLL 的你有帮助。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询