简介:这是一份面向Windows 32位平台C/C++开发者的FFmpeg 4.3.1完整开发包,针对官方长期缺少win32位预编译SDK的痛点,由作者自行从GitHub拉取2021年1月19日最新源码编译而成,可直接用于音视频编解码、转封装、滤镜处理等项目的集成开发。压缩包共191个文件,约27.32MB,其中126个h头文件用于接口声明与开发引用,8个dll动态库及对应8个lib导入库、8个def模块定义文件、8个a静态库支撑链接与运行,另有3个exe可执行程序与30个html文档,覆盖avcodec、avformat、avfilter、swscale、swresample、avdevice、postproc等核心模块。目前已有853人学习下载,适合需要稳定win32位FFmpeg开发环境的中高级音视频工程师,省去自行交叉编译的时间成本,拿到即可对照头文件与库文件快速搭建工程并调试运行。
1. 拿到 ffmpeg-4.3-win32-gpl-shared 压缩包,先搞清楚它能干什么
如果你在 Windows 上做音视频开发,尤其是 32 位目标程序,大概率绕不开一个场景:编译好的 FFmpeg 动态库要么版本对不上,要么缺头文件,要么链接时符号找不到。这个ffmpeg-4.3-win32-gpl-shared-20210119.zip就是一份已经编译好的 Windows 32 位动态库分发包,GPL 授权,shared 模式,包含运行时的 DLL 和开发用的导入库、头文件。它解决的核心问题很直接:你不需要在 Windows 上从零搭 MSYS2 或 MinGW 环境去编译 FFmpeg,解压后配好路径就能在 C/C++ 工程里调用 libavcodec、libavformat、libswscale 这些库。适合谁?做 Windows 桌面播放器、转码工具、采集推流客户端,且目标架构是 x86 32 位的开发者。如果你做的是 64 位程序,这份包不适用,需要找 win64 版本。
2. ffmpeg win32 sdk dev 开发库的目录结构与链接方式
2.1 解压后你会看到什么
这个包解压后通常呈现三层结构,和官方 shared 构建的布局一致。先别急着写代码,把目录看清楚能省掉后面很多链接错误。
# 假设解压到 D:\ffmpeg-4.3-win32-gpl-shared D:\ffmpeg-4.3-win32-gpl-shared\ ├── bin\ │ ├── ffmpeg.exe │ ├── ffplay.exe │ ├── ffprobe.exe │ ├── avcodec-58.dll │ ├── avformat-58.dll │ ├── avutil-56.dll │ ├── swresample-3.dll │ └── swscale-5.dll ├── include\ │ ├── libavcodec\ │ ├── libavformat\ │ ├── libavutil\ │ ├── libswresample\ │ └── libswscale\ ├── lib\ │ ├── avcodec.lib │ ├── avformat.lib │ ├── avutil.lib │ ├── swresample.lib │ └── swscale.lib └── doc\bin目录里既有命令行工具也有运行时 DLL,include是开发头文件,lib里是导入库。注意这里的.lib是 MSVC 风格的导入库还是 MinGW 的.a,取决于构建方式。GPL shared 包通常同时提供.lib和.dll.a,或者只提供其中一种。你拿到包后先确认lib目录下的文件后缀,这决定了你用 MSVC 还是 MinGW 来链接。
2.2 在 Visual Studio 中配置头文件与库路径
假设你用 Visual Studio 2019 建一个 Win32 控制台工程,目标平台选 x86。配置分三步:头文件搜索路径、库搜索路径、附加依赖项。
// 示例:最简调用,验证链接是否通过 extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> } #include <iostream> int main() { // 打印 FFmpeg 版本,确认链接的是 4.3 分支 std::cout << "avformat version: " << avformat_version() << std::endl; std::cout << "avcodec version: " << avcodec_version() << std::endl; return 0; }这段代码只做一件事:调用avformat_version()和avcodec_version(),如果链接成功且运行时不缺 DLL,控制台会打印出版本号。逻辑说明:extern "C"是必须的,因为 FFmpeg 是 C 库,C++ 编译器需要知道不要做名称修饰。参数说明:avformat_version()返回一个整数,4.3 版本对应 libavformat 58.x,具体数值可以在version.h里查到。
配置路径时,在项目属性里找到「C/C++ → 常规 → 附加包含目录」,填入D:\ffmpeg-4.3-win32-gpl-shared\include。在「链接器 → 常规 → 附加库目录」填入D:\ffmpeg-4.3-win32-gpl-shared\lib。在「链接器 → 输入 → 附加依赖项」里加入avformat.lib; avcodec.lib; avutil.lib; swscale.lib; swresample.lib。顺序有讲究:avformat依赖avcodec,avcodec依赖avutil,所以avformat写在前面,avutil写在后面,否则 MSVC 链接器可能报符号未解析。
2.3 运行时 DLL 的放置与调试
编译通过不代表能跑。bin目录下的 DLL 必须和你的.exe放在同一目录,或者放在系统 PATH 能搜索到的路径。调试阶段我一般直接把bin目录加到项目属性的「调试 → 环境」里,写成PATH=D:\ffmpeg-4.3-win32-gpl-shared\bin;%PATH%,这样在 VS 里按 F5 就能直接跑,不用手动拷贝 DLL。
注意:如果你把 DLL 拷到
C:\Windows\System32,32 位程序要放到SysWOW64,但我不建议这么做,污染系统目录后面排查版本冲突会很痛苦。
3. 用 ffmpeg win32 sdk 做一次实际解码:从打开文件到取出一帧
3.1 解码流程的五个关键步骤
FFmpeg 解码有一套固定套路,4.3 版本仍然沿用旧版 API(avcodec_decode_video2在 4.3 里已标记废弃但还能用,新代码应该用avcodec_send_packet/avcodec_receive_frame)。下面这段代码演示打开一个视频文件,找到视频流,解码出第一帧的 YUV 数据。
extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> } int decode_first_frame(const char* filepath) { AVFormatContext* fmt_ctx = nullptr; // 1. 打开输入文件,分配格式上下文 if (avformat_open_input(&fmt_ctx, filepath, nullptr, nullptr) < 0) { return -1; // 打开失败,文件不存在或格式不支持 } // 2. 读取流信息,这一步会填充 streams 数组 if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { avformat_close_input(&fmt_ctx); return -2; } // 3. 找到第一条视频流 int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); if (video_idx < 0) { avformat_close_input(&fmt_ctx); return -3; } AVStream* vstream = fmt_ctx->streams[video_idx]; // 4. 根据流参数找到解码器并打开 AVCodec* codec = avcodec_find_decoder(vstream->codecpar->codec_id); if (!codec) { avformat_close_input(&fmt_ctx); return -4; } AVCodecContext* codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, vstream->codecpar); if (avcodec_open2(codec_ctx, codec, nullptr) < 0) { avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx); return -5; } // 5. 读包、发到解码器、收帧 AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); while (av_read_frame(fmt_ctx, pkt) >= 0) { if (pkt->stream_index == video_idx) { avcodec_send_packet(codec_ctx, pkt); int ret = avcodec_receive_frame(codec_ctx, frame); if (ret == 0) { // 成功拿到一帧,frame->data[0] 是 Y 平面,data[1] 是 U,data[2] 是 V av_packet_unref(pkt); break; } } av_packet_unref(pkt); } av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&codec_ctx); avformat_close_input(&fmt_ctx); return 0; }逻辑说明:avformat_open_input负责探测容器格式,avformat_find_stream_info会预读一段数据来确定编码参数,av_find_best_stream是 4.3 里推荐的找流方式,比手动遍历streams更省事。avcodec_send_packet和avcodec_receive_frame是 4.3 的新版解码接口,替代了旧的avcodec_decode_video2。参数说明:av_find_best_stream的第三个参数-1表示不指定期望的解码器,让 FFmpeg 自己选;第四个参数-1表示不关心关联流。avcodec_receive_frame返回 0 表示成功取到一帧,返回AVERROR(EAGAIN)表示需要继续送包。
3.2 编译时容易遇到的链接错误与解决
用 MSVC 编译上面这段代码,最常见的报错是LNK2019: 无法解析的外部符号 _av_...。原因通常是附加依赖项里库的顺序不对,或者漏掉了avutil.lib。另一个高频问题是LNK2038: 检测到 _ITERATOR_DEBUG_LEVEL 的不匹配,这是因为 FFmpeg 的.lib是 Release 模式编译的,而你的工程用了 Debug 模式。解决办法是把工程切到 Release,或者在 Debug 模式下也使用 Release 运行时库(项目属性 → C/C++ → 代码生成 → 运行时库 → 多线程 DLL (/MD))。
注意:如果你用的是 MinGW,
lib目录下应该是.dll.a文件,链接时写-lavformat -lavcodec -lavutil -lswscale,顺序同样重要。
4. 避坑:ffmpeg win32 sdk 开发库在 Windows 上的五个常见问题
4.1 现象:程序启动时报「找不到 avcodec-58.dll」
原因:运行时 DLL 不在可执行文件的搜索路径里。Windows 加载 DLL 的顺序是:exe 所在目录 → 系统目录 → PATH 环境变量。你编译时链接的是.lib,但运行时需要.dll,两者是分开的。
解决:把bin目录下所有 DLL 拷到你的.exe旁边,或者在调试环境里设置 PATH。我一般写一个copy_dlls.bat放在工程根目录,每次编译后自动拷贝。
@echo off set FFMPEG_BIN=D:\ffmpeg-4.3-win32-gpl-shared\bin copy /Y "%FFMPEG_BIN%\*.dll" "$(OutDir)"4.2 现象:avformat_open_input返回失败,但文件路径明明是对的
原因:路径里有中文或空格,而你的代码用了const char*直接传参。FFmpeg 在 Windows 上对 UTF-8 路径的处理取决于构建时的字符集设置,GPL shared 包通常按 UTF-8 处理,但 Windows 的fopen默认是 ANSI。
解决:把文件路径转成 UTF-8 再传进去,或者用avformat_open_input之前先SetCurrentDirectory到文件所在目录,传相对路径。更稳妥的做法是用avpriv_open的替代方案,但 4.3 里没有直接暴露,常见做法是用MultiByteToWideChar转宽字符后用_wfopen自己打开,再交给avformat_open_input的自定义 IO 回调。
4.3 现象:解码出来的画面颜色不对,偏绿或偏紫
原因:YUV 到 RGB 的转换矩阵用错了。FFmpeg 解码出来的是 YUV420P,如果你直接按 RGB 解释frame->data,颜色肯定错。另一个可能是sws_scale的色彩空间参数没设对。
解决:用sws_getContext时明确指定SWS_BILINEAR和正确的色彩空间。4.3 里推荐用sws_scale之前先查frame->colorspace,如果是AVCOL_SPC_BT709就按 BT709 转,否则按 BT601。
4.4 现象:链接时报LNK2001: 无法解析的外部符号 _avcodec_register_all
原因:4.3 版本里avcodec_register_all()已经被废弃了,虽然头文件里还有声明,但某些构建可能没有导出这个符号。你如果照着旧教程写,就会踩这个坑。
解决:删掉avcodec_register_all()和av_register_all()的调用,4.3 里不需要手动注册,avcodec_find_decoder会自动初始化。
4.5 现象:32 位程序在 64 位 Windows 上跑,内存不够用
原因:32 位进程的地址空间上限是 2GB(实际可用更少),解码 4K 视频时AVFrame和内部缓冲区很容易撑爆。
解决:如果目标平台必须是 32 位,尽量用av_frame_alloc后及时av_frame_unref,不要缓存太多帧。如果业务允许,换 64 位版本是更根本的解法。这份包只适合 32 位场景,别硬扛。
5. 进阶:用 ffmpeg win32 sdk 做硬件解码探测与性能验证
5.1 检查当前构建支持哪些硬件解码器
FFmpeg 4.3 在 Windows 上支持 D3D11VA 和 DXVA2 两种硬件解码方式。你拿到这份 GPL shared 包后,第一件事是确认它编译时有没有开--enable-d3d11va和--enable-dxva2。方法很简单,写一段代码遍历avcodec_find_decoder_by_name。
extern "C" { #include <libavcodec/avcodec.h> } void probe_hw_decoders() { const char* names[] = { "h264_d3d11va", "hevc_d3d11va", "h264_dxva2", "hevc_dxva2", "h264_qsv", "hevc_qsv", nullptr }; for (int i = 0; names[i] != nullptr; i++) { AVCodec* c = avcodec_find_decoder_by_name(names[i]); printf("%s: %s\n", names[i], c ? "available" : "not found"); } }逻辑说明:avcodec_find_decoder_by_name按名称查找解码器,如果返回非空指针说明这个解码器在编译时被启用了。参数说明:h264_d3d11va是 D3D11 硬件解码的 H.264 解码器名称,h264_qsv是 Intel Quick Sync 的。如果你的包是纯 GPL 构建,QSV 可能没开,因为 QSV 需要额外的授权组件。
5.2 用 ffprobe 验证包的完整性
在写代码之前,先用bin目录里的ffprobe.exe跑一下,确认包本身没坏。
D:\ffmpeg-4.3-win32-gpl-shared\bin\ffprobe.exe -v error -show_streams -select_streams v:0 test.mp4这条命令会输出视频流的编码参数、分辨率、帧率、像素格式。如果ffprobe能正常跑,说明 DLL 之间的依赖关系是完整的。如果报错「找不到 avutil-56.dll」,那就是bin目录不完整,需要重新解压。
5.3 性能验证:软解与硬解的帧率对比
我一般会写一个简单的计时循环,解码同一个 1080p 文件 100 帧,分别用h264软解和h264_d3d11va硬解,看耗时差异。硬解的关键是设置AVCodecContext的hw_device_ctx,4.3 里用av_hwdevice_ctx_create创建 D3D11 设备。
// 创建 D3D11 硬件设备上下文 AVBufferRef* hw_ctx = nullptr; int ret = av_hwdevice_ctx_create(&hw_ctx, AV_HWDEVICE_TYPE_D3D11VA, nullptr, nullptr, 0); if (ret < 0) { printf("D3D11VA not available, fallback to software decode\n"); } else { codec_ctx->hw_device_ctx = av_buffer_ref(hw_ctx); }参数说明:AV_HWDEVICE_TYPE_D3D11VA是设备类型,第三个参数指定设备名称,传nullptr表示用默认适配器。创建成功后把hw_device_ctx赋给解码器上下文,后续avcodec_receive_frame返回的frame->format会是AV_PIX_FMT_D3D11,需要再用av_hwframe_transfer_data把数据从 GPU 拷回内存才能做后续处理。
注意:硬解不是万能的,某些编码规格(比如 10bit HEVC)在旧显卡上可能不支持,创建设备成功不代表解码一定成功,还是要看
avcodec_receive_frame的返回值。
从那以后我每次拿到一份新的 FFmpeg 预编译包,都会先跑一遍ffprobe确认 DLL 完整,再写一个最小解码 demo 验证链接和运行时,最后才往正式工程里集成。这套流程帮我省掉了很多「编译通过但一跑就崩」的后悔药时间。希望帮到你。
本文还有配套的精品资源,点击获取