Windows MinGW64环境下CMake构建FFmpeg C项目报错及优化咨询
Windows MinGW64下CMake构建FFmpeg 5.1 C项目的链接错误问题及优化需求
项目结构
ffmpeg-tutorial ├── include │ ├── libavcodec │ ├── libavdevice │ ├── libavfilter │ ├── libavformat │ ├── libavutil │ ├── libswresample │ └── libswscale ├── lib │ ├── pkgconfig │ ├── libavcodec.a │ ├── libavdevice.a │ ├── libavfilter.a │ ├── libformat.a │ ├── libavutil.a │ ├── libswresample.a │ └── libswscale.a ├── CMakeLists.txt └── main.c
CMakeLists.txt内容
cmake_minimum_required(VERSION 3.20) project(ffmpeg_tutorial) set(CMAKE_C_STANDARD 11) include_directories(include) link_directories(lib) add_executable(ffmpeg_tutorial main.cpp) target_link_libraries(ffmpeg_tutorial avformat avcodec avutil swscale swresample z bz2 iconv ws2_32 schannel kernel32 advapi32 kernel32 user32 gdi32 winspool shell32 ole32 oleaut32 uuid comdlg32 advapi32 )
main.c内容
#include <stdio.h> #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswresample/swresample.h" int main() { std::cout << "Hello, World!" << std::endl; std::cout << av_version_info() << std::endl; printf("ffmpeg version is %s\n", av_version_info()); // Open input file AVFormatContext *inputContext = nullptr; if (avformat_open_input(&inputContext, "input.mp3", nullptr, nullptr) != 0) { printf("Couldn't open input file\n"); return -1; } // Read input stream if (avformat_find_stream_info(inputContext, nullptr) < 0) { printf("Couldn't find stream information\n"); return -1; } // Get audio stream index int audioStream = -1; for (int i = 0; i < inputContext->nb_streams; i++) { if (inputContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audioStream = i; break; } } if (audioStream == -1) { printf("Couldn't find audio stream\n"); return -1; } }
FFmpeg编译步骤
- 安装MSYS2及MinGW64工具链:
pacman -S mingw-w64-x86_64-toolchain - 安装编译依赖:
pacman -S base-devel yasm nasm pkg-config - 编译静态FFmpeg:
cd ffmpeg ./configure --disable-shared --enable-static --arch=x86_64 --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --pkg-config-flags=--static --prefix=../ffmpeg-build make -j $(nproc) make install
链接错误信息
[ 50%] Building CXX object CMakeFiles/ffmpeg_tutorial.dir/main.cpp.obj [100%] Linking CXX executable ffmpeg_tutorial.exe D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: G:/cywen_private/cpp_projects/ffmpeg-tutorial/lib/libavformat.a(tls_schannel.o): in function `tls_write': D:\Msys64\usr\src\ffmpeg/libavformat/tls_schannel.c:563: undefined reference to `EncryptMessage' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: G:/cywen_private/cpp_projects/ffmpeg-tutorial/lib/libavformat.a(tls_schannel.o): in function `tls_read': D:\Msys64\usr\src\ffmpeg/libavformat/tls_schannel.c:441: undefined reference to `DecryptMessage' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: G:/cywen_private/cpp_projects/ffmpeg-tutorial/lib/libavcodec.a(mfenc.o):mfenc.c:(.rdata$.refptr.IID_ICodecAPI[.refptr.IID_ICodecAPI]+0x0): undefined reference to `IID_ICodecAPI' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: G:/cywen_private/cpp_projects/ffmpeg-tutorial/lib/libavcodec.a(tiff.o): in function `tiff_uncompress_lzma': D:\Msys64\usr\src\ffmpeg/libavcodec/tiff.c:577: undefined reference to `lzma_stream_decoder' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: D:\Msys64\usr\src\ffmpeg/libavcodec/tiff.c:582: undefined reference to `lzma_code' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: D:\Msys64\usr\src\ffmpeg/libavcodec/tiff.c:583: undefined reference to `lzma_end' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: G:/cywen_private/cpp_projects/ffmpeg-tutorial/lib/libavutil.a(random_seed.o): in function `av_get_random_seed': D:\Msys64\usr\src\ffmpeg/libavutil/random_seed.c:127: undefined reference to `BCryptOpenAlgorithmProvider' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: D:\Msys64\usr\src\ffmpeg/libavutil/random_seed.c:130: undefined reference to `BCryptGenRandom' D:/Msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: D:\Msys64\usr\src\ffmpeg/libavutil/random_seed.c:131: undefined reference to `BCryptCloseAlgorithmProvider' collect2.exe: error: ld returned 1 exit status mingw32-make[3]: *** [CMakeFiles\ffmpeg_tutorial.dir\build.make:95: ffmpeg_tutorial.exe] Error 1 mingw32-make[2]: *** [CMakeFiles\Makefile2:82: CMakeFiles/ffmpeg_tutorial.dir/all] Error 2 mingw32-make[1]: *** [CMakeFiles\Makefile2:89: CMakeFiles/ffmpeg_tutorial.dir/rule] Error 2 mingw32-make: *** [Makefile:123: ffmpeg_tutorial] Error 2
需求
- 解决上述链接错误
- 简化CMakeLists.txt中
target_link_libraries的冗长参数 - 获取该FFmpeg项目的优化建议
解决方案与优化建议
一、链接错误解决
错误源于缺少FFmpeg依赖的系统库和第三方库,需补充到链接列表中:
EncryptMessage/DecryptMessage:补充链接secur32IID_ICodecAPI:补充链接mfplat、mf(Media Foundation组件)lzma_*系列函数:补充链接lzma(或编译FFmpeg时加--disable-lzma关闭该功能)BCrypt*系列函数:补充链接bcrypt
临时修复的话,在原target_link_libraries末尾添加:
secur32 mfplat mf lzma bcrypt
二、简化CMake链接参数
利用FFmpeg编译时生成的pkgconfig配置文件,自动管理所有依赖,无需手动罗列库:
修改后的CMakeLists.txt:
cmake_minimum_required(VERSION 3.20) project(ffmpeg_tutorial C) # 明确指定C语言,避免编译混淆 set(CMAKE_C_STANDARD 11) # 指向本地FFmpeg的pkgconfig目录 set(ENV{PKG_CONFIG_PATH} "${CMAKE_SOURCE_DIR}/lib/pkgconfig") find_package(PkgConfig REQUIRED) # 检查所需FFmpeg组件 pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET libavformat libavcodec libavutil libswscale libswresample ) add_executable(ffmpeg_tutorial main.c) # 直接使用pkgconfig导入的目标,自动处理所有依赖 target_link_libraries(ffmpeg_tutorial PRIVATE PkgConfig::FFMPEG)
三、项目优化建议
- 文件一致性修复:main.c中混用了C++的
std::cout,要么将文件名改为main.cpp,要么替换为C语言的printf,避免编译语言混淆。 - FFmpeg编译裁剪:编译FFmpeg时只启用项目需要的功能,比如不需要网络/TLS可加
--disable-network,不需要Media Foundation可加--disable-mf,不需要LZMA可加--disable-lzma,减少库体积和依赖。 - 资源管理完善:代码中打开的
AVFormatContext未关闭,需在程序退出前添加avformat_close_input(&inputContext);避免内存泄漏。 - 错误处理增强:使用
av_strerror将FFmpeg错误码转为可读信息,比如:int ret = avformat_open_input(&inputContext, "input.mp3", NULL, NULL); if (ret != 0) { char err_buf[AV_ERROR_MAX_STRING_SIZE]; av_strerror(ret, err_buf, AV_ERROR_MAX_STRING_SIZE); printf("打开输入文件失败:%s\n", err_buf); return -1; } - 编译警告开启:添加编译警告参数,提前发现潜在问题:
target_compile_options(ffmpeg_tutorial PRIVATE -Wall -Wextra) - CMake规范遵循:避免使用
include_directories、link_directories这类全局指令,改用target_include_directories等目标级指令,符合现代CMake最佳实践。
内容的提问来源于stack exchange,提问作者flywen
相关产品推荐
相关产品推荐

