ffmpeg-3.4-mingw32编译实战:32位Windows老系统部署 简介这是一份面向Windows 32位开发者的FFmpeg 3.4 MinGW32编译资源包解决了在Qt/C等环境下快速集成音视频编解码、格式转换与流媒体处理的需求。包内共170个文件主要包括头文件h、C源码c、导入库与静态库a/lib、动态链接库dll、编译配置def/pc及ffmpeg、ffprobe等可执行工具整体压缩包仅2.62MB体积小巧、便于部署。FFmpeg 3.4支持H.264/H.265、VP9、AAC、Opus等主流编码并提供RTMP、HLS、MPEG-DASH等流媒体协议处理能力该版本还带有大量视频音频滤镜及命令行工具适合直接调用或二次开发。资源包内附多个示例C文件如转码、封装、解码等及ffpreset预设文件可帮助开发者快速理解API调用流程与编译集成方法。目前已有227人学习下载对于需要在32位Windows环境或MinGW工具链下使用FFmpeg的读者是一份实用的入门与参考材料。1. ffmpeg-3.4-mingw32还在维护旧系统的人绕不开这组编译产物手头有个跑在 Windows 7 嵌入式工控机上的老项目系统是 32 位内存 4G不敢动。要给它加一个录像转码模块搜遍全网发现官方已经不提供 32 位 Windows 的 FFmpeg 构建包只有源码。那几天我把 MSYS2、MinGW、configure 这几个词来回排列组合搜索最后发现大多数人卡在同一个地方不是不会敲命令而是不知道 3.4 这个版本在 32 位 Windows 编译链上的特殊性。这篇文章把我用 ffmpeg-3.4-mingw32 从编译到接进业务代码的完整路径写出来包括每个 configure 参数为什么这么设、链接报错怎么看、以及运行时那些玄学问题。2. 为什么是 3.4 mingw32这组组合的边界在哪2.1 3.4 这个版本在 FFmpeg 生命周期里的位置FFmpeg 3.4 发布于 2017 年底代号是 Cantor。它不是一个功能最全的版本但它是最后一个在 Windows 32 位环境下能比较省心编出来的大版本。之后 FFmpeg 把代码库往 64 位优先的方向推几个核心模块陆续引入了需要 64 位指针才能高效处理的内部结构。虽然 32 位 MinGW 工具链到现在也能编译新版源码但链接时间和运行稳定性都明显不如 3.4 时期。对还在维护老系统的开发者来说3.4 还有个隐性的好处它的 API 和现在主流的 4.x/5.x/6.x 之间虽然有差异但解码器、封装器的基础调用方式一脉相承。你照着 3.4 的接口写好的调用代码将来如果平台升级到 64 位迁移成本远低于从更老的 2.x 版本迁过来。另外 3.4 对第三方依赖库的版本要求比较宽松。比如 x264 用 2017 年前后的稳定版就行zlib、libpng、lzma 这些基础库在 MSYS2 的 32 位仓库里都能直接匹配到可用版本。这不是说新版 FFmpeg 不行而是 3.4 的依赖匹配范围更宽在离线环境、内网环境里更容易凑齐一套能用的库。2.2 mingw32 和 mingw64、MSVC 的选型差异mingw32 里的 32 不是指编译器只能编 32 位程序而是指它默认的 target triplet 是 i686-w64-mingw32。你在 MSYS2 里装的 mingw-w64-i686-toolchain编出来的程序跑在 32 位 Windows 上mingw-w64-x86_64-toolchain 编出来跑在 64 位 Windows 上。如果你的目标机器是 32 位系统那只能用前者。这里有个容易绕弯的点MSYS2 提供了一个叫 MSYS 的 shell 环境它本身是个 64 位程序或者根据你安装包决定。你在这个 shell 里执行 configure但编译器、链接器、目标库用的都是 32 位那套最终产物是 32 位 PE 文件。所以「mingw32」这个词在标题里指的是产物目标不是开发环境本身。和 MSVC 相比MinGW 的优势在于 configure 脚本体系是 Linux 那套思路autoconf 生成的东西在 MSYS2 里直接跑不用手动维护 .vcxproj 工程文件。FFmpeg 官方虽然也提供 MSVC 编译路径但那需要额外处理 nasm 汇编器、pkg-config 路径等一系列环境变量第一次操作很容易在步骤衔接处翻车。我的建议是如果你只需要 FFmpeg 的库和命令行工具走 MinGW 路线最省心。2.3 什么时候不应该选这组方案3.4 mingw32 不是万金油。如果你的目标机器是 64 位 Windows哪怕系统是 Windows 7我也建议直接用 x86_64 工具链编新版 FFmpeg。32 位程序在 64 位系统上能跑但内存寻址被限制在 4G 以内视频处理这种吃内存的活很容易撞上限。另外如果你在做的项目对解码速度有极端要求考虑 Intel Media SDK、NVDEC 这类硬件加速方案时3.4 对它们的支持已经陈旧了。3.4 版本里 QSV 的 API 还是老一套新的显卡驱动未必兼容。这种情况就得选新版 FFmpeg然后接受 32 位编译链更折腾的事实。确定路线之前先回答一个问题你的目标系统真的是 32 位吗还是手里正好有个老编译器就这么试了如果是后者重新考虑一下。提示FFmpeg 的版本号可以从ffmpeg -version输出里看到编出来之后第一时间确认--enable-version3这类配置是否生效不要只看文件名。3. 搭建 MSYS2 编译环境从零到能跑 configure 的最小步骤3.1 安装 MSYS2 与 32 位工具链MSYS2 是一个在 Windows 上提供 Linux 风格环境的软件发行版。它有三个核心组件MSYS shell类 Unix 的终端环境、pacman 包管理器、以及多个 target 的交叉工具链。我们要用的是 i686 那一套。安装 MSYS2 之后默认打开的是 UCRT64 或 MSYS 环境。这里注意我们要用的是MSYS2 Shell还是MinGW32 Shell答案是配置步骤在哪个 shell 里做都行但编译出来的二进制要确保用的是/mingw32/bin下的工具链。最容易的办法是直接在开始菜单里打开MSYS2 MinGW 32-bit这个快捷方式它会把 PATH 自动指到/mingw32/bin避免混用。pacman -Syu pacman -S --needed base-devel mingw-w64-i686-toolchain第一行pacman -Syu更新整个 MSYS2 环境和包数据库。第二行安装基础开发工具链包括 gcc、make、autoconf 等。--needed的意思是已安装的包直接跳过不会重复安装。这一步装完之后在 shell 里执行gcc -v看输出应该能看到 Target 那一行写着i686-w64-mingw32这就说明当前环境是 32 位工具链。3.2 安装 FFmpeg 3.4 编译需要的依赖库FFmpeg configure 会检查很多可选库。我们最小化编译的话不需要全部装但下面这几个建议装齐因为它们覆盖了最常见的编解码场景pacman -S mingw-w64-i686-libiconv mingw-w64-i686-zlib mingw-w64-i686-lzma # 以下按需安装 pacman -S mingw-w64-i686-libvpx mingw-w64-i686-x264 mingw-w64-i686-x265libiconv处理字符集转换FFmpeg 处理字幕和某些容器格式时会用到。zlib是几乎所有压缩相关模块的基础lzma用于 XZ 压缩的封装和读取。这三个如果缺失configure 会跳过相关功能但不会直接报错。x264、x265、libvpx是编码器库装了他们 FFmpeg 才能输出 H.264、HEVC、VP9 格式的文件。一个容易忽略的依赖是nasm。它不在 toolchain 里自带必须单独装。pacman -S mingw-w64-i686-nasm装完之后确认一下版本nasm -v。如果 configure 时提示找不到 nasm最可能是这个包没装或者你打开的是 64 位环境的 shell而 32 位的 nasm 不在 PATH 里。3.3 准备 FFmpeg 3.4 源码与目录结构源码可以从 FFmpeg 官网下载 3.4 的 tar.bz2 包或者git clone后切到n3.4分支。我倾向于下载 release 包而不是 git 拉取因为 release 包已经跑过一轮完整测试git 分支上偶尔会有中间提交带进来的临时问题。源码解压到某个纯英文路径比如C:\ffbuild\src。编译产物输出到C:\ffbuild\out。这么做的好处是 configure 里写 prefix 时不涉及中文路径和空格MinGW 对带空格路径的处理偶有毛病犯不上在这个地方浪费排查时间。cd /c/ffbuild mkdir -p src out tar xjf ffmpeg-3.4.tar.bz2 -C src4. 编译 ffmpeg-3.4-mingw32 的 configure 参数照着改就行4.1 最小可用配置进入源码目录后第一步是跑 configure。FFmpeg 的 configure 不像 autoconf 那套唯一标准参数的组合自由度很高。下面这个命令是我在 32 位 Windows 目标下最常用的最小配置./configure --archx86 \ --target-osmingw32 \ --prefix/c/ffbuild/out \ --enable-cross-compile \ --disable-programs \ --disable-doc \ --disable-network \ --enable-static \ --disable-shared \ --pkg-configpkg-config逐行说明。--archx86明确告诉 configure 目标是 32 位架构这一步能避免它去探测宿主环境误判成 x86_64。--target-osmingw32指定目标操作系统是 WindowsMinGW 运行时。--enable-cross-compile在 target 和 host 不一致时是必选项如果 configure 报「use --enable-cross-compile」的提示多半是缺了这个。--disable-programs表示不生成ffmpeg.exe、ffprobe.exe这些命令行工具只编库如果只需要库文件这个参数能省三到五分钟编译时间。--disable-network在不需要网络拉流时关掉减少链接依赖。--enable-static --disable-shared让输出是静态库。跑完 configure 后注意看输出末尾有没有WARNING: ... not found的行。这些警告只代表相关功能没被编进去不一定是错误。但如果警告里出现了 x264、zlib 这些你明明装了的东西就该检查路径了。4.2 三个必调参数第一个必调参数是--extra-cflags。MSYS2 的 32 位工具链默认包含了一些与 FFmpeg 冲突的优化选项最常见的是-O2与 FFmpeg 内建汇编的兼容问题。我一般会显式覆盖--extra-cflags-m32 -I/c/ffbuild/out/include-m32是双保险确保 gcc 生成 32 位代码即便 configure 判断失误也能在这层纠正。-I头文件搜索路径指向我自定义的输出目录目的是让 FFmpeg 找到我手工装的库的头文件。第二个必调参数是--extra-ldflags。静态链接时经常需要手动指定库搜索路径--extra-ldflags-L/c/ffbuild/out/lib-L指定静态库位置。如果你发现链接阶段报错说找不到某个.a文件先检查这个路径对不对。第三个必调参数是--disable-x86asm。这个参数有意思——3.4 版本在 mingw32 环境下nasm 的汇编优化有时候会生成有问题的代码表现为运行时解码花屏或者静默失败。遇到这种问题关掉汇编优化来规避。代价是速度损失 10% 到 20%但兼容性大幅提升。我通常先尝试默认开启的汇编优化如果跑出的测试视频有花屏再关掉。4.3 静态库与动态库的取舍FFmpeg 在 Windows 上编动态库DLL有额外的复杂之处需要处理 lib 文件与 dll 文件的配套、导出符号表的漂移问题。MinGW 环境下的动态库生成经常在链接阶段报一堆未解析的符号因为默认的导出策略不如 MSVC 那套.def文件可控。因此除非你的调用方明确要求 DLL 形式建议第一次编静态库。静态库的坏处是调用方工程里链接时会把 FFmpeg 的一大堆对象文件全部打包进可执行文件体积暴增。一个包含了 FFmpeg 静态库的 exe 轻松过 20MB。但换来的是部署时不用带一堆 DLL 文件对于工控机这种环境反而省心。另外静态库模式下 FFmpeg 的avformat、avcodec等库之间也有依赖顺序问题。链接器要求库的顺序是从底层到上层排avformat依赖avcodec和avutil所以链接参数里-lavformat -lavcodec -lavutil这个顺序不能乱。静态库链接报 undefined reference 时先调整库的排列顺序再谈加-l参数。链接参数顺序对应库出错场景-lavformat格式封装/解封装往前放-lavcodec编解码器必须跟在 avformat 之后-lavutil工具函数排在最后-lswresample音频重采样一般放 avutil 前4.4 按需裁剪能编什么3.4 版本的可裁剪粒度很细。如果只是某一个具体需求比如「把 H.264 的 MP4 转成 AVI」那可以关掉大量的编解码器来缩短编译时间--disable-everything \ --enable-decoderh264 \ --enable-encoderh264 \ --enable-demuxermp4 \ --enable-muxeravi \ --enable-parserh264 \ --enable-protocolfile--disable-everything先把所有功能关掉然后按需开启。注意--enable-protocolfile别漏掉没有它FFmpeg 连本地文件都打不开。--enable-parserh264是因为裸 H.264 流解封装时候要用到。裁剪得越狠编译速度越快但这要求你知道自己到底要哪些模块。改完配置动一次手比较费事花个十分钟想清楚需求再动手。5. 编译期的 5 个常见坑现象、原因、解决5.1 configure 报错 nasm not found现象configure 进行到一半提示nasm not found或者yasm not found然后退出。原因MSYS2 的 32 位环境里 nasm 是单独的包。大部分安装教程只让你装了 toolchain没提 nasm。另一个常见原因是你打开了 MSYS2 的 UCRT64 环境64 位在里面跑 configure但打包的 nasm 是 64 位路径下的而 configure 在探测时找不到可执行文件。解决执行pacman -S mingw-w64-i686-nasm装 32 位版本然后用which nasm确认路径在/mingw32/bin下。如果不是重新开一个 MinGW 32-bit 的 shell。5.2 链接时报 undefined reference 到奇怪的符号现象make 跑到链接阶段报一大堆undefined reference to av_...特别是你自己写测试程序调用库时更容易碰到。原因三种可能。第一静态库链接顺序写反了avformat放在avutil后面。第二configure 里--disable-everything裁掉了你调用的模块。第三FFmpeg 的库有版本化符号机制avcodec.57.dll链接参数和库文件名对不上。解决先用pkg-config --libs libavformat看它输出了什么顺序照抄到你的 Makefile 里。如果 pkg-config 没有输出手动按-lavformat -lavcodec -lavutil顺序排列再不够就加-lswresample -lpostproc补全依赖链。还有一种调试技巧用gcc -v看链接命令确认每个-l实际匹配到了哪个.a文件。5.3 编出来的 exe 在 64 位 Windows 上秒退现象程序在开发机64 位 Windows 10上双击运行黑框闪一下消失。原因这个程序依赖的 DLL 不是系统自带的比如libgcc_s_dw2-1.dll、libstdc-6.dll这些是 MinGW 运行库的一部分。开发机因为装了 MSYS2PATH 里能搜到这些 DLL所以运行正常部署到纯净机器上就找不到。解决在编译时用-static-libgcc -static-libstdc把运行时静态链进去。如果 FFmpeg 的库本身是静态编的这个问题的概率会小很多。更稳妥的做法是编译命令里加--extra-ldflags-static让它彻底静态化代价是生成的文件更大。注意这不是 FFmpeg 本身的 bug是 MinGW 工具链的运行方式决定的。写部署文档时务必注明这一点否则运维同事会把锅甩给 FFmpeg。5.4 硬解码失败错误码 -1094995529现象调用avcodec_decode_video2返回负数网上查这个错误码是AVERROR_INVALIDDATA但相同数据在 Linux 上能解出来。原因在 3.4 的 mingw32 构建里某些 H.264 编码的输入流需要--enable-decoderh264_qsv或硬件解码路径而 32 位环境下 Intel QSV 的支持是残缺的FFmpeg 在初始化时按照默认优先级选择了一个不存在的解码器导致返回无效数据。解决在代码中显式指定解码器为avcodec_find_decoder(AV_CODEC_ID_H264)之后的第一个软件解码器。另外configure 时建议--disable-hwaccels关掉所有硬件加速模块纯软解在 32 位平台上反而稳定。代价是 CPU 占用变高但旧系统上内存和 GPU 驱动本来撑不起硬解。5.5 pkg-config 找不到 zlib 库的 .pc 文件现象跑 configure 时明明装了 zlib警告里还是提示ERROR: zlib not found。原因MSYS2 的 zlib 包带了 .pc 文件但 pkg-config 的搜索路径没包含/mingw32/lib/pkgconfig。如果之前在你的 shell 里设置过PKG_CONFIG_PATH环境变量并指向了 64 位那套目录就会覆盖默认搜索路径。解决export PKG_CONFIG_PATH/mingw32/lib/pkgconfig:$PKG_CONFIG_PATH然后重新跑 configure。如果还是找不到直接看/mingw32/lib/pkgconfig里有没有zlib.pc。MSYS2 的安装包拆成了运行库和开发包两部分只装libz不会带.pc文件要装mingw-w64-i686-zlib这个完整包。用pacman -Qs zlib检查当前装的是哪个。6. 编译完成后先做这三件事验证产物、封装调用、固化流程6.1 用 ffmpeg 自带工具验证功能完整如果你 configure 时没有--disable-programs产出的ffmpeg.exe就是最好的验证工具。在一个测试目录放一个 H.264 编码的 MP4 文件执行./ffmpeg -i test.mp4 -c:v copy -f avi test.avi这条命令只做流复制不涉及重编码用来验证解封装和 muxer 的完整性。跑通之后再用-c:v libx264强制 H.264 编码那才会走到 x264 库的链路。如果libx264编码报错说明 configure 阶段对 libx264 的探测失败。我还习惯看一眼ffmpeg -codecs的输出确认H.264那行有D和E两个字母——一个代表解码一个代表编码。只有 E 没有 D说明解码器没编进去。6.2 把 FFmpeg 3.4 接进业务代码的封装要点许多人第一次在 Windows 上调 FFmpeg 库最大的问题不是 API 本身而是文件和流路径的编码方式。MinGW 版的 FFmpeg 在打开文件名时默认使用本地字符集你的业务代码如果传 UTF-8 字符串给avformat_open_input中文路径会直接失败。标准做法是调用avformat_open_input之前把路径从 UTF-8 转成 UTF-16再用avformat_open_input的宽字符变体// 伪代码示意 const char *utf8_path D:\\素材\\测试.mp4; wchar_t wpath[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, utf8_path, -1, wpath, MAX_PATH); AVFormatContext *fmt NULL; int ret avformat_open_input(fmt, wpath, NULL, NULL);注意avformat_open_input的第二个参数用宽字符版本时 FFmpeg 会识别出这是 Windows 宽路径。进程中需要至少调用一次av_register_all()3.4 版本没有自动注册机制。av_register_all放在初始化代码里第一次调用 FFmpeg 任何方法之前。6.3 固化编译流程写一个编译脚本我吃过「编好了但三个月后要加个新模块忘了怎么编」的亏。现在所有编译操作都收敛在一个脚本里。#!/bin/sh # build_ffmpeg_mingw32.sh set -e export PKG_CONFIG_PATH/mingw32/lib/pkgconfig ./configure \ --archx86 --target-osmingw32 \ --prefix/c/ffbuild/out \ --enable-cross-compile \ --disable-programs --disable-doc \ --enable-static --disable-shared \ --disable-network \ --disable-hwaccels \ --extra-cflags-m32 -I/c/ffbuild/out/include \ --extra-ldflags-m32 -L/c/ffbuild/out/lib \ $ make -j$(nproc) make installset -e保证任何一步出错就停止。$允许你在不改主流程的前提下追加临时模块。把脚本放在源码根目录之外用sh build_ffmpeg_mingw32.sh --enable-libx264 --enable-gpl这样额外开启编码器支持。对照这个脚本即使半年后回头也能在三分钟内重建整套编译环境。这些验证动作做完你的 ffmpeg-3.4-mingw32 才算真正可用。我自己的习惯是编译完后顺手把 configure 输出的完整日志压缩存档因为有些特性它显示为「yes」但实际链接不过那个日志就是未来排错的第一手参考。希望这篇实战笔记能帮你在旧平台和旧版本之间少走几个来回。本文还有配套的精品资源点击获取