拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FFmpeg 3.4 MinGW32编译实战:从MSYS2构建到集成避坑指南

FFmpeg 3.4 MinGW32编译实战:从MSYS2构建到集成避坑指南 简介一款面向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-mingw32MSYS2 环境下 configure 与 make 的完整流程预编译的 ffmpeg.exe 虽然能转码但当你被要求“把这个链接到我们的 32 位采集卡 SDK 里”或者需要把 libx264 也编进去时预编译包就无能为力了。自己编译并不是玄学关键是把工具链、依赖库和 configure 参数搞对。我一般用 MSYS2 的 MinGW32 终端完成整套动作下面从装环境到生成静态库一步步说。2.1 为什么选 MSYS2 而不是 Cygwin 或裸 MinGWWindows 下能跑 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-osmingw32 和 --enable-libx264 为什么必须写对FFmpeg 的 configure 是整个编译成败的核心它不像普通 Makefile 直接开跑而是会做七十余项检测探测编译器、汇编器、库函数是否存在。标题里的 mingw32 最终就体现在两个开关上--archx86 和 --target-osmingw32。只有把这两个参数落到 configure 命令行生成的执行文件和库才是指定格式。./configure \ --archx86 \ --target-osmingw32 \ --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-osmingw32 是告诉 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-mingw32ffmpeg -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 crop640:360:120:80,scale640:360 \ -c:v libx264 -crf 23 -preset fast \ -c:a aac -b:a 96k -ar 44100 clip.mp4cropw:h:x:y 的四个参数分别是裁剪宽度、高度、左上角横坐标、左上角纵坐标。这里裁的是 640x360从源画面的 x120、y80 开始往右往下取。如果 xw 超过源宽度或者 yh 超过源高度FFmpeg 会直接报 filter: Invalid argument 并退出。这是 invalid argument 最典型的来源之一很多新手以为是文件损坏其实只是坐标计算问题。在滤镜链中 crop 之后接 scale是为了把裁剪出的分辨率输出到目标分辨率。scale640:360 在这里等于没变但如果裁剪出的是 641x361 这样的奇数尺寸裸的 libx264 会拒绝编码width not divisible by 2。所以建议裁剪宽高都用偶数或让 scale 用保证偶数的表达式ffmpeg -i in.mp4 -vf cropiw-200:ih-200:200:0,scaletrunc(iw/2)*2:trunc(ih/2)*2 out.mp4iw、ih 是滤镜输入宽度和高度200 表示往右上角靠scale 里 trunc(iw/2)*2 把宽度压成偶数。这个写法在批量处理不同分辨率源时尤其省心。crop 的参数是像素单位不是百分比需要换算若源是 1920x1080裁左上角 800x600就是 crop800: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 位 dllmingw32 的“32”是硬限制现象自己开发的 64 位 C# 程序通过 DllImport 调用 ffmpeg-3.4-mingw32 的 avcodec-57.dll运行时报 BadImageFormatException或者 Win32 错误 0x800700C1。原因PE 文件格式按 CPU 架构区分为 PE3232 位和 PE3264 位。标题里的 mingw32 编出的 dll 是 PE32Windows 加载器不允许 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.4configure 生成的快速测试文件路径解析出错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-osmingw32 是否真的进入产物。再跑 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换机器后重编还能复现少走很多弯路。希望帮到你。本文还有配套的精品资源点击获取
返回列表