- 一、 編譯環境
- 二、目錄結構
- 三、Configure指令
- configure參數說明
- 四、Configure調試
- 1、加列印的方法
- 2、條件執行
- 3、腳本列印行号
- 4、跟蹤腳本執行
- 5、enable子產品的檢測函數
- check_header/check_header_objcc
- check_lib/require
- require_pkg_config
- dumpbin
- 6、pkg-config
- 手動構造.pc檔案
- 五、yasm
- 六、頭檔案路徑
- 七、遇到的錯誤
- 1、LIBCMTD
- 2、缺少snprintf
- 3、缺少avpriv_snprintf
- 4、缺少useconds_t
- 5、__inline__
- 6、mingwex.lib
- 八、ShiftMediaProject
編譯ffmpeg主要是出于興趣,想研究一下ffmpeg和某些音視訊codec格式。用Visual Studio編譯主要是單步調試友善。雖然對gdb很熟悉,也經常用gdb調試,但gdb指令行或內建了gdb的IDE如codeblock、eclipse等,都遠不如Visual Studio友善。gdb界面太不友好,而且需要對代碼比較熟悉才好調試。用codeblock、eclipse調試ffmpeg遇到過很多問題,與IDE自身有關系。最終選擇了Visual Studio,從使用效果來看,效率很高。
ffmpeg編譯分為兩步:
第一步:configure,主要的目的是産生config.mak,用于後面的編譯;
第二步:make,執行編譯過程,産生可執行檔案。如果enable的特性很少,編譯則很簡單。自己編譯時enable的特性比較多,後面的描述會比較長。
有關編譯ffmpeg依賴的第三方庫,請參考本部落格的vs2013編譯ffmpeg系列文章
一、 編譯環境
vs編譯ffmpeg的官方指導文檔請參考http://ffmpeg.org/platform.html#Native-Windows-compilation-using-MinGW-or-MinGW_002dw64。
編譯環境是win7 64位 + mingw/msys(32位環境) + vs2013,ffmpeg的版本是3.3,後面的描述基本上是基于這個環境。
mingw/msys一直是用的32位版本。在XP上編譯ffmpeg也使用了很長一段時間,最開始研究ffmpeg的時候還沒有msys2,由于沒有相關的需求,這個環境一直都沒有換。ffmpeg的configure檔案是個bash腳本,須在mingw/msys下面執行。好像沒有看到誰用cygwin來配合vs編譯ffmpeg。
msys.bat 比較靠前的位置需要加個語句:
這個指令的作用是準備vs2013的編譯環境,call了這個腳本後,msys才能找到vs2013的cl編譯器,vs2013編譯時用到的頭檔案路徑、庫檔案路徑也已經準備好了。
vs的版本包括vs2008、vs2010、vs2012、vs2013都用過。
不要試圖用vs2008、vs2010、vs2012來編譯ffmpeg,因為vs2012及以前的版本不支援c99文法,vs2013才開始支援。
ffmpeg裡面有很多代碼都是用c99文法規範編寫的,vs2012及以前的版本編譯時會報錯。曾用vs2010編譯ffmpeg用了很長時間,編譯的時候需要将代碼先轉換成c99的代碼,再用vs的cl.exe來編譯轉換後的代碼,搞起來比較麻煩,而且會有意想不到的問題。用vs2013來編譯ffmpeg問題則少多了。
編譯過很多ffmpeg的版本,包括1.0、2.x、3.0、3.2.2、3.3、3.4.2等,3.3用的時間比較長,後面都用這個版本來描述,可能會有部分描述是針對3.3以前的版本。
二、目錄結構
由于引用的第三方子產品比較多,改動也有點多,是以目錄結構要安排好才不會亂。後面的描述中的路徑可以參考下面的目錄結構描述。頂層目錄是ffmpeg_MSVC,如下圖所示,裡面有兩個目錄,contribute下面是ffmpeg所依賴的第三方源代碼,有80個左右的目錄,有的第三方源代碼依賴其他子產品,是以目錄比較多。MSVC_ffmpeg下面是不同版本的ffmpeg源代碼。
下面的這些目錄都用vs2013編譯過:
contribute下面分了兩個子目錄,MSVC下面的代碼都是ffmpeg所依賴的第三方子產品的源代碼。msys下面是用msys+gcc編譯ffmpeg時依賴的第三方子產品的源代碼,主要作用是在遇到錯誤用于對比。
ffmpeg-3.3源代碼目錄:
源代碼目錄下面增加了幾個目錄:
extra_lib:ffmpeg所依賴的msys/mingw的庫,有的庫可能是編譯老版本ffmpeg所需的,但沒有去掉。
inc:msys/mingw的頭檔案,或者是第三方子產品的頭檔案。有時候重裝了msys或在不同電腦上拷貝這個編譯環境,msys/mingw的頭檔案可能會不一樣,為了避免依賴msys/mingw的頭檔案,将用到的頭檔案直接放到ffmpeg裡面。最開始沒有意識到ffmpeg在configure、make的時候會引用msys/mingw的頭檔案,出現了很多問題,後來單獨建了這個inc檔案夾,不再依賴msys/mingw的頭檔案,問題就少多了。
msvc:vs2013的工程所在目錄,ffmpeg.exe等建了vs工程。
pc_files:ffmpeg在configure的時候會用到pkg-config,有的第三方子產品用vs2013編譯後沒有産生.pc檔案,需要自己手動構造,是以将需要用pkg-config檢測的第三方子產品對應的.pc檔案放到pc_files目錄下,這樣也可以避免在configure的時候到源代碼目錄下去搜尋.pc檔案。目前用到的.pc檔案有32個。
三、Configure指令
目前(20180620)所用到的configure指令如下,放在bash腳本檔案裡面執行的:
#!/bin/bash
binPrefix_D=vs2013_build
export PKG_CONFIG_PATH="$(pwd)/pc_files "
echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH
echo "==================== Start to build debug version ===================="
echo "1. configure ffmpeg first."
./configure --toolchain=msvc --prefix=./$binPrefix_D --extra-cflags="-Dsnprintf=_snprintf -MTd -Z7 -I ./inc \
-I ../../contribute/MSVC/faac-1.28/include \
-I ../../contribute/MSVC/lame-3.99.5/include \
-I ../../contribute/MSVC/x264-master/SMP/build_result/include \
-I ../../contribute/MSVC/libtheora-1.2.0alpha1/include \
-I ../../contribute/MSVC/openjpeg-1.5.1/libopenjpeg \
-I ../../contribute/MSVC/libogg-1.3.1/include \
-I ../../contribute/MSVC/libvorbis-1.3.4/include \
-I ../../contribute/MSVC/xvidcore/src \
-I ../../contribute/MSVC/opus-1.1/include \
-I ../../contribute/MSVC/libvpx-v1.3.0 \
-I ../../contribute/MSVC/openal-soft-1.15.1/include \
-I ../../contribute/MSVC/bzip2-1.0.6 \
-I ../../contribute/MSVC/x265_20160531/x265/source \
-I ../../contribute/MSVC/x265_20160531/x265/build/vc13-x86 \
-I ../../contribute/MSVC/libiconv-1.9.2/include \
-I ../../contribute/MSVC/libilbc-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/game-music-emu-master/vs2013_build/include \
-I ../../contribute/MSVC/soxr-0.1.2-Source/src \
-I ../../contribute/MSVC/gmp-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/zlib-1.2.8 \
-I ../../contribute/MSVC/libcdio-paranoia-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/libcdio-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/libcdio-master_20160630/SMP \
-I ../../contribute/MSVC/frei0r-plugins-1.5.0/vs2013_build/include \
-I ../../contribute/MSVC/gsm-1.0-pl13/inc \
-I ../../contribute/MSVC/opencore-amr-0.1.3/msys_build/include \
-I ../../contribute/MSVC/snappy_20160715/snappy/vs2013_build/include \
-I ../../contribute/MSVC/twolame-0.3.13/libtwolame \
-I ../../contribute/MSVC/vo-amrwbenc-0.1.3/msys_build/include \
-I ../../contribute/MSVC/WavPack_sources/Debug/include \
-I ../../contribute/MSVC/xavs-code_20160829 \
-I ../../contribute/MSVC/decklink/include \
-I ../../contribute/MSVC/xz-5.2.2/src/liblzma/api \
-I ../../contribute/MSVC/nvenc_5.0.1_sdk/Samples/common/inc \
-I ../../contribute/MSVC/chromaprint-1.3.2/src -DCHROMAPRINT_NODLL \
-I ../../contribute/MSVC/flite-2.0.0-release/msys_build/include \
-I ../../contribute/MSVC/libgcrypt-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/libgpg-error-master_20160630/vs2013_build/include \
-I ../../contribute/MSVC/CUDA_NVIDIA/include \
-I ../../contribute/MSVC/libxml2-2.9.1/include \
-I ../../contribute/MSVC/libcelt/msvc \
" \
--extra-ldflags="/NODEFAULTLIB:LIBCMT \
-LIBPATH:../../contribute/MSVC/lame-3.99.5/output/Debug \
-LIBPATH:../../contribute/MSVC/x264-master/SMP/build_result/lib/x86 \
-LIBPATH:../../contribute/MSVC/libtheora-1.2.0alpha1/win32/VS2010/Win32/Debug \
-LIBPATH:../../contribute/MSVC/openjpeg-1.5.1/bin/Debug \
-LIBPATH:../../contribute/MSVC/libogg-1.3.1/win32/VS2010/Win32/Debug \
-LIBPATH:../../contribute/MSVC/libvorbis-1.3.4/win32/VS2010/Win32/Debug \
-LIBPATH:../../contribute/MSVC/xvidcore/build/win32/bin \
-LIBPATH:../../contribute/MSVC/opus-1.1/win32/VS2010/Win32/Debug \
-LIBPATH:../../contribute/MSVC/libvpx-v1.3.0/Win32/Debug \
-LIBPATH:../../contribute/MSVC/openal-soft-1.15.1/Debug \
-LIBPATH:../../contribute/MSVC/bzip2-1.0.6/Debug \
-LIBPATH:../../contribute/MSVC/x265_20160531/x265/build/vc13-x86/Debug \
-LIBPATH:../../contribute/MSVC/zvbi-0.2.35/src/.libs \
-LIBPATH:../../contribute/MSVC/libiconv-1.9.2/lib \
-LIBPATH:../../contribute/MSVC/libilbc-master_20160630/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/game-music-emu-master/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/soxr-0.1.2-Source/msvc/Debug \
-LIBPATH:../../contribute/MSVC/gmp-master_20160630/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/zlib-1.2.8/contrib/vstudio/vc11/x86/ZlibStatDebug \
-LIBPATH:../../contribute/MSVC/libcdio-paranoia-master_20160630/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/libcdio-master_20160630/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/frei0r-plugins-1.5.0/vs2013_build/lib/ \
-LIBPATH:../../contribute/MSVC/gsm-1.0-pl13/lib \
-LIBPATH:../../contribute/MSVC/opencore-amr-0.1.3/msys_build/lib \
-LIBPATH:../../contribute/MSVC/snappy_20160715/snappy/vs2013_build/lib \
-LIBPATH:../../contribute/MSVC/twolame-0.3.13/win32/lib \
-LIBPATH:../../contribute/MSVC/vo-amrwbenc-0.1.3/msys_build/lib \
-LIBPATH:../../contribute/MSVC/WavPack_sources/Debug \
-LIBPATH:../../contribute/MSVC/xavs-code_20160829/build/win32/bin \
-LIBPATH:../../contribute/MSVC/xz-5.2.2/windows/Debug/Win32/liblzma \
-LIBPATH:../../contribute/MSVC/chromaprint-1.3.2/src/Debug \
-LIBPATH:../../contribute/MSVC/flite-2.0.0-release/msys_build/lib \
-LIBPATH:../../contribute/MSVC/libgcrypt-master_20160630/vs2013_build/lib/x86 \
-LIBPATH:../../contribute/MSVC/CUDA_NVIDIA/lib/Win32 \
-LIBPATH:../../contribute/MSVC/libxml2-2.9.1/lib \
-LIBPATH:../../contribute/MSVC/libcelt/Debug \
-LIBPATH:./extra_lib \
gcc.lib mingwex.lib \
" \
--enable-debug \
--enable-gpl --enable-version3 --enable-nonfree --enable-libmp3lame --enable-libx264 --enable-libtheora \
--enable-libopenjpeg --enable-libvorbis --enable-libxvid --enable-libopus --enable-libvpx --enable-openal \
--enable-runtime-cpudetect --enable-postproc --enable-avresample --enable-bzlib --enable-sdl \
--enable-libass --enable-libwebp --enable-libx265 --enable-libzvbi --enable-libfreetype --enable-fontconfig \
--enable-libspeex --enable-avisynth --enable-libilbc --enable-libfribidi --enable-libgme --enable-libmodplug --enable-libsoxr \
--enable-gnutls --disable-schannel --enable-gmp --enable-libssh --enable-libcdio --enable-libbluray --enable-opengl \
--enable-libmfx --enable-libopenh264 --enable-dxva2 --enable-zlib --enable-frei0r --enable-libbs2b --enable-libgsm \
--enable-libcaca --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-openssl --enable-libsnappy \
--enable-libschroedinger --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libwavpack --enable-libxavs \
--enable-libxavs --enable-libzimg --enable-libfdk-aac --enable-decklink --enable-nvenc --enable-gcrypt --enable-chromaprint \
--enable-libshine --enable-libtesseract --enable-libopencv --enable-opencl --enable-cuda --enable-cuvid
configure參數說明
export PKG_CONFIG_PATH**="$(pwd)/pc_files "
:定義.pc檔案的搜尋路徑,pack-config會用到(請參考後面的内容)。Ffmpeg所依賴的第三方子產品的.pc檔案都放在目前目錄下的pc_files檔案夾裡面。
--toolchain=msvc
:指定用vs的編譯器,configure裡面搜尋msvc可以找到有關cl.exe編譯器的檢測代碼。
--prefix=./$binPrefix_D
:make install的時候會用到這個路徑,make完後執行make install可以将庫檔案、頭檔案拷貝到這個目錄下。
--extra-cflags="”
:configure會将這裡面的标志放到config.mk的CFLAGS變量裡面,make的時候會用到CFLAGS定義的标志。
--extra-ldflags="”
:configure會将這裡面的标志放到config.mk的LDFLAGS變量裡面,連結時會用到LDFLAGS定義的标志。
-Dsnprintf=_snprintf
:以前編譯的時候遇到過缺snprintf符号的問題,這個标志一直加在參數裡面了。
-MTd
:最開始編譯ffmpeg的時候選擇了這個參數,後面一直使用。需要注意的是,ffmpeg的庫用這個标志編譯後,引用ffmpeg庫的程式、ffmpeg庫依賴的第三方程式都需要用這個标志編譯。vs2013的工程屬性裡面有設定:Project properties->Configuration properties->C/C++->Code generation->Runtime Library改成Mtd。
-Z7
:調試資訊的格式。這個好像也需要統一設定,即ffmpeg庫、引用ffmpeg庫的程式、ffmpeg庫依賴的第三方程式都要用-Z7編譯。
-I
:(大寫的i,include中的i)後面是頭檔案路徑。
頭檔案路徑沒有什麼特别的,多個頭檔案路徑格式如下:
--extra-cflags=" -I ./inc \
-I ../../contribute/MSVC/faac-1.28/include ”
/NODEFAULTLIB:LIBCMT
:經常遇到libcmtd和libcmt兩個庫相沖突的問題,直接在extra-cflags加上這個标志,忽略libcmt庫裡面的符号。
gcc.lib mingwex.lib
:msys+gcc編譯的第三方庫依賴于這兩個庫,有很多第三方軟體隻能用msys+gcc編譯,如chromaprint等。
-LIBPATH:path
:第三方庫檔案所在的路徑,連結的時候會搜尋這些路徑,直到找到每一個依賴的庫和符号。
庫檔案路徑格式如下:
--extra-ldflags="-LIBPATH:../../contribute/MSVC/lame-3.99.5/output/Debug \
-LIBPATH:../../contribute/MSVC/x264-master/SMP/build_result/lib/x86”
上面這個格式configure執行沒有問題,也可以得出正确的庫檔案路徑。但根據configure裡面的msvc_common_flags函數的” -L*)”規則,下面這種寫法才是正确的:
--extra-ldflags="-L../../contribute/MSVC/lame-3.99.5/output/Debug \
-L../../contribute/MSVC/x264-master/SMP/build_result/lib/x86”
有時間試一下這個寫法。.pc檔案裡面用的是這個-L的寫法。
--enable-xxx
:可以用configure –help檢視各個–enable-xxx的具體含義。
configure檔案本身的分析請參考雷神的部落格。
四、Configure調試
大部分軟體的configure執行分3個階段:
1、 檢測cpu類型、作業系統類型、編譯器所支援的參數、頭檔案等。
2、 分析configure所帶的enable參數,檢測所依賴的頭檔案和庫檔案。
3、 産生makefile。
經常遇到configure相關的問題,是以configure調試的方法比較重要。
1、加列印的方法
configure是個bash腳本,通常bash腳本加列印的方法:
echo “cflags_filter=$cflags_filter”
configure執行時的詳細列印在config.log裡面,遇到錯誤的時候可以打開這個檔案檢視具體是什麼錯誤。
2、條件執行
下面的語句會輸出第二個echo的列印,用這個方法可以跳過某些不想執行的語句。因為configure執行時間很長,在查問題的時候可以跳過某些語句,加快問題查找。
if [ true = true ] ; then
echo "==============true============"
else
echo "==============false============"
fi
“[”和”]”前後都需要空格。腳本會走第一個echo分支,将要略過的語句放在else分支裡面。
3、腳本列印行号
echo -n “line $LINENO ”
加在configure裡面,以檢測執行到哪行了。這個語句對makefile沒有作用。
4、跟蹤腳本執行
sh -x configure
這個是shell腳本通用的方法。“-x”選項使shell在執行腳本的過程中把它實際執行的每一個指令行顯示出來,并且在行首顯示一個”+”号。 “+”号後面顯示的是經過了變量替換之後的指令行的内容,有助于分析實際執行的是什麼指令。
5、enable子產品的檢測函數
大部分問題都出在–enable-xxx這個階段。檢測所依賴的第三方庫或頭檔案主要是下面這三類函數:
check_header/check_header_objcc
檢測頭檔案,這兩個函數在configure裡面都可以找到其定義。
比如configure參數裡面加了–enable-cuda,則對應的檢測規則是:
“#”号後面是注釋。從config.log裡面可以找到其檢測時的列印:
check_header cuda.h
check_cpp
BEGIN ./ffconf.MdbZVmyu.c
#include <cuda.h>
int x;
END ./ffconf.MdbZVmyu.c
cl -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS= …
即生成臨時檔案ffconf.MdbZVmyu.c(臨時檔案一般放在ffmpeg根目錄下),裡面隻包含兩條代碼:
#include <cuda.h>
int x;
然後用cl編譯ffconf.MdbZVmyu.c,編譯沒有報錯就檢測通過了。cl語句比較長,上面的cl語句沒有全部截出來。
check_lib/require
同時檢測頭檔案和庫檔案,require最終也是調用了check_lib函數。
比如–enable-gmp對應的檢測規則:
enabled gmp && require gmp gmp.h mpz_export libgmpd.lib
從config.log裡面可以找到其檢測時的列印:
require gmp gmp.h mpz_export libgmpd.lib
check_lib gmp.h mpz_export libgmpd.lib
check_func_headers gmp.h mpz_export libgmpd.lib
check_ld cc libgmpd.lib
check_cc libgmpd.lib
BEGIN ./ffconf.MdbZVmyu.c
#include <gmp.h>
#include <stdint.h>
long check_mpz_export(void) { return (long) mpz_export; }
int main(void) { int ret = ;
ret |= ((intptr_t)check_mpz_export) & xFFFF;
return ret; }
END ./ffconf.MdbZVmyu.c
cl -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS= …
./compat/windows/mslink /NODEFAULTLIB:LIBCMT …
即用cl檢測gmp.h頭檔案是否存在、檢測check_ mpz_export符号是否有定義,最後用./compat/windows/mslink進行連結,檢測libgmpd.lib是否存在、check_mpz_export是否有具體的實作。mslink是個腳本,裡面調用的是vs2013的連結器link。
require_pkg_config
這個函數通過pkg-config指令來檢測依賴的第三方庫。
如–enable-libass對應的檢測規則如下:
enabled libass && require_pkg_config libass ass/ass.h ass_library_init
從config.log裡面可以找到其檢測時的列印:
use_pkg_config libass ass/ass.h ass_library_init
pkg-config --debug --exists --print-errors libass
Option --debug seen
Option --exists seen
Option --print-errors seen
Path position of 'libass' is
Adding 'libass' to list of known packages, returning as package 'libass'
check_func_headers ass/ass.h ass_library_init …
check_ld cc …
check_cc …
BEGIN ./ffconf.MdbZVmyu.c
#include <ass/ass.h>
#include <stdint.h>
long check_ass_library_init(void) { return (long) ass_library_init; }
int main(void) { int ret = ;
ret |= ((intptr_t)check_ass_library_init) & xFFFF;
return ret; }
END ./ffconf.MdbZVmyu.c
cl -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS= …
./compat/windows/mslink /NODEFAULTLIB:LIBCMT …
pack-config加了–debug參數(列印比較多,上面沒有全部貼出來),即将configure裡面的check_pkg_config()語句:
改成:
dumpbin
dumpbin可以查符号表,對報缺符号的錯誤很有用:
dumpbin -SYMBOLS x265-static.lib #将x265-static.lib的符号都倒出來。
也可以檢視dll依賴:
dumpbin -DEPENDENTS ffmpeg.exe #可以看到ffmpeg.exe所依賴的dll檔案。
6、pkg-config
configure裡面對一些子產品的檢測都是用pkg-config來實作的,很多錯誤是在執行pkg-config的時候出現的,或者是由于其傳回的子產品的頭檔案或庫的路徑有問題而導緻configure失敗。
pkg-config的調試手段:
echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH 此指令可以檢查pkg-config目前的搜尋路徑,pkg-config會根據PKG_CONFIG_PATH所列的路徑來搜尋.pc檔案。Windows下的mingw環境裡面沒有這個環境變量,如果ffmpeg在configure的時候要使用.pc檔案,則需要手動指定.pc檔案的路徑。Linux下安裝了pkg-config後會設定這個環境變量,執行這個echo語句的時候會看到相應的路徑。
pkg-config加
--debug
參數可以看出其搜尋路徑,configure在檢查時執行類似于
pkg-config --exists --print-errors x264
的語句,在configure.log裡面可以看到。當出問題的時候,直接将此指令加上
--debug
參數看pkg-configd 執行過程和結果。
pkg-config –debug –exists –print-errors libwebp >= 0.2.0要改成
pkg-config --debug --exists --print-errors "libwebp >= 0.2.0"
才能在msys裡面執行,libwebp >= 0.2.0要加雙引号。
PKG_CONFIG_PATH環境變量裡面,路徑之間用冒号分割,冒号前後不能有空格。Windows+msys、linux下都是這個規則。
export PKG_CONFIG_PATH的語句寫法要注意,如果目前PKG_CONFIG_PATH變量為空,則直接寫成:
export PKG_CONFIG_PATH=$(pwd)/pc_files
如果目前PKG_CONFIG_PATH變量不為空,則可以寫成:
否則的話,當PKG_CONFIG_PATH為空時,”:”會作為路徑的一部分,pkg-config執行的報下面的錯誤:
路徑的最後多了個冒号,不知道msys裡面為何pkg-config識别不了,pkg-config版本是0.27.1。linux系統下的0.23版本則沒有此問題。
在msys下,PKG_CONFIG_PATH環境變量裡面,多個路徑用”:”分割, export語句格式如下:
--dont-define-prefix
來訓示不需要覆寫prefix變量。請參考後面的schroedinger編譯。
手動構造.pc檔案
一些直接用MSVC編譯的庫沒有産生.pc檔案,是以需要手動構造.pc檔案。其實很簡單,比如libwebp手動構造的.pc檔案:
prefix=../../contribute/MSVC/libwebp-
exec_prefix=${prefix}
libdir=${exec_prefix}/output/debug-static/x86/lib
includedir=${prefix}/src
Name: libwebp
Description: Libwebp
Version:
Libs: -L${libdir} libwebp_debug.lib
Cflags: -I${includedir}
主要有用的是Libs、Cflags兩個變量,為後續編譯指明頭檔案和庫檔案所在的位置。在執行ffmpeg的configure之前先将.pc檔案所在的路徑export出來,在ffmpeg-3.3目錄下面執行:
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$(pwd)/pc_files
注意,冒号前後不能有空格。
為了友善,直接将所有的.pc拷貝到ffmpeg-3.3下面的pc_files目錄下。
單獨驗證libwebp的時候可以用下面的指令:
五、yasm
彙編代碼的編譯需要用到yasm,采用的版本是yasm-1.2.0,官網上下載下傳的,編譯好了後各vs版本都可以用。在msys下編譯,解壓後的編譯方法:
./configure; make
中間沒有遇到錯誤。
yasm、vsyasm、libgcc_s_dw2-1.dll、libiconv-2.dll、libintl-8.dll
,放到C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin下面。後三個檔案在/MinGW/bin下面。
vsyasm.props、vsyasm.targets、vsyasm.xml
放到C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\BuildCustomizations下面,這三個檔案在yasm的源代碼下面。
編譯x265時的更新檔
yasm一直用的是1.2.0版本(x265 2.6之後的版本用的是nasm,為了編譯速度),此版本的yasm編譯x265的時候會異常退出,原因是裡面有個hash表定義的太小,需要打更新檔才能編譯x265。即yasm-1.3.0\modules\preprocs\nasm\nasm-pp.c裡面:
改成:
重新編譯yasm并生成yasm.exe,并替換掉C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin下面的yasm.exe。
yasm-1.3.0已經解決了這個問題。
六、頭檔案路徑
~ \MinGW\msys\1.0\win32、~ \MinGW\include目錄最好都注釋掉,否則configure的時候引用的頭檔案會在這些路徑下,所有的頭檔案都用VC自帶的、contribute\MSVC下面的第三方庫、ffmpeg-3.3\inc下面的。
同時要確定環境變量裡面沒有mingw、msys的頭檔案路徑,即在msys的終端下用export指令确認INCLUDE變量後面沒有相關路徑,不然也會出錯。
曾經遇到過’rint’ undefined的錯誤:
或者:
vf_hqdn3d.o_converted.c
libavfilter/vf_hqdn3d.c() : error C4013: 'lrint' undefined; assuming extern returning int
libavfilter/vf_hqdn3d.c() : warning C4133: 'function' : incompatible types - from 'const AVPixelFormat [20]' to 'const int *'
這個是因為config.h裡面有#define HAVE_LRINT 1,configure通過/mingw/include下面的頭檔案找到了rint。真正的rint在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\ math.h裡面。如果沒有檢測到rint的話,就有ffmpeg源代碼下面的libm.h裡面定義的rint。
七、遇到的錯誤
1、LIBCMTD
關于多線程庫,都統一用libcmtd,即編譯的時候加上/MTd,包括所有的外部庫、ffmpeg的源代碼等。
增加了
--enable-libfaac
後可能會出現下面的錯誤:
LIBCMTD.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook already defined in LIBCMT.lib(dbghook.obj)
LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype_l already defined in LIBCMT.lib(isctype.obj)
LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype already defined in LIBCMT.lib(isctype.obj)
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
ffprobe_g.exe : fatal error LNK1169: one or more multiply defined symbols found
make: *** [ffprobe_g.exe] Error
在configure的
--extra-cflags
參數裡面加上/NODEFAULTLIB:LIBCMT
下面的錯誤:
LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype_l already defined in LIBCMT.lib(isctype.obj)
LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype already defined in LIBCMT.lib(isctype.obj)
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
在configure的
--extra-cflags
參數裡面加上/NODEFAULTLIB:LIBCMT。
下面這個錯誤:
LINK : error LNK2001: unresolved external symbol _mainCRTStartup
silk_common.lib(NLSF_VQ_weights_laroia.obj) : error LNK2001: unresolved external symbol __RTC_CheckEsp
若庫用-MTd編譯的,但是源代碼沒有用此标志,則會報這個錯誤。源代碼和庫檔案都要采用一緻的标志位編譯。
Project properties->Configuration properties->C/C++->Code generation->Runtime Library改成Mtd
2、缺少snprintf
如果編譯的時候報缺少snprintf的錯誤,則在configure的時候,将
--extra-cflags
裡面加上-Dsnprintf=_snprintf。
3、缺少avpriv_snprintf
error LNK2001: unresolved external symbol _avpriv_snprintff
後來發現這個問題是configure的時候引用了/mingw/include裡面的頭檔案,ffmpeg-2.2的解決辦法:
avpriv_snprintf在compat\msvcrt\snprintf.c裡面,在configure裡面搜尋msvcrt或snprintf.o,這個在probe_libc裡面有相關的語句。在這個函數後面加個列印,将libc_type的值打出來,發現其值是mingw32,正确的值應該是msvcrt,這個比較關鍵,有段時間這個值錯了,導緻出現了很多問題。檢視probe_libc裡面mingw32的檢測條件是:
elif check_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" ||
check_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then
即存在頭檔案_mingw.h且頭檔案裡面定義了__MINGW_VERSION或定義__MINGW32_VERSION。是以在configure的參數裡面的頭檔案路徑裡面包含了_mingw.h。後來發現ffmpeg-2.2 /inc目錄下面有_mingw.h,去掉這個檔案重新configure就可以。但在編譯libavcodec/libxvid.c的時候需要getopt.h 和_mingw.h,編譯的時候又手動将_mingw.h改回來。
--enable-fontconfig
後,configure在檢查fontconfig的時候需要_mingw.h,是以直接把_mingw.h裡面的定義東東放到getopt.h裡面,并確定頭檔案搜尋路徑裡面沒有_mingw.h。
4、缺少useconds_t
configure的時候加上
--enable-libx264
後,就必須加上unistd.h,否則編譯avio.c的時候會報錯,編譯的時候也沒有顯示具體是什麼錯誤。unistd.h裡面用到了useconds_t,這個本來在下面的頭檔案裡面定義的:
x264沒有适配vs的編譯器,但能在msys環境下編譯,真正的types.h應該是H:\MinGW\include\sys\types.h,但vs的安裝目錄下也有types.h,在C:\Program Files\Microsoft Visual Studio 12.0\VC\include\sys下面。由于搜尋頭檔案時,系統頭檔案路徑(即vs安裝目錄下的)在其他頭檔案路徑的前面,是以編譯的時候會用vs下面的。是以這個問題的解決辦法是直接将定義:
typedef unsigned int useconds_t;
放到ffmpeg-3.3/inc/unistd.h裡面。
5、__inline__
vs的cl編譯器不認識__inline__,直接将unistd.h裡面的ftruncate相關定義注釋掉。
MSVC2013之前的版本都不支援inline關鍵字,編譯的時候需要加定義-Dinline=__inline。MSVC2013版本inline成了關鍵字,但好像和gcc的inline作用不一樣,下面這個錯誤需要将代碼當作C++來編譯,default配置編譯會有問題。
6、mingwex.lib
configure會檢查很多數學函數如roundf、sinf等,這些函數在mingwex.lib裡面,是以将mingwex.lib加到
--extra-ldflags
裡面,在configure的時候帶上
--extra-ldflags
參數。如果沒有檢查到這些函數,則會用ffmpeg自帶的。
加上mingwex.lib後編譯的時候會有下面的錯誤:
h:\mingw\msys\1.0\home\aa\ffmpeg_msvc\msvc_ffmpeg\ffmpeg-3.0\libavutil\x86/intmath.h(58) : error C4013: '_tzcnt_u32' undefined; assuming extern returning int
在mingw、msys的庫裡面沒有找到tzcnt_u32,MSVC下沒有搜尋。解決的辦法是直接在config.h裡面将HAVE_FAST_CLZ改成0,讓程式使用ffmpeg自帶的相關函數。每次configure都需要手動修改一下,沒有遇到這個錯誤就不用管。
mingwex.lib是拷貝了/MinGW/lib目錄下的,原名libmingwex.a,直接改名的,沒有用工具轉換。
MSVC2013+ffmpeg-3.0,報下面的錯誤:
LIBCMTD.lib(strtoq.obj) : error LNK2005: _strtoull 已經在 mingwex.lib(strtoumax.o) 中定義
LIBCMTD.lib(strtoq.obj) : error LNK2005: _strtoumax 已經在 mingwex.lib(strtoumax.o) 中定義
解決的辦法是将strtoumax.o從mingwex.lib裡面去掉,先用ar指令将/MinGW/bin/libmingwex.a裡面的strtoumax.o去掉,再重命名libmingwex.a為mingwex.lib,MSVC也可以直接連結.a檔案。
ar -d libmingwex.a strtoumax.o
如果_strtof也報重複定義,也是同樣的處理方法。
用MSVC2013編譯還需要去掉strtoimax.o,configure在檢測strtoll的時候報重定義。LIBCMTD.lib裡面有strtoll的實作,ffmpeg configure如果沒有檢測到strtoll則定義strtoll=_strtoi64(-D strtoll=_strtoi64)。
八、ShiftMediaProject
官網:https://github.com/ShiftMediaProject
這個上面提供ffmpeg及其依賴的第三方庫下載下傳,都是源代碼,而且裡面都有vs的工程。這上面本來有很多項目的(至少有5頁),2017年後删除了很多。
沒有用這上面的編譯方法,因為想更友善地enable ffmpeg的特性。有部分ffmpeg依賴的第三方庫是用的這個上面的。