如果你准备使用VS编译FFmpeg,推荐使用vs2013并且参考其他文章,而不是按照以下过程使用vs2005去编译,因为本文只是记录在编译过程出现的问题和解决办法,因为使用vs2005编译ffmpeg实在是作死
安装依赖环境:
- 安装MSYS-1.0.11
- 安装pkg-config,将pkg-config.exe、libglib-2.0-0.dll拷贝到mysys的bin目录下
- 由于vs2005不支持c99,需要安装C99-to-C89 Converter & Wrapper
解压c99-to-c89-1.0.3.zip,将c99conv.exe、c99wrap.exe拷贝到mysys的bin目录下 - 安装make-3.81.exe,将make.exe拷贝到mysys的bin目录下
- 解压coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2,将其中的pr.exe拷贝到mysys的bin目录下
- 安装diffutils-2.8.7-1.exe,将将安装目录bin内的cmp.exe等拷贝到mysys的bin目录下
- 安装yasm,将yasm.exe拷贝到mysys的bin目录下
msinttypes-r26.zip包括c99的两个头文件inttypes.h,stdint.h,解压到目录"C:UsersmDownloadsmsinttypes-r26"
由于msvc不支持unix的unistd.h,所以需要自己手动编写一个unistd.h
编辑以下代码,保存为unistd.h,并且同样保存在"C:UsersmDownloadsmsinttypes-r26"
#ifndef _UNISTD_H #define _UNISTD_H #include#include #include #endif //_UNISTD_H
在configure中使用参数-I附加头文件目录"C:UsersmDownloadsmsinttypes-r26"
解压ffmpeg-2.4.tar.gz
到源码目录下,编辑configure文件
将
if [ -z "$cl_major_ver" ] || [ $cl_major_ver -ge 18 ]; then
cc_default="cl"
else
cc_default="c99wrap cl"
改为
if [ -z "$cl_major_ver" ] || [ $cl_major_ver -ge 18 ]; then
cc_default="c99wrap cl"
else
cc_default="c99wrap cl"
否则会有因为不支持c99语法而产生的报错
C:Program Files (x86)Microsoft Visual Studio 8VCINCLUDEio.h(224) : 参见“unlink”的声明
消息:“The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _unlink. See online help for details.”
libavformat/hdsenc.c(535) : error C2059: 语法错误 : “{”
libavformat/hdsenc.c(544) : error C2059: 语法错误 : “if”
libavformat/hdsenc.c(546) : error C2143: 语法错误 : 缺少“{”(在“->”的前面)
libavformat/hdsenc.c(546) : error C2059: 语法错误 : “->”
libavformat/hdsenc.c(548) : error C2143: 语法错误 : 缺少“{”(在“->”的前面)
libavformat/hdsenc.c(548) : error C2059: 语法错误 : “->”
libavformat/hdsenc.c(549) : error C2059: 语法错误 : “return”
libavformat/hdsenc.c(550) : error C2059: 语法错误 : “}”
libavformat/hdsenc.c(579) : error C2059: 语法错误 : “.”
libavformat/hdsenc.c(580) : error C2059: 语法错误 : “,”
libavformat/hdsenc.c(581) : error C2059: 语法错误 : “,”
libavformat/hdsenc.c(582) : error C2059: 语法错误 : “,”
libavformat/hdsenc.c(583) : error C2059: 语法错误 : “,”
libavformat/hdsenc.c(587) : error C2059: 语法错误 : “.”
libavformat/hdsenc.c(594) : error C2059: 语法错误 : “.”
make: *** [libavformat/hdsenc.o] Error 2
执行configure时不知道为什么没有检测到msvc,导致$libc_type没有正确赋值,导致编译链接报错,strtod.c、snprintf.c没有得到编译
error LINK2001:undefined reference to '_avpriv__strtod' error LINK2001:undefined reference to '_avpriv__snprintf'
手动去设置,在configure文件的
case $libc_type in
bionic)
add_compat strtod.o strtod=avpriv_strtod
;;
之前加上
libc_type_fix(){
pfx=$1
eval ${pfx}libc_type=msvcrt
# The MSVC 2010 headers (Win 7.0 SDK) set _WIN32_WINNT to
# 0x601 by default unless something else is set by the user.
# This can easily lead to us detecting functions only present
# in such new versions and producing binaries requiring windows 7.0.
# Therefore explicitly set the default to XP unless the user has
# set something else on the command line.
check_${pfx}cpp_condition stdlib.h "defined(_WIN32_WINNT)" ||
add_${pfx}cppflags -D_WIN32_WINNT=0x0502
}
libc_type_fix
在源码目录下libavformat/os_support.h中,将以下行注释,否则报lseek重定义错误
//# define lseek(f,p,w) _lseeki64((f), (p), (w))
在compatmsvcrtsnprintf.c中,注释
//#if defined(__MINGW32__) #define EOVERFLOW EFBIG //#endif
否则提示
error C2065:"EOVERFLOW";未声明的标识符
compatwindowsmakedef文件编辑,将
sed -e '/public symbols/,$!d' -e '/^ {1,}Summary/,$d' -e "s/ {1,}${prefix}/ /" -e 's/ {1,}/ /g' |
改为
sed -e '/public symbols/,$!d' -e '/^ {1,}Summary/,$d' -e "s/ {1,}${prefix}/ /" -e 's/ {1,}/ /g' |
否则sed报错,并且生成的def文件不完整:
sed.exe -e expression #1,char 1:unknow command :`C'
编译时用到User32.lib、Gdi32.lib库,创建库文件夹C:UsersmDownloadslib,加入Gdi32.Lib,并且在configure指定库目录,但是在链接过程出现
LINK: warning LNK4044: 无法识别的选项“/LC:UsersmDownloadslib";已忽略
原因是configure中指定库目录使用-L,这是mingw的用法,而对于msvc,应该是-LIBPATH:
还需要在libavdevicegdigrab.c中加入以下语句来调用库
#pragma comment (lib,"User32.lib") #pragma comment (lib,"Gdi32.lib")
否则出现以下报错
正在创建库 libavdevice/avdevice.lib 和对象 libavdevice/avdevice.exp gdigrab.o : error LNK2019: 无法解析的外部符号 __imp__EndPaint@8,该符号在函数 _gdigrab_region_wnd_proc@16 中被引用
对于mysys的启动,需要让其继承msvc的环境变量,才能够使用msvc的link.exe,cl.exe等工具。
首先对于mysys安装目录下的msys.bat文件加入以下内容
call "C:Program Files (x86)Microsoft Visual Studio 8VCvcvarsall.bat"
寻找以下行,取消注释(去掉rem)
rem setMSYS2_PATH_TYPE=inherit
在开始菜单中,找到vs的目录,启动Visual Studio 2005命令提示,并且在其中运行msys.bat来启动mysys,启动后,在mysys中输入
export PATH=/C/Program Files (x86)/Microsoft Visual Studio 8/VC/bin:$PATH
确保vs环境在系统变量前,则优先使用vs的link.exe,而不是mysys的link.exe(与编译链接无关的一个程序)
在mysys中,切换目录
cd /C/Users/m/Downloads/ffmpeg-2.4.tar/ffmpeg-2.4
执行configure
./configure --prefix=build_msvc --toolchain=msvc --enable-shared --disable-static --extra-cflags="-I/C/Users/m/Downloads/msinttypes-r26 -Dsnprintf=_snprintf" --extra-ldflags="-LIBPATH:/C/Users/m/Downloads/lib"
-Dsnprintf=_snprintf 定义宏snprintf=_snprintf,否则提示
error C4013:"snprintf"未定义,假设外部返回int
–enable-shared 是指定生成动态链接库,可以在编程中进行使用,否则编译出来只有单个的ffmpeg程序
若configure出现以下提示
c99wrap cl is unable to create an executable file. If c99wrap cl is a cross-compiler, use the --enable-cross-compile option. Only do this if you know what cross compiling means. C compiler test failed.
检查c99conv.exe、c99wrap.exe是否安装正确
configure会生成config.mak、config.h文件,编辑config.h
做如下修改,将0改为1,
#define HAVE_IO_H 1 #define HAVE_UNISTD_H 1
否则源文件不能相应头文件,导致提示
error C4013:"read"未定义,假设外部返回int error C4013:"write"未定义,假设外部返回int error C4013:"_lseeki64"未定义,假设外部返回int error C4013:"close"未定义,假设外部返回int
编译安装
make make install
若出现以下错误
CC libavdevice/alldevices.o make: *** [libavdevice/alldevices.o] Error 1
检查configure配置附加头文件目录是否正确,inttypes.h,stdint.h头文件是否在相应目录中
使用mysys2编译时,出现下面两个问题,使用mysys1.0.11可以避免
awk: 命令行:1: /including/ { sub(/^.*file: */, ""); gsub(//, "/"); if (!match($0, / /)) print "libavdevice/alldevices.o:", $0}
awk: 命令行:1: ^ 未结束的字符串
只能将condig.mak文件以下部分注释
#CCDEP=$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '/including/ { sub(/^.*file: */, ""); gsub(/\/, "/"); if (!match($$0, / /)) print "$@:", $$0}' > $(@:.o=.d)
而编译执行./compat/windows/makedef时mysys2由于参数过长,竟然不能解析所有输入的参数
问题就出在这里
for object in "$@"; do
if [ ! -f "$object" ]; then
echo "Object does not exist: ${object}" >&2
exit 1
fi
done
提示
Object does not exist: liba
对于makedef的参数,包含几百上千个.o文件名字,但是到libavcodec/mpegutils.o之后就截止了,后面就因为参数过长直接被舍弃,导致出现错误。而使用mysys1.0.11却可以编译通过
编译后的文件在build_msvc的bin目录下
总结:
- 极度不推荐使用vs2005编译ffmpeg,他不是干这个的。千万不要去尝试,由于不支持c99标准,编译时会出现各种奇怪的错误,就算编译出来,也不一定能用
windows还是得mysys+mingw编译ffmpeg最简单,不用做任何代码和编译脚本的修改。一次编译通过。如果考虑使用msvc编译出来的库具有pdb文件,可以进行调试,也要用vs2013以上的版本,支持c99标准,不会出现这么多问题 - 这篇文章的目的只是作为编译过程出现的问题的解决办法的参考
- 对于大型项目的编译,一般就是三种问题,依赖环境和环境变量的问题,编译配置文件和编译参数的问题,源代码本身相对于编译器的问题
- 对于vs2005,我不想用他再编译ffmpeg第二次。每次编译好不容易解决了一个问题,都以为终于要结束了。结果就是报出更多的问题,如果一开始就知道会出这么多问题,我是无论如何不会去这样做的
关于msvc编译ffmpeg,参考文章:
vs2013编译ffmpeg之一 概述
the official compilation guide on ffmpeg wiki
windows下用vs2010编译ffmpeg
vs2013编译ffmpeg之四十二 zvbi
Compiling FFmpeg with X264 on Windows 10 using MSVC



