简介:这套软件包是针对32位Windows环境预编译的FFmpeg 3.4版本,基于MinGW32工具链构建,目标用户是使用Qt或MinGW进行音视频开发的C/C++工程师,主要解决在Windows下快速获得解码、编码、转封装、滤镜处理与流媒体协议支持的问题。包内共170个文件,整体仅2.62MB,属于轻量级裁剪版本。文件构成方面,除107个h头文件用于API声明、21个c示例或源码文件、6个a静态库、6个dll动态库、6个lib导入库外,还包括def导出定义、pc的pkg-config配置、ffpreset滤镜预设、exe命令行工具以及Makefile和readme,适合作为二次开发的参考骨架,也可直接复制到Qt工程中使用。已有227人学习下载,对快速评估MinGW32环境下FFmpeg 3.4的接口组织方式有一定参考价值。如果希望在Qt中集成多媒体能力,可直接利用这套mingw32库连接头文件与链接库,省去自行交叉编译FFmpeg的繁琐流程;日常处理媒体文件时,也可调用自带exe完成格式转换、音频提取、HLS切片或RTMP推流等任务。由于包体紧凑,特别适合内存或磁盘空间受限的开发环境与学习场景。
1. ffmpeg-3.4-mingw32:还在用老版本的 Windows 转码,到底在坚持什么
手头一台 32 位 Windows 工控机,出厂快十年,内存 2GB,上面跑着采集卡配套的老驱动。每天要处理几小时监控视频:转码、抽帧、截片段。随便拿一个新版 ffmpeg 的 Windows 构建丢进去,双击直接提示"不是有效的 Win32 应用程序"。这就是 ffmpeg-3.4-mingw32 至今还有人惦记的原因:它是少数能在 32 位 Windows 上稳定跑完整转码链路的构建形态,一个 exe 拷进去就能干活,不依赖 Python 运行时,也不要求机器有 64 位系统。
这篇写给两类人。一类要在老旧设备、XP/7 的 32 位环境里部署视频处理任务的维护者,另一类是想把 ffmpeg 以 32 位静态库形式集成进 C 工程、又不想在新版本构建上折腾的开发者。下文会按"先捡现成 → 再自己编 → 运行时排查 → 工程集成"的顺序推进,最后给一个能直接省时间的截取技巧。你不需要事先精通 FFmpeg 源码,但最好会开命令行。
2. 先跑起来:拿到并验证一个可用的 ffmpeg-3.4-mingw32 构建
2.1 static 还是 shared:两种交付形态怎么选
拿到 ffmpeg-3.4-mingw32 这个名字时,第一件事不是解压,而是确认你要的是 static 还是 shared 构建。两者在部署方式上是完全不同的两种东西。
static 构建把 FFmpeg 的库全部编进了 ffmpeg.exe 一个文件,运行时不需要额外的 avcodec-57.dll、avformat-57.dll 之类的动态库。shared 构建则相反,exe 只有几十 KB,真正的逻辑都在一堆 dll 里,分发时必须把整套 dll 一起带走。
| 对比项 | static 构建 | shared 构建 |
|---|---|---|
| 文件组成 | ffmpeg.exe 单文件 | ffmpeg.exe + 多个 av*.dll + MinGW 运行时 dll |
| 部署成本 | 拷贝一个文件即可 | 目录里缺一个 dll 就启动失败 |
| 体积 | 通常几 MB,带外部编码器更大 | 全部文件合计比 static 略小 |
| 升级维护 | 想换功能必须重新编 exe | 替换单个 dll 就能升级组件 |
| 适用场景 | 交付到客户机器、离线环境 | 自己开发调试、多程序共享库 |
我的建议很直接:你要往别人机器上发,一律 static;只有你在本地做二次开发、需要同时让多个工具链复用同一套 FFmpeg 库时,才选 shared。32 位环境的机器普遍老旧,DLL 地狱带来的麻烦远大于省下的那点磁盘空间。
解压后先看目录结构。static 版通常只有一个 bin 目录,里面躺着 ffmpeg.exe。shared 版会有 bin 和 lib 两个目录,bin 里除了 exe 还有一堆 dll。看到 dll 文件名里的 57、55 这些数字,说明它确实是 3.4 时代生成的库,而不是某个新版伪装成旧版本。
2.2 快速验证:一条命令读出编译选项与可用编码器
拿到 exe 后,先别急着转视频,用三条命令确认它的真实身份。命令行进入 exe 所在目录,依次执行:
ffmpeg.exe -buildconf ffmpeg.exe -encoders | findstr /i x264 ffmpeg.exe -hwaccels-buildconf会打印出编译时的全部 configure 参数,比-version更彻底。你要重点看三处:--target-os=mingw32表示这是 32 位 Windows 目标;--arch=x86确认指令集是 x86;--enable-static或--enable-shared告诉你它是哪种形态。第二行的findstr /i x264是 Windows 下的过滤命令,如果输出里有一行带 libx264,说明这个构建集成了 H.264 编码器,后面转 MP4 就方便很多。-hwaccels列出可用的硬件加速方案,3.4 时代最常见的是 dxva2。
这里有个很容易犯的错:在 64 位 Windows 上,32 位 exe 同样能跑,但任务管理器里会标注"32 位"。别把 32 位构建当成坏文件,只要命令行能正常打印版本信息,它就能干活。
如果-buildconf里出现了你没见过的参数,不要慌。第三方构建往往会在官方基础上加一些自定义优化,比如--extra-cflags=-march=...。这类参数直接影响可移植性,尤其是-march=native,意味着这是编译机器专用的二进制,换台 CPU 可能直接崩溃。后面第 4 章会专门讲这个坑。
2.3 最小转码命令:把第一个文件跑通
验证完构建,用一条最保守的命令做实际转码,确认它能正常读写文件、驱动 CPU 跑满:
ffmpeg.exe -y -i input.avi -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 128k output.mp4参数含义:-y表示输出文件已存在时直接覆盖;-i input.avi指定输入;-c:v libx264选视频编码器;-preset veryfast是 x264 的速度档,压缩率低但转得快,适合先验证流程;-crf 23是质量系数,数值越小质量越高,23 是通用起点;-c:a aac把音频转成 AAC;-b:a 128k固定音频码率。
跑起来后日志里会滚动进度行,长这样:frame= 1234 fps= 120 q= 28.0 size= 5123kB time= 00:01:23.45 bitrate= 502.3kbits/s speed= 2.1x。frame 是已编码帧数,fps 是当前编码速度,time 是输入时间轴位置,speed 是相对实时的倍率。speed 大于 1 说明转码比播放快,小于 0.5 就要考虑是不是参数开太高了。
如果命令报Unknown encoder 'libx264',说明这个构建没集成 x264,要么换一个带 x264 的构建,要么回到第 3 章自己编一个。如果报Invalid argument或直接闪退,优先怀疑系统缺运行库,下一章逐个排查。第一次跑通后,再考虑调 preset、crf 和分辨率。
注意:输出文件路径里有空格时,必须用双引号把整个路径包起来,这是 Windows 命令行最基础的坑,ffmpeg 3.4 对引号的处理又格外敏感。
3. 自己编译:从 MinGW-w32 工具链到 ffmpeg-3.4 的完整构建
3.1 工具链选型与安装:为什么用 MinGW-w32 而不是 MSVC 或 Cygwin
现成构建不放心,或者需要裁剪出特定编码器组合时,就得自己编。编译 ffmpeg-3.4-mingw32 的核心,是先有一套能在 Windows 上生成 32 位原生程序的工具链。常见方案有三种,实际用下来差距很大。
用 MSVC 编 FFmpeg 不是不行,但要处理 yasm/nasm 汇编器、头文件差异、链接库命名规则,3.4 这个年代的源码对 MSVC 的兼容性远不如现在的新版本,折腾成本高。用 Cygwin 环境编出来的 exe 依赖 cygwin1.dll,目标机器上还得装 Cygwin 运行时,跟"拷一个 exe 就能跑"的诉求完全背道而驰。剩下最顺的是 MinGW-w32 工具链,它生成的是原生 Windows PE 可执行文件,不引入额外运行时,这正是标题里 mingw32 的含义。
标题里的 mingw32 指的是 32 位 Windows 目标,而不是某个具体工具链项目。通常使用前缀i686-w64-mingw32-的交叉编译器,i686表示 32 位 x86,w64是 MinGW-w64 项目名,但它同样提供 32 位目标。看到前缀里有 w64 别以为只能编 64 位,关键是看 i686 还是 x86_64。
编译可以在 Linux 上交叉生成,也可以在 Windows 本地做。Linux 下的安装最常见:多数发行版软件源里都有 i686 版 MinGW-w32 交叉工具链,装完直接验证版本:
i686-w64-mingw32-gcc --versionWindows 本地编译则推荐用带 i686 MinGW-w32 子系统的终端环境,安装工具链和汇编器:
pacman -S --needed mingw-w64-i686-toolchain mingw-w64-i686-yasmFFmpeg 3.4 的 x86 汇编优化依赖 yasm 或 nasm,不装的话 configure 会提示nasm/yasm not found or too old,然后禁用大部分汇编优化,转码速度肉眼可见地掉。装完后在终端里执行i686-w64-mingw32-gcc --version,能看到类似gcc version 12.x的输出,就说明工具链可用。这一步别跳过,很多"编译到一半报错"的问题,根源都是工具链没装全。
3.2 configure 参数怎么给:裁剪出一个够用的 ffmpeg-3.4-mingw32
FFmpeg 的编译灵魂全在 configure。不裁剪直接编,会得到一个大而全但编译时间按小时计的产物;裁剪太狠,又会在运行时发现缺了解析器、缺了协议。我给出一套验证过的裁剪思路,先确定你要的输入输出格式,再逐个开对应组件。
以下 configure 命令对应"读 AVI、写 MP4、带 x264 编码"的最小需求,同时禁用了播放器工具和文档:
./configure \ --target-os=mingw32 \ --arch=x86 \ --cross-prefix=i686-w64-mingw32- \ --prefix=/opt/ffmpeg-3.4-mingw32 \ --enable-static \ --disable-shared \ --disable-everything \ --enable-gpl \ --enable-libx264 \ --enable-encoder=libx264 --enable-encoder=aac \ --enable-decoder=h264 --enable-decoder=aac --enable-decoder=mpeg4 \ --enable-muxer=mp4 --enable-muxer=avi \ --enable-demuxer=avi --enable-demuxer=mov --enable-demuxer=flv \ --enable-protocol=file \ --enable-parser=h264 --enable-parser=aac \ --enable-filter=scale \ --disable-doc --disable-debug --disable-ffplay --disable-ffprobe这段命令的核心是--disable-everything先把所有组件关掉,再把需要的逐个打开。这样产物体积小、编译时间短,也避免把不需要的解码器带进交付物。几个关键参数的作用:--target-os=mingw32和--arch=x86告诉 configure 目标平台;--cross-prefix指定交叉编译器前缀,configure 会自动补全 gcc、ar、strip 等工具名;--enable-gpl是法律开关,libx264 是 GPL 协议,不开这个选项,configure 直接拒绝启用 x264;--enable-filter=scale是缩放滤镜,转码时几乎必用。
| 参数 | 作用 | 备注 |
|---|---|---|
| --disable-everything | 关闭所有组件 | 裁剪的起点,不开它直接编会非常慢 |
| --enable-libx264 | 启用 x264 外部库 | 需要先编好 x264,并配置 PKG_CONFIG_PATH |
| --enable-encoder=aac | 启用内置 AAC 编码器 | 免去外部 fdk-aac,省去 license 顾虑 |
| --enable-protocol=file | 启用本地文件协议 | 裁剪后必须手动开,否则读不到输入文件 |
| --disable-ffplay | 不编播放器 | 减少交付物数量 |
| --enable-small | 用空间换体积 | 需要更小时的补充选项 |
--enable-libx264是这条命令里唯一不能独立生效的项,它要求系统里先有 x264 的 32 位静态库。常见做法是先自己编一份 x264,再让 FFmpeg 通过 pkg-config 找到它:
tar xjf x264.tar.bz2 cd x264 ./configure --cross-prefix=i686-w64-mingw32- \ --host=i686-w64-mingw32 \ --enable-static --disable-cli \ --prefix=/opt/x264 make -j4 make install编译完 x264 后,回到 FFmpeg 源码目录,执行 configure 前先导出环境变量,让 FFmpeg 能找到 x264 的头文件和库文件:
export PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig ./configure \ --extra-cflags=-I/opt/x264/include \ --extra-ldflags=-L/opt/x264/lib \ ... # 其余参数同上这里最容易翻车的点在架构不匹配:x264 必须编成 i686 32 位版本,如果机器上之前编过 x86_64 版的 x264,FFmpeg configure 会报x264 not found using pkg-config,或者链接时报架构冲突。检查方法很简单:file /opt/x264/lib/libx264.a,输出里应包含i386字样,而不是x86-64。
如果不想碰 x264,也有替代路径:去掉 configure 里的--enable-libx264和--enable-gpl,视频编码器改用--enable-encoder=mpeg4,这是 FFmpeg 内置的 MPEG-4 Part 2 编码器,不需要外部库。代价是同样的码率下画质不如 H.264,文件体积也更大。某些场景下这是合法的取舍,比如目标播放器是老式硬盘播放器,只认 MPEG-4。
3.3 make、install 与产物整理:得到可分发的最小构建
configure 成功后,编译本身反而简单。执行:
make -j4 make install-j4表示 4 个编译任务并行,老机器上建议降到-j2,MinGW 交叉编译时每个编译任务的 gcc 进程吃内存不少,并行太多容易把内存占满导致编译进程被杀,而且这种被杀没有明显报错,只会看到 make 突然中断。make 执行完后再运行 make install,产物会按 configure 里的--prefix装到/opt/ffmpeg-3.4-mingw32目录下。
检查产物时注意,因为我们禁用了 ffplay 和 ffprobe,bin 目录下应该只有 ffmpeg.exe。这时先别急着拷走,在源码目录跑一次窥探依赖:
i686-w64-mingw32-objdump -p /opt/ffmpeg-3.4-mingw32/bin/ffmpeg.exe | grep "DLL Name"这条命令会列出 ffmpeg.exe 运行时依赖的所有 dll。-p表示显示 PE 文件头信息,grep "DLL Name"过滤出导入表。如果你编的是 static 版,输出应该只有KERNEL32.dll、msvcrt.dll这类 Windows 系统自带 dll;如果出现了libgcc_s_sjlj-1.dll或libwinpthread-1.dll,说明 gcc 的运行时库被动态链接了,分发时必须把这两个 dll 一起带上。在目标机器上缺这类 dll 时,双击 exe 会直接弹窗报错,很多"拷到别的机器就无响应"的问题都出在这一步。
如果要让产物彻底单文件化,编译链接阶段可以加-static-libgcc -static-libstdc++,或者 configure 时加--extra-ldflags=-static。前者只解决 gcc 运行时,后者会把所有能静态的库都静态进去。我一般倾向--extra-ldflags=-static,省心。
产物整理建议建一个干净目录,只放 ffmpeg.exe 和必需的 dll(如果有),然后在这个目录里重新执行第 2.3 节的最小转码命令做冒烟测试。测完确认没问题,再把它打成压缩包交付。这样能避免把开发机上 PATH 里的旧 dll 误当成产物的一部分。
4. 避坑排查:ffmpeg-3.4-mingw32 运行时的 5 个典型故障
4.1 运行时缺 dll 与"无法定位程序输入点"
现象:ffmpeg.exe 双击无反应,命令行运行时提示libgcc_s_sjlj-1.dll not found,或者更隐蔽的avcodec-57.dll 已加载,但找不到入口点 xxx。
原因:前者是 MinGW 运行时 dll 没跟着 exe 走,常见于把 static 版误认成单文件、实际编译时仍动态链接了 gcc 运行时;后者是 dll 混用,exe 是 A 构建编译的,目录里放的 avcodec-57.dll 却来自 B 构建,两边导出的符号表对不上。
解决:先确认 exe 到底依赖哪些 dll,用第 3.3 节的 objdump 命令列导入表,然后让所有 dll 与 exe 位于同一目录,并确保目录里没有第二份同名 dll。Windows 加载 dll 的搜索顺序是 exe 所在目录优先,把 dll 和 exe 放一起能规避大部分 PATH 污染。如果换了机器仍然报缺 dll,直接改用 static 构建或者链接时加-static,这是最彻底的后悔药。
4.2 32位进程的 2GB 内存上限与超大文件处理
现象:处理 4K 视频或超长视频时,ffmpeg 中途退出,日志尾部出现Cannot allocate memory,或者直接杀进程无任何输出。
原因:32 位进程在默认 Windows 配置下只有约 2GB 用户态虚拟地址空间。FFmpeg 3.4 做视频解码时,每个参考帧、每路输入输出缓冲区都在这个空间里分配,4K 单帧就接近 8MB,多参考帧加上 B 帧重排,再叠一个 scale 滤镜,字节数轻松涨到几百 MB。内存碎片一多,malloc 就失败。
解决:给这条转码任务限线程,-threads 2能明显降低峰值内存;减少滤镜链,能用-vf scale=...一次完成的不要拆成两步;长视频分段处理,例如用-t限制单次转码时长。如果目标机器是 64 位系统,可以在编译 32 位程序时加-Wl,--large-address-aware,让 32 位进程在 64 位系统上用到完整的 4GB 地址空间。但注意,在纯 32 位系统上这个标志没有作用,老 XP 机器别指望它。
4.3 中文文件名、带空格路径与参数编码问题
现象:ffmpeg -i 测试视频.avi out.mp4报No such file or directory,但文件名明明存在;或者输出文件名乱码,生成一堆看不懂的字符。
原因:这是 3.4 时代最折磨人的编码错位。Windows 命令行把参数按本地代码页(简体中文系统是 GBK/CP936)传给进程,MinGW 的运行时把 argv 转成宽字符后又转回 UTF-8 给 FFmpeg,而 FFmpeg 3.4 的 file 协议期望的是 UTF-8 路径。两端一交错,非 ASCII 字符就乱套。
解决:最稳的办法是绕开非 ASCII,在脚本里先把源文件重命名为纯英文名,处理完再改回来。也可以用 8.3 短路径规避,在命令行执行cmd /c for %I in (测试视频.avi) do @echo %~sI拿到短名,把短名传给 ffmpeg。别指望chcp 65001能彻底解决,ffmpeg 3.4 内部不跟随控制台代码页变化。这个问题到新版 ffmpeg 已用宽字符 API 解决,但 3.4 上它就是个硬限制。
4.4 编出来的 ffmpeg 没有 x264:外部库与 license 取舍
现象:自己编译时开了--enable-libx264,configure 阶段报错:ERROR: x264 not found using pkg-config;或者编译时没报错,运行时-c:v libx264却提示 Unknown encoder。
原因:configure 报错通常是 pkg-config 找不到 x264.pc,或者找到的是 64 位版本;运行时 Unknown encoder 则说明编出来的 ffmpeg 本身没带 libx264,可能 configure 阶段静默降级了——某些版本在外部库检测失败时会自动去掉该功能,而不是中断。
解决:编译前严格检查PKG_CONFIG_PATH指向的目录里有没有 x264.pc,并确认这个 pkg-config 文件里Libs:开头没有-Wl,--as-needed之类异常参数。交叉编译时如果用系统 pkg-config,它会去搜宿主机的/usr/lib/pkgconfig,几乎必然找不到 i686 的 x264。解决方法是设置PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig,必要时直接用i686-w64-mingw32-pkg-config。另外想清楚协议:x264 是 GPL,如果你交付的二进制对外分发,意味着你的产品得兼容 GPL;商用场景嫌麻烦,就用内置的--enable-encoder=mpeg4或--enable-encoder=h264加--enable-experimental顶一下,代价是画质和速度都差一截。
4.5 老版本不认新 CPU 指令集:在老旧 Windows 机器上崩溃
现象:在一个机器上编译的 ffmpeg-3.4-mingw32,拷到另一台更老的机器上,执行任何命令都秒退,或报Illegal instruction。
原因:构建时加了针对编译 CPU 的优化指令,比如--extra-cflags=-march=native或-msse4。FFmpeg 大量使用汇编优化,一旦运行 CPU 缺少对应指令集,解码器直接崩。这在"开发机很新、目标机器很老"的交付场景里极其常见。
解决:自编时不要添加任何-march=native之类的参数,让 configure 走默认的 i686 兼容路径。如果是第三方构建,看-buildconf输出里有没有可疑的-march或-mtune。最笨也最有效的验证方式,是在目标机器上跑一次ffmpeg -version,能出完整输出就说明基础指令集兼容。真需要为老 CPU 优化时,用--extra-cflags=-march=i586这类保守参数,为奔腾级别的老平台编译,比盲目用 native 稳得多。
5. 让它干活:在批处理脚本与 C 工程里用好这个 32位 ffmpeg
5.1 批处理脚本里的稳健调用:退出码、超时与并发控制
ffmpeg 单独跑能通,不等于脚本里能稳定跑。批处理里最常翻车的是误判成功、路径引号和并发挤爆内存。下面这个脚本能对目录下所有 avi 批量转码,并对失败文件单独记录:
@echo off setlocal enabledelayedexpansion set FFMPEG=ffmpeg.exe set SRC_DIR=D:\input set OUT_DIR=D:\output set ERR_LOG=D:\error.log for %%f in ("%SRC_DIR%\*.avi") do ( echo [INFO] processing %%~nf "%FFMPEG%" -y -i "%%f" -c:v libx264 -preset veryfast -crf 23 -c:a aac "%OUT_DIR%\%%~nf.mp4" if !errorlevel! neq 0 ( echo [ERROR] %%~nf failed with code !errorlevel! >> "%ERR_LOG%" ) else ( echo [OK] %%~nf done ) ) echo all jobs finished关键点在setlocal enabledelayedexpansion和!errorlevel!。for 循环括号体里如果用%errorlevel%,取到的是循环开始前的值,永远判断不出失败,必须用延迟展开语法!errorlevel!。%%~nf是 for 变量的扩展语法,取文件名去掉扩展名,用于拼输出路径。ffmpeg 路径和输入输出路径全部用双引号包裹,这个脚本路径里带空格也不会翻车。
这个脚本是串行执行,因为 ffmpeg-3.4-mingw32 单个实例在编码时能吃掉 200MB 以上内存,老机器上开两个实例就可能触发第 4.2 节的内存崩溃。真要提高吞吐,优先加-threads 2而不是开多进程。
批处理管不住超时。ffmpeg 偶发卡死在某个畸形文件上时,脚本会一直挂着。我一般用 PowerShell 做带超时保护的调用,WaitForExit等待指毫秒数,超时直接杀进程:
$p = Start-Process -FilePath "ffmpeg.exe" -ArgumentList "-y","-i","input.avi","-c:v","libx264","output.mp4" -PassThru -NoNewWindow if (-not $p.WaitForExit(900000)) { $p.Kill() Write-Host "timeout and killed" } else { Write-Host "exit code: $($p.ExitCode)" }ArgumentList这里特意一项一项逗号分隔,避免整个参数串里的空格被错误拆分。NoNewWindow让 ffmpeg 的日志直接打到当前控制台,方便监控进度。超时阈值按你的视频长度和机器性能调,一般 15 分钟足够。
5.2 在 32位 C/C++ 程序里静态链接 FFmpeg 3.4 库
另一类常见诉求是把 FFmpeg 3.4 的库直接链进自己的 Windows 32 位程序。静态链接的好处是交付物仍是单个 exe。下面是一个能打开视频文件并打印时长和格式的最小 C 程序:
#include <stdio.h> #include <libavformat/avformat.h> int main(int argc, char *argv[]) { AVFormatContext *fmt_ctx = NULL; int ret; if (argc < 2) { fprintf(stderr, "usage: probe <file>\n"); return 1; } /* 3.4 版本仍需要显式注册所有格式,4.0 之后才自动注册 */ av_register_all(); ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL); if (ret < 0) { fprintf(stderr, "open failed: %d\n", ret); return 1; } printf("format: %s\n", fmt_ctx->iformat->long_name); printf("duration: %lld seconds\n", (long long)(fmt_ctx->duration / AV_TIME_BASE)); avformat_close_input(&fmt_ctx); return 0; }编译命令的链接顺序是静态链接最常见的坑,被依赖的库必须放在依赖它的库后面:
i686-w64-mingw32-gcc -o probe.exe probe.c \ -I/opt/ffmpeg-3.4-mingw32/include \ -L/opt/ffmpeg-3.4-mingw32/lib \ -lavformat -lavcodec -lavutil -lswresample \ -lz -lpthread -lm -static-libgcc链接顺序上,-lavformat在前是因为它依赖-lavcodec和-lavutil;-lavutil被多个库依赖,必须排在最后面;-lz、-lpthread是 ffmpeg 在 Windows 下的传递依赖,漏了会报一堆 undefined reference。-static-libgcc防止生成对 gcc 运行时 dll 的依赖。如果还编了 x264,链接参数里得再加-lx264,并且 x264 库也必须是 i686 静态版,否则会链接出混架构产物。
如果想让你的 32 位程序在 64 位 Windows 上获得更大地址空间,编译时追加-Wl,--large-address-aware。这样 exe 的 PE 头里会标记 Large Address Aware,64 位系统上运行时能用到 4GB 用户态。但纯 32 位系统上不要依赖它,默认仍只有 2GB。
程序里av_register_all()是 3.4 的老规矩,漏掉它会导致avformat_open_input打开某些格式时找不到对应 demuxer,返回Unknown format。这个 API 在 4.0 后被移除,如果以后升级源码,记得删掉这行,否则编译直接失败。
6. 最后的进阶:用 -ss 提前定位和 -c copy 把转码时间砍一半
批量处理长视频时,最浪费时间的操作是把整个文件从头解码一遍,只为了取中间一分钟片段。FFmpeg 3.4 的-ss参数放在-i前和放在-i后,是两种完全不同的行为,这一点足够改变工作节奏。
放在-i之前是输入定位,ffmpeg 会先去视频流里找关键帧,直接从关键帧附近开始解码,速度快到几乎瞬间。配合-c copy不重编码,等于只做容器层面的切割。我处理监控视频惯用的快速预览命令是:
ffmpeg -ss 10:00 -i in.mp4 -t 60 -c copy out.mkv这条命令在 10 分钟处切出 60 秒片段,因为不做重编码,CPU 基本空闲,一个 2GB 的文件也是几秒完成。注意两点:输出用 mkv 而不是 mp4,因为老版本 muxer 对-c copy的 mp4 时间戳处理不够稳,切出来的 mp4 可能播放卡顿;切割点会落在关键帧上,所以实际起点可能比 10:00 早零点几到几秒,这在快速预览场景下完全可以接受。
要把-c copy换成重编码来精确定位,命令结构不变,但-ss仍放在-i前,让解码器先跳到目标区域,再从那里开始逐帧精确解码:
ffmpeg -ss 10:00 -i in.mp4 -t 60 -c:v libx264 -preset fast -crf 20 out.mp4这条命令比-ss放在-i后快得多,原因是它只解码目标区域附近的帧,而不会从文件头一路解到 10 分钟处。输出起点会非常接近 10:00,误差控制在单帧以内。我自己的习惯是先跑一条-ss在前加-c copy的快速命令,几秒钟拿到预览片段,确认时间点后,再决定是否用重编码命令做精修。这套流程帮我少等了无数次全量转码,尤其是面对几小时的监控录像时。
3.4 版本确实老了,新版本有更快的解码器调度、更完善的硬件加速和更好的 Windows 文件编码处理,但这些优势在 32 位老旧设备上都无从谈起。ffmpeg-3.4-mingw32 的意义不是"最新",而是在那条技术债务最深、最没人维护的设备线上,仍然能用一个静态 exe 把视频处理任务稳定跑起来。希望这篇能帮你把它的剩余价值榨干净,少踩几个我当年踩过的坑。
本文还有配套的精品资源,点击获取