简介:一款面向32位Windows开发者的FFmpeg 3.4预编译包,采用MinGW32环境构建,便于在Qt/C++工程中直接集成音视频解码、转码与流媒体处理,省去自行编译依赖的繁琐。压缩包共170个文件、大小仅2.62MB,以头文件和C源码为主,同时包含DLL动态库、导入库与静态库、pc/def配置、命令行可执行程序及readme、makefile等辅助文件,结构紧凑,适合轻量集成。包内附有音频转码、转封装、解封装解码等场景的C示例,可帮助开发者理解FFmpeg接口调用与数据流组织;配套的预设与工程配置,也能显著降低二次开发的环境搭建成本。该版本基于FFmpeg 3.4,支持H.264、H.265、VP9、AAC、Opus等常见编码格式及RTMP、HLS等流媒体协议,功能覆盖广泛。已有226人浏览学习,适合在32位Windows、MinGW或Qt环境下进行多媒体开发、功能裁剪或二次封装的开发者直接选用。
1. ffmpeg-3.4-mingw32 是什么:一个 32 位构建为什么还能活到今天
如果你在一个老项目的第三方依赖清单里看到 ffmpeg-3.4-mingw32 这个名字,或者从某个 Windows 工业软件安装包里翻出一个 ffmpeg.exe,它多半不是最新版,而是一份用 MinGW-w32 工具链针对 32 位 Windows 编译的 FFmpeg 3.4 构建。
它解决的是“老程序还要继续用 FFmpeg”这个现实问题:3.4 分支 API 足够稳定,MinGW 编出来的 exe 不依赖 VC 运行库,而 32 位产物能被大量仍以 x86 模式运行的插件宿主、采集卡 SDK 和旧系统加载。如果你正在维护这类环境,或想自己用 MSYS2 构建一套静态库,这篇能帮你从编译到接入完整跑通;如果只想下载工具转格式,这份构建也比 x64 版更贴近某些生产机器的实际限制。
2. 从零编译 ffmpeg-3.4-mingw32:MSYS2 环境下 configure 与 make 的完整流程
预编译的 ffmpeg.exe 虽然能转码,但当你被要求“把这个链接到我们的 32 位采集卡 SDK 里”,或者需要把 libx264 也编进去时,预编译包就无能为力了。自己编译并不是玄学,关键是把工具链、依赖库和 configure 参数搞对。我一般用 MSYS2 的 MinGW32 终端完成整套动作,下面从装环境到生成静态库一步步说。
2.1 为什么选 MSYS2 而不是 Cygwin 或裸 MinGW
Windows 下能跑 FFmpeg 编译的环境大致有三类,直接选择 MSYS2 的原因很具体:Cygwin 生成的 exe 依赖 cygwin1.dll,部署时容易像缺 libgcc 那样缺一个 cygwin 运行时;裸 MinGW 需要自己手工下载 zlib、x264 等依赖的头文件、库和 pkg-config,一旦版本混搭,configure 探测到的符号全是乱的。MSYS2 用 pacman 管理包,并且分 i686 和 x86_64 两套仓库,可以精确进入 32 位环境。
打开 MSYS2 安装目录里的“MSYS2 MinGW32-bit”终端(不是 MSYS2 MSYS 那个入口),先做一次系统更新。这个步骤如果你是第一次装,通常会让你关闭终端重启第二次,因为 pacman 更新了自身和核心库后,当前进程里还留着旧版本。
pacman -Syu # 若提示“close this window”,关闭当前终端,重新打开 MSYS2 MinGW32-bit 再执行: pacman -Su参数说明:-Syu 中 -U 会把所有需要升级的包一起升级;升级过程如果在 core 库上中断,就重复第二行。完成后下一步装编译链和依赖。
pacman -S --needed mingw-w64-i686-gcc mingw-w64-i686-nasm \ mingw-w64-i686-yasm mingw-w64-i686-pkg-config \ mingw-w64-i686-libvpx mingw-w64-i686-x264 mingw-w64-i686-zlib这里最容易被忽略的是包名里的 i686,它对应 32 位 x86。如果习惯性装成了 mingw-w64-x86_64-*,后面 configure 检测到的是 64 位编译器,产物就不是标题里的 mingw32。nasm 和 yasm 是给汇编优化用的,x264 和 libvpx 是第三方编码库;如果只用 FFmpeg 自带编码器,可以把后两个去掉,但常用 H.264 能力就没了。
装完后在终端里先验证一下 gcc 路径,避免后续几十个编译错误才回来查环境:
which gcc gcc --version输出路径应类似 /mingw32/bin/gcc,版本号里的 i686 字样能确认是 32 位。这一步是选型理由的落点:你控制好工具链,configure 才不会被 64 位的意外变量带偏。
2.2 获取 FFmpeg 3.4 源码并放到干净目录
FFmpeg 官网或镜像站点提供 ffmpeg-3.4.tar.xz。这里的下载文件名就是 ffmpeg-3.4,整数版本号意味着 2017 年发布的稳定分支,API 对新编译环境已经足够成熟。下载文件后,在 MinGW32 终端里解压到一个纯英文、无空格的路径。很多人喜欢放在带空格的 Program Files 下,最后 configure 的 C 编译器测试十有八九失败。
mkdir -p /c/ffbuild cd /c/ffbuild tar -xf /tmp/ffmpeg-3.4.tar.xz cd ffmpeg-3.4 ls | grep -E 'configure|Makefile|libavcodec'这里把路径固定在 C:\ffbuild,有两个好处:一是避免空格和 UTF-8 文件名干扰快速测试程序;二是后续生成的中间文件不会触发 Windows 长路径问题。列出关键文件是为了确认这是源码包,而不是某站点打包的预编译版。
2.3 配置编译参数:--target-os=mingw32 和 --enable-libx264 为什么必须写对
FFmpeg 的 configure 是整个编译成败的核心,它不像普通 Makefile 直接开跑,而是会做七十余项检测,探测编译器、汇编器、库函数是否存在。标题里的 mingw32 最终就体现在两个开关上:--arch=x86 和 --target-os=mingw32。只有把这两个参数落到 configure 命令行,生成的执行文件和库才是指定格式。
./configure \ --arch=x86 \ --target-os=mingw32 \ --enable-static \ --disable-shared \ --enable-gpl \ --enable-version3 \ --enable-libx264 \ --enable-libvpx \ --enable-zlib \ --disable-doc \ --disable-debug \ --disable-ffplay \ --extra-cflags="-static-libgcc" \ --extra-ldflags="-static-libgcc"这一串参数里,几个容易理解错的地方值得单独拿来说。--target-os=mingw32 是告诉 FFmpeg 使用纯 Win32 原生实现,虽然 MinGW 下也有 cygwin 选项,但那样输出会带 cygwin1.dll 依赖。--enable-static 和 --disable-shared 成对出现,表示最终只需要 .a 静态库和静态链接的 ffmpeg.exe,后续拿到别的机器上不用再抱一堆 DLL。--enable-gpl 和 --enable-version3 必须开,因为 libx264 采用 GPL 许可,不开会在 configure 阶段直接拒绝组合。
--enable-libx264 是能不能输出 H.264 的关键,但要注意,FFmpeg 3.4 的老版本对 libx264 版本有上限要求,太新的 x264 源码可能引入新特性导致 3.4 编译报错。MSYS2 的 i686 仓库里 x264 版本一般和老 FFmpeg 兼容,这也是选 MSYS2 而不是自己下载 x264 源码的另一个理由。--disable-ffplay 表示不编译播放器,ffplay 依赖 SDL,生产环境下用不到,去掉后少一个依赖。
还有两个静态运行时的坑,直接在 configure 阶段堵住:--extra-cflags="-static-libgcc" 和 --extra-ldflags="-static-libgcc" 强制把 GCC 运行时库静态链接到产物里,否则生成的 ffmpeg.exe 在别的机器上会提示找不到 libgcc_s_dw2-1.dll。若你不需要 libvpx 也可以去掉 --enable-libvpx,但默认建议保留,VP8/VP9 在 Web 场景仍然有用。配置完成后 configure 会输出一堆 Enabled/Disabled 列表,确认里面有 static 和 libx264 字样再进入下一步。
2.4 编译、安装与验证最小可运行产物
configure 通过后,编译本身没有太多玄学,但并行数需要根据内存定。在 MinGW32 终端里执行:
make -j4 make install-j4 表示同时编译 4 个目标,如果你的机器只有 2GB 内存,最好改成 -j2,因为 FFmpeg 的编译中间文件比较大,过高的并行数是常见的内存爆掉原因,表现为 virtual memory exhausted 或某个子进程被系统杀死。官方建议的 -j$(nproc) 在 MSYS2 下会读到整机核心数,个人经验是 4 足够。
make install 默认安装到 /usr/local,也就是 MSYS2 目录下的 usr/local。如果希望把产物集中到一个自定义目录,在 configure 时加 --prefix=/c/ffbuild/out 再执行 make install。安装完成后,验证是否真的得到了想要的 ffmpeg-3.4-mingw32:
ffmpeg -version ls /usr/local/lib | grep avcodec pkg-config --cflags --libs libavcodec pkg-config --modversion libavcodecffmpeg -version 的输出第一行会包含 ffmpeg version 3.4 和 --enable-libx264,这是最直观的确认。pkg-config 如果提示找不到包,设置环境变量:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig要判断静态库是否真的可用,可以看一眼 /usr/local/lib 里是否有 libavcodec.a 而不是只有 libavcodec.so,这里不出现 .so 才正常,因为 3.4 源码在 MinGW32 下默认不会生成 .so。这一步做完,你就拥有了一份可复制、可裁剪的 ffmpeg-3.4-mingw32 全家桶。
3. 把编译产物用起来:m3u8 转 MP4、区域截取与低延迟推流
编译完 ffmpeg.exe 不是终点,真正的使用场景才决定参数怎么设。这一章挑三个我工作中反复用到的方向:HLS 流转单文件、监控画面局部截取、推流到流媒体服务器时压延迟。它们分别对应最常见的实际诉求。
3.1 m3u8 转 MP4:一段 TS 流如何变成能拖放的单文件
接到一个 m3u8 播放列表,最终交付往往要求一个 MP4。第一种做法是直接复制流,只改封装,速度快到接近几秒,但前提是源流编码格式适合 MP4。命令如下:
ffmpeg -i "https://your-server/path/index.m3u8" -c copy \ -bsf:a aac_adtstoasc -movflags +faststart output.mp4这里的 -c copy 表示不重新编码,对命令行理解不深的用户会把它当成“无损”,其实它只是复用已编码数据。HLS 的片段是 TS 封装,TS 里的 AAC 音频带 ADTS 头,而 MP4 要求音频流是 ASC 配置,因此 -bsf:a aac_adtstoasc 把音频比特流过滤成 MP4 识别的格式。不加这个过滤器,输出文件经常画面正常但没声音,而且现象不报错,很坑。
-movflags +faststart 是给 Web 播放用的,把 moov 元数据挪到文件头。如果不加,文件要等下载完才能拖播放进度条。对于需要服务器直接提供点播文件的场景,这个参数几乎是必加。
如果源流码率参数很奇怪,或者你希望把分辨率统一,就要放弃 copy 改用重编码:
ffmpeg -i "in.m3u8" -c:v libx264 -crf 20 -preset medium \ -c:a aac -b:a 128k -movflags +faststart output.mp4重编码耗时取决于源时长,但能解决源流里时间戳混乱造成的音画不同步。有的 m3u8 源网络断流会导致输入提前结束,输出文件时长被截短,这时可以在 -i 前加 -timeout 10000000(单位微秒)让 ffmpeg 等待网络重传,数值越大越耐断,但也可能卡在坏链上很久。经验做法是先不加超时跑小片段测试,再决定。
3.2 截取视频部分区域:crop 参数越界时的“Invalid argument”从哪来
监控视频通常一整个画面,业务上只关心某个角落。FFmpeg 的 crop 滤镜负责截取矩形区域,scale 负责二次缩放。命令组合如下:
ffmpeg -i surveillance.mp4 -vf "crop=640:360:120:80,scale=640:360" \ -c:v libx264 -crf 23 -preset fast \ -c:a aac -b:a 96k -ar 44100 clip.mp4crop=w:h:x:y 的四个参数分别是裁剪宽度、高度、左上角横坐标、左上角纵坐标。这里裁的是 640x360,从源画面的 x=120、y=80 开始往右往下取。如果 x+w 超过源宽度或者 y+h 超过源高度,FFmpeg 会直接报 filter: Invalid argument 并退出。这是 invalid argument 最典型的来源之一,很多新手以为是文件损坏,其实只是坐标计算问题。
在滤镜链中 crop 之后接 scale,是为了把裁剪出的分辨率输出到目标分辨率。scale=640:360 在这里等于没变,但如果裁剪出的是 641x361 这样的奇数尺寸,裸的 libx264 会拒绝编码:width not divisible by 2。所以建议裁剪宽高都用偶数,或让 scale 用保证偶数的表达式:
ffmpeg -i in.mp4 -vf "crop=iw-200:ih-200:200:0,scale=trunc(iw/2)*2:trunc(ih/2)*2" out.mp4iw、ih 是滤镜输入宽度和高度,200 表示往右上角靠;scale 里 trunc(iw/2)*2 把宽度压成偶数。这个写法在批量处理不同分辨率源时尤其省心。crop 的参数是像素单位,不是百分比,需要换算;若源是 1920x1080,裁左上角 800x600,就是 crop=800:600:0:0。
如果只要画面不要声音,加上 -an 即可。反之需要补充音频轨时,保留 -c:a 参数。滤镜顺序会影响性能和内存占用,crop 越早越好,因为后面的 scale 处理的是缩小后的帧,CPU 开销更小。
3.3 推流到 SRS 但延迟越来越大:先重建 GOP 结构
SRS 是常见的开源流媒体服务器,用 FFmpeg 推流后客户端延迟大,问题经常不在服务器,而在推流端的编码参数。默认 x264 会按场景自动插关键帧,GOP 可能拉到几十帧甚至上百帧,播放器缓冲等待关键帧的时间被拉长。低延迟推流命令我一般这样写:
ffmpeg -re -i input.mp4 -c:v libx264 -preset ultrafast \ -tune zerolatency -g 2 -keyint_min 2 -sc_threshold 0 \ -c:a aac -b:a 96k -ar 44100 \ -f flv rtmp://your-srs-server/live/stream-preset ultrafast 用最少的编码计算换取实时性,-tune zerolatency 关闭 x264 的 lookahead 和缓冲;这两项加一起能显著降低编码端引入的延迟。真正的关键帧控制靠 -g 2:它让每个 GOP 最多 2 帧,而 -sc_threshold 0 关闭场景切换检测,防止画面剧烈变化时编码器自作主张插入额外关键帧,破坏均匀间隔。keyint_min 2 配合 -g 2 确保从第一个关键帧开始就按这个间隔工作。
这里还要强调 -re 的作用:它让输入按原视频时间戳速率读取,而不是全力读。缺了它,FFmpeg 会把一段 5 分钟视频几秒内推完,SRS 收到的数据包时间戳乱掉,表现就是延迟忽高忽低甚至卡顿。如果你的输入是摄像头 RTSP 流而不是文件,-re 不需要,因为实时流本身有时间戳。
带宽有限时再加一个 -b:v 800k 限制视频码率;若网络波动严重,编码器瞬时码率过高会在 SRS 端触发拥塞,延迟进一步放大。ultrafast + zerolatency 代价是同等码率下画面质量比 medium 差,但直播场景优先保证实时性。这些参数组合也是解决推流到 SRS 存在延迟的常规手段,SRS 端不需要改任何配置就能看到首屏延迟降下来,前提是播放器也用低延迟模式。
4. 避坑:ffmpeg-3.4-mingw32 编译和使用中的 5 个经典翻车现场
无论你是自己编译还是直接下载,只要接触 ffmpeg-3.4-mingw32,下面这几个问题几乎绕不开。它们不是某个人的环境特例,而是 32 位 MinGW 构建的普遍脾气。
4.1 configure 报错 Unknown option "--enable-libx264":拿错了包
现象:从某站下载 ffmpeg-3.4-mingw32.zip,解压后进入目录执行 ./configure --enable-libx264,立刻得到 Unknown option "--enable-libx264",然后退出。
原因:这份 zip 是预编译产物,目录里是 ffmpeg.exe 和一堆 dll,没有 configure 脚本和 Makefile。你是在要求一个已经编译完成的程序重新编译自己,configure 当然不认。很多新手把可用二进制包和源码包混为一谈。
解决:先确认目录结构。真正的 FFmpeg 3.4 源码包解压后一定能看到 configure 文件;预编译包只有 bin 目录或根目录直接放 exe。如果你只想当命令行工具用,直接跑 exe 即可;如果你要编译改造,去官方源码镜像下载 ffmpeg-3.4.tar.xz。为了避免二次犯,在终端里执行:
ls configure Makefile如果返回 No such file,就停止所有 configure 操作。
4.2 编译中 undefined reference:架构前缀混乱是最大嫌疑
现象:make 进行到链接阶段,报一堆 undefined reference to__imp__pthread_mutex_lock' 或 undefined reference toav_free',即使安装了 mingw-w64 包也依旧失败。
原因:绝大多数时候是打开了 MSYS2 的 MSYS 终端,而不是 MinGW32-bit 终端。MSYS 终端里 gcc 仍是 MSYS 的 64 位编译器,FFmpeg 3.4 的 configure 会据此生成目标文件,而依赖库又来自 i686,两边架构不一,链接器匹配不到符号。少数情况是少了 mingw-w64-i686-winpthreads 包,但架构错排在第一位。
解决:重新打开“MSYS2 MinGW32-bit”终端,先执行 which gcc,确认输出 /mingw32/bin/gcc,再在源码目录执行 make distclean,把之前生成的错误配置文件清掉,然后重新 configure。执行:
which gcc make distclean ./configure ...(按第 2 章参数)... make -j4如果你用的依赖包是从 x86_64 仓库装的,卸载掉并装 i686 版本。链接顺序问题也会产生 undefined reference,但通常在静态库链进 C 程序时才明显,编译 FFmpeg 本身时,架构错是最常见的。
4.3 运行 ffmpeg.exe 弹窗缺 libgcc_s_dw2-1.dll:运行时库被动态链了
现象:本机编译完 ffmpeg.exe 跑得好好的,把整个目录拷到客户的一台 Windows 7 机器上,双击后弹出找不到 libgcc_s_dw2-1.dll,程序立刻退出。
原因:MinGW 的 gcc 默认把异常处理运行时库作为动态库链接,exe 在被编译机器能找到是因为 MSYS2 的 /mingw32/bin 就在 PATH 里;换一台干净机器就没有了。libgcc_s_dw2-1.dll 是 32 位 MinGW 特有的 DWARF 异常处理运行时,后缀 _dw2 表明异常模型,64 位构建通常是 SEH,不会出现这个名字。
解决:编译阶段静态链 GCC 运行时。在 configure 命令行增加:
--extra-cflags="-static-libgcc" \ --extra-ldflags="-static-libgcc"然后再 make。如果已经编译好了不想重编,临时补救是把 /mingw32/bin/libgcc_s_dw2-1.dll 和 libwinpthread-1.dll 拷到 exe 所在目录,但这样发布包里多两个 DLL,迟早还要踩缺依赖的坑。验证是否静态成功:
objdump -p ffmpeg.exe | grep "DLL Name"输出里只要还有 libgcc 或 winpthread 字样,说明没静态干净,需要重来。
4.4 64 位程序调不了 32 位 dll:mingw32 的“32”是硬限制
现象:自己开发的 64 位 C# 程序通过 DllImport 调用 ffmpeg-3.4-mingw32 的 avcodec-57.dll,运行时报 BadImageFormatException,或者 Win32 错误 0x800700C1。
原因:PE 文件格式按 CPU 架构区分为 PE32(32 位)和 PE32+(64 位)。标题里的 mingw32 编出的 dll 是 PE32,Windows 加载器不允许 64 位进程装载它。这不是 FFmpeg 配置问题,而是操作系统层面的规则。
解决:如果主程序必须 64 位,只能换用 x86_64 工具链重新编一份 FFmpeg,或者找 x86_64 的预编译包;如果业务锁定 32 位插件,把主程序的平台目标设为 x86,让整个进程跑在 32 位模式。还有一种跨进程方案:写一个 32 位代理 exe 负责调用 FFmpeg,与 64 位主程序通过共享内存或 socket 通信。很多采集卡 SDK 就只能由 32 位进程加载,这时 ffmpeg-3.4-mingw32 反而是正确选择。别尝试 LoadLibrary 绕过,Windows 会直接拒绝并返回 ERROR_MOD_NOT_FOUND。
4.5 configure 崩溃在 C compiler test failed:路径、杀软和终端三连坑
现象:源码步骤都对,gcc 能编译 hello.c,但执行 configure 跑到 Checking for C compiler ... test failed,随后退出。
原因:三选一。源码放在带空格的路径,如 C:\Users\My Name\Downloads\ffmpeg-3.4,configure 生成的快速测试文件路径解析出错;Windows Defender 把 configure 释放到临时目录的可执行文件当成未知病毒删了;打开的是 MSYS 终端而不是 MinGW32 终端,gcc 指向错误。
解决:先把源码目录迁移到无空格路径,比如 C:\ffbuild\ffmpeg-3.4,重新解压。然后确认在 MinGW32-bit 终端里执行。最后,如果实时防护仍干扰,暂时关闭再 configure,成功后将整个 C:\ffbuild 目录加白名单。执行顺序建议:
cd /c/ffbuild/ffmpeg-3.4 which gcc echo $PATH ./configure ...echo $PATH 的输出里应包含 /mingw32/bin 且不包含 mingw64 的入口,这一步能暴露绝大多数环境问题。configure 成功后,再打开杀毒软件也不影响后续 make,因为 make 不再频繁生成一次性测试程序。
5. 进阶:验证构建并把它接进 32 位程序
5.1 验证构建参数:别只看 -version
最简单可靠的验证不只是 ffmpeg -version,而是 ffmpeg -buildconf。它会原样打印 configure 参数,确认 --enable-libx264、--target-os=mingw32 是否真的进入产物。再跑 5 秒测试转码,能暴露运行时的编码器异常:
ffmpeg -buildconf | grep -- "--enable-libx264" ffmpeg -i sample.mp4 -t 5 -c:v libx264 -an test.mp4如果 test.mp4 能正常生成,说明 libx264 被 ffmpeg-3.4-mingw32 正确接管;这一步比看任何 README 都有说服力。
5.2 把静态库接进 C 项目的最小骨架
FFmpeg 3.4 老 API 还在用 av_register_all(),这是新版本删掉的初始化入口。32 位进程内调用 libavformat 的最小编译骨架如下:
#include <stdio.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> int main(int argc, char **argv) { av_register_all(); AVFormatContext *fmt = NULL; if (argc != 2) return 1; if (avformat_open_input(&fmt, argv[1], NULL, NULL) < 0) { fprintf(stderr, "open failed\n"); return 2; } avformat_find_stream_info(fmt, NULL); for (int i = 0; i < fmt->nb_streams; i++) { printf("stream %d: codec_type=%d\n", i, fmt->streams[i]->codecpar->codec_type); } avformat_close_input(&fmt); return 0; }编译时链接顺序很关键,libavformat 依赖 libavcodec 和 libavutil,被依赖的库必须放在依赖者后面:
gcc -o probe.exe probe.c -I/usr/local/include \ -L/usr/local/lib -lavformat -lavcodec -lavutil -lmMinGW 链接器是单遍扫描,出现 undefined reference 时先看 -l 顺序,再补 -lws2_32 -lsec32。发布前用 strip --strip-unneeded probe.exe ffmpeg.exe,能去掉局部无用符号,体积更小且行为不变。我后来习惯把 configure 参数存成 build.sh,换机器后重编还能复现,少走很多弯路。希望帮到你。
本文还有配套的精品资源,点击获取