天天看點

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

  • 一、 編譯環境
  • 二、目錄結構
  • 三、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編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

下面的這些目錄都用vs2013編譯過:

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

contribute下面分了兩個子目錄,MSVC下面的代碼都是ffmpeg所依賴的第三方子產品的源代碼。msys下面是用msys+gcc編譯ffmpeg時依賴的第三方子產品的源代碼,主要作用是在遇到錯誤用于對比。

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

ffmpeg-3.3源代碼目錄:

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

源代碼目錄下面增加了幾個目錄:

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個。

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject
vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

三、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

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

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配置編譯會有問題。

vs2013編譯ffmpeg之一 概述一、 編譯環境二、目錄結構三、Configure指令四、Configure調試五、yasm六、頭檔案路徑七、遇到的錯誤八、ShiftMediaProject

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依賴的第三方庫是用的這個上面的。