iOS: FFmpeg編譯和使用問題總結
折磨了我近一週多時間的FFmpeg庫編譯問題終於解決了,必須得把這一段時間來遇到過的坑全寫出來。如果急著解決問題,編譯最新版本的FFmpeg庫請直接看第二部分,編譯較老版本(0.7)的FFmpeg庫請直接跳至第七部分,那裡有你想要的編譯指令碼,但別忘了抽空看看全文。
一、背景
網上有很多FFmpeg編譯配置的資料,大部分都是關於FFmpeg最新的版本(2.0)的,我一開始也想著編寫一個2.0版本的,可以放到接手的那個專案中,發現各種問題(無法快進,沒有聲音),再看一下程式碼一堆警告,原因很簡單,使用的FFMpeg庫太新了,很多介面變動了。由於手上沒有多少資訊,不知道那個專案使用的是哪個版本的FFmpeg庫,一點點找,終於知道原來使用的是0.7.x的。找到目標版本的FFmpeg本以為萬事大吉了,後來才發現原來這才是坑的開始,有歷經一系列磨難,最後終於把編譯問題解決了。
二、FFmpeg最新版本的庫編譯
FFmpeg最新版本的應該是2.1的,歷史版本詳見http://www.ffmpeg.org/releases/,在這個網站上我們可以下到所有歷史版本的庫。FFmpeg是一個跨平臺的用C語言寫成的庫,包含了編碼,解碼,色彩空間轉換等庫。編譯需要用到命令列,對於我們這些沒搞過後臺或者linux開發的指令碼知識欠缺的人來說的確算是一個挑戰。慶幸的是現在網路這麼方便,不會做問Google,很快就找到了一個在xcode5下一鍵編譯FFmpeg庫的指令碼。這個指令碼是個老外寫的,真心強大,從下載到編譯到構建最後的Fat庫一氣呵成。
指令碼地址: https://gist.github.com/m1entus/6983547
執行這個指令碼需要依賴一個庫Perl寫的指令碼,搜了一下網上目前編譯FFmpeg庫的帖子基本都會提到這個指令碼,指令碼地址如下: https://github.com/mansr/gas-preprocessor。
下載完這兩個指令碼後,編譯FFmpeg庫的準備工作就基本完成了,接著依次執行下面幾步:
1、拷貝gas-preprocessor.pl檔案到 /usr/bin目錄下。
2、修改gas-preprocessor.pl檔案的許可權
注:需要有讀,寫和執行的許可權。具體操作為,首先在命令列下進入/usr/bin目錄,然後執行chmod命令,如下圖所示:
3、切換build-ffmpeg.sh指令碼的目錄下,使用命令
sh build-ffmpeg.sh 執行該指令碼即可。
注: 1) build-ffmpeg.sh指令碼的父目錄的名字不能包括空格,否則可能導致構建失敗。
2) build-ffmpeg.sh指令碼中可以配置編譯的FFMpeg版本,以及使用iOS SDK的版本,如下圖所示:
該指令碼中預設採用的FFmpeg是2.0版本,使用iOS 7.0的SDK編譯,c語言編譯器採用clang,應用中可以根據實際專案需要選中不同的FFmpeg和iOS SDK版本。
根據上面的步驟看來,編譯工作也沒有什麼複雜的,為什麼我會說踩了很多坑呢?這個問題我會一點點兒解釋。
三、編譯較早期版本的FFmpeg本庫
第二部分中我們介紹了一個牛逼的指令碼,一鍵編譯,這給我們造成了一種錯覺,FFmpeg編譯不過如此嗎!如果我們嘗試一下把指令碼中的VERSION變成0.7試試,執行指令碼,發現編譯報錯。如下圖所示:
提示位置選項--disable-iconv,根據提示我們輸入./configure檢視所有可用選項。命令列下切換到實際的FFmpeg原始碼目錄下,檢視幫助如下圖:
我們可以看到很多選項,英語不難,就是有些選項描述的太簡潔了,所以實際使用時如果不確定的話,我們可以去問問google。
好了回過頭來看看這個configure檔案到底有什麼作用呢?
1、裁剪
我們知道FFmpeg庫是一個非常龐大的庫,包括編碼,解碼以及流媒體的支援等,如果不做裁剪全部編譯進來的話,最後生成的靜態庫會很大。實際使用中我們可能只想用到解碼(例如播放器),因此我們可以使用相關選項指定編譯時禁用編碼部分。當然我們還可以做進一步的裁剪,例如只開啟部分常用格式的解碼,禁用掉其他的解碼,這樣編譯出來的靜態庫將會更小。
要想裁剪,我們的先知道有哪些部分,使用下面的命令可以檢視FFMpeg庫支援的元件列表。
1
2
3
4
5
6
7
8
9
10
11
|
--list-decoders show all available decoders --list-encoders show all available encoders --list-hwaccels show all available hardware accelerators --list-muxers show all available muxers --list-demuxers show all available demuxers --list-parsers show all available parsers --list-protocols show all available protocols --list-bsfs show all available bitstream filters --list-indevs show all available input devices --list-outdevs show all available output devices --list-filters show all available filters |
我們可以根據實際需要把不用的部分都禁用掉,這樣編譯快,包也會比較小,常用的裁剪選項如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
--disable-doc
do not build documentation --disable-ffmpeg disable ffmpeg build --disable-ffplay disable ffplay build --disable-ffserver disable ffserver build --disable-network disable network support [no] --disable-encoder=NAME disable encoder NAME --enable-encoder=NAME enable encoder NAME --disable-encoders disable all encoders --disable-decoder=NAME disable decoder NAME --enable-decoder=NAME enable decoder NAME --disable-decoders disable all decoders --disable-hwaccel=NAME disable hwaccel
|
舉個例子,如果我們需要做一款本地視訊播放器,那麼我們可以使用如下配置:
當然你還可以根據幫助列表進行更細粒度的裁剪,例如只支援哪幾種格式的解碼等等。
2、指定編譯環境
FFMpeg作為一個跨平臺的庫,不同的平臺,不同的人的計算機上編譯器的路徑都可能不盡相同,所以我們需要為編譯指令碼指定編譯器的路徑。同事我們還可以指定其他編譯選項,如是否交叉編譯,目標平臺系統,CPU架構,需要依賴的其他庫的路徑已經指定是否禁用匯編優化等。
1
2
3
4
5
6
7
8
9
10
11
|
--enable-cross-compile assume a cross-compiler is used --sysroot=PATH root of cross-build tree --sysinclude=PATH location of cross-build system headers --target-os=OS compiler targets OS [] --cc=CC use C compiler CC [gcc] --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [] --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [] --arch=ARCH select architecture [] --cpu=CPU select the minimum required CPU (affects instruction selection, may crash on older CPUs) --disable-asm disable all assembler optimizations |
sysroot即iOS SDK的路徑,注意編譯真機版本的庫時需要使用iPhoneOS.platform中SDK的路徑,編譯模擬器版本的庫使用iPhoneSimulator.platform中SDK的路徑。target-os填寫darwin(蘋果系統的核心),arch可以根據具體的情況新增i386(模擬器),armv6,armv7等。cpu根據具體型別可填寫cortex-a8,cortox-a9,i386等。
3、指定靜態庫的安裝路徑
指定執行make install命令時編譯好的靜態庫和相關標頭檔案拷貝到的位置,即FFmpeg庫編譯後輸出的路徑。通常我們只需要設定“--prefix=PREFIX”選項即可。例如我們需要將最後生成靜態庫的路徑指向“build/armv7”下,則設定--prefix="build/armv7";
四、FFmpeg0.7版本庫一鍵編譯指令碼
通過第三部分的介紹,相信我們應該對FFmpeg的配置都有了一個初步的認識,我們再回到第三部分開始時我們執行build-ffmpeg.sh的碰到的問題,經過檢視configure的幫助,我們發現0.7這個版本的FFmpeg庫卻是沒有"--disable-iconv"選項。這個牛逼的指令碼是針對當前較新的FFmpeg庫寫的,在低版本中沒有一些配置選項也是正常。
下面給出經過修改後的指令碼,指令碼中對原先的指令碼進行了精簡,去掉了下載部分的程式碼。
#!/bin/sh ######################################################################## ##################### copyright by smileEvday ########################## ##################### smileEvday.cnblogs.com ########################### ######################################################################## # FFMpeg,SDK版本號 VERSION="0.7.4" SDKVERSION="6.1" #最低支援的SDK版本號 MINSDKVERSION="5.0" # 原始檔路徑 SRCDIR=$(pwd) BUILDDIR="${SRCDIR}/build" mkdir -p $BUILDDIR # 獲取xcode開發環境安裝路徑 DEVELOPER=`xcode-select -print-path` # 要編譯的架構列表 ARCHS="armv7 armv7s i386" for ARCH in ${ARCHS} do if [ "${ARCH}" == "i386" ]; then PLATFORM="iPhoneSimulator" EXTRA_CFLAGS="-arch i386" EXTRA_LDFLAGS="-arch i386 -mfpu=neon" EXTRA_CONFIG="--arch=i386 --cpu=i386" else PLATFORM="iPhoneOS" EXTRA_CFLAGS="-arch ${ARCH} -mfloat-abi=softfp" EXTRA_LDFLAGS="-arch ${ARCH} -mfpu=neon -mfloat-abi=softfp" EXTRA_CONFIG="--arch=arm --cpu=cortex-a9 --disable-armv5te" fi make clean # you can do any clip here ./configure --prefix="${BUILDDIR}/${ARCH}" \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffserver \ --enable-cross-compile \ --enable-pic \ --disable-asm \ --target-os=darwin \ ${EXTRA_CONFIG} \ --cc="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/usr/bin/gcc" \ --as="/usr/bin/gas-preprocessor.pl" \ --sysroot="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDKVERSION}.sdk" \ --extra-cflags="-miphoneos-version-min=${MINSDKVERSION} ${EXTRA_CFLAGS}" \ --extra-ldflags="-miphoneos-version-min=${MINSDKVERSION} ${EXTRA_LDFLAGS} -isysroot ${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDKVERSION}.sdk" make && make install && make clean done ######################################################################################################################## ##################################################### 生成fat庫 ######################################################### ######################################################################################################################## mkdir -p ${BUILDDIR}/universal/lib cd ${BUILDDIR}/armv7/lib for file in *.a do cd ${SRCDIR}/build xcrun -sdk iphoneos lipo -output universal/lib/$file -create -arch armv7 armv7/lib/$file -arch armv7s armv7s/lib/$file -arch i386 i386/lib/$file echo "Universal $file created." done cp -r ${BUILDDIR}/armv7/include ${BUILDDIR}/universal/ echo "Done."
注:由於FFmpeg庫比較陳舊,該指令碼使用xcode4.6下,編譯器為GCC,採用6.1的SDK進行編譯。如果你的機器上裝的同事安裝了xcode4.x和xcode5的話,可以在命令列下使用如下命令切換當前的預設編譯環境為xcode4.6即可:
設定好xcode的編譯環境以後,只需要將該指令碼拷貝到FFMpeg原始檔路徑下執行即可一鍵生成armv7,armv7s,i386以及合成後的全平臺庫。
五、如何使用以及編譯連結中可能遇到的問題
第四部分中我們對build-ffmpeg.sh的指令碼進行了修改和精簡後得到了build-ffmpeg0.7.sh,我們只需要執行該指令碼就可以一鍵完成FFmpeg 0.7版本庫的編譯工作了。編譯後我們得到的是lib目錄(包含所有生成的靜態庫)以及include目錄(包含相應的標頭檔案),使用時我們只需要將這些檔案新增到工程中即可。
問題到這裡似乎就全部解決了,如果順利的話,恭喜你,你可以直接使用了。
如果你跟我一樣的"不幸"的話,可能還會遇到一些其他問題。下面是我遇到的問題及解決辦法:
1、time.h重複問題
我們知道一般靜態庫都是搭配標頭檔案使用的,要在專案裡面使用FFmpeg庫,我們出了需要在xcode的build phases中新增靜態庫以外,還需要匯入該庫對應的標頭檔案。FFmpeg庫對應的標頭檔案有很多,通常會採用設定header search path的方式來匯入標頭檔案,這樣做有兩個好處: 第一可以避免對我們的工程結構造成干擾。第二可以在一定程式上降低標頭檔案衝突。
time.h衝突的問題就是屬於標頭檔案衝突,系統的標準庫中有time.h檔案,FFmpeg應該是在1.1之後也加入了一個time.h檔案,路徑為libavutil/time.h。所以如果你使用的是FFmpeg1.1之後的版本,那麼在使用中就可能會碰到標頭檔案衝突的問題。解決這個問題,網上流傳一個方法是修改FFmpeg庫中time.h檔案的名字,我覺得這太麻煩了,而且也容易出錯。後來檢視FFmpeg原始碼的時候偶然發現它自身內部引用這個time.h的時候都有帶一層父目錄,如#include "libavutil/time.h"。因此想是不是通過指定標頭檔案搜尋路徑就可以解決這個問題。
開啟工程設定頁面,搜尋header search path如下圖所示:
如果你的FFmpeg庫正好是放在當前的路徑下,且為了偷懶設定了遞迴包含標頭檔案的話,那麼你很可能就會遇到time.h衝突的問題。因為xcode工程預設的設定是優先查詢使用者路徑,編譯時FFmpeg中libavutil下的time.h就會優先被連結,從而導致不會再連結系統time.h檔案,最終導致編譯失敗。
解決這個問題有兩個辦法:
a、取消掉Header Search Paths中的遞迴引用。
b、設定Always Search User Paths為NO。
2、gcc c compiletest error問題
xcode5下面編譯FFmpeg都採用clang,同樣也會遇到類似問題。這個問題通常出現在配置檔案錯誤的情況下,一般都是gcc路徑錯誤,當然也可能是其他編譯引數錯誤問題。
出現這個問題我們應該首先檢查gcc的路徑是否正確,如果確認了指定路徑上存在gcc程式,但是還是報錯的,我們再去檢查當前要編譯的平臺和指定的gcc路徑是否一致,如果你使用iPhoneOS.platform下面的gcc去編譯i386平臺的庫那肯定是不會測試通過的。
3、C compiler test failed問題
編譯i386版本的FFmpeg庫和armv版本庫可能用到的引數不盡相同,例如我遇到這個問題,我的編譯選項中有一項如下:
--extra-cflags='-arch i386 -mfloat-abi=softfp -miphoneos-version-min=5.0'
在我確認其他引數(如cpu,arch)都正確的情況下,依然提示我們“C compiler test failed.” 後面緊跟著一句檢視config.log你可以得到更詳細的資訊,於是開啟該檔案,你可以在最開始的地方看到你的配置語句,如果是用指令碼,這塊兒會顯示最終解釋後(替換引數為真實值)的配置語句。然後緊跟著一堆具體的配置,通常哭啼的錯誤資訊會在該檔案的最末尾。我遇到的問題的資訊如下:
看到標紅的這個區域了沒有,提示“-mfloat-abi=softfp”選項不支援,刪掉該選項後,在執行時配置就通過了。其他配置問題,都可以通過檢視config.log來獲取更詳細的錯誤資訊。
4、由於未匯入libbz動態庫的問題
如果匯入FFmpeg庫了,並且配置了標頭檔案搜尋路徑,遇到"Undefined symbols for architecture armv7s: _BZ2_bzDecompressInit",如下圖所示:
這個問題是由於沒有匯入“libbz2.dylib”庫的原因,匯入庫即可解決該問題。
5、libavcodec/audioconvert.h標頭檔案缺失問題
不知道為什麼執行make install的時候libavcodec中的audioconvert.h怎麼沒有拷貝到include目錄下的libavcodec中去,檢視發現原來libavutil目錄下已經有一個audioconvert.h了。解決這個問題只需要從FFmpeg庫的libavcodec中拷貝audioconvert.h標頭檔案到include的libavcodec目錄中即可解決。
六、雜談
感謝我所遭遇的"不幸",如果當時接受的專案使用的最新版本的FFmpeg庫,我可能就直接執行一下那個牛逼的指令碼,然後一切就可以順順利利。如果真是那樣的話,我可能也就不會花時間去學習基本的指令碼知識,去了解FFmpeg庫的相關配置,這樣的結果就是下次當我中獎遇到FFmpeg庫編譯連結等問題時,只能束手無策。
說了這麼多,當我們使用一個技術的時候,不應該僅僅停留在會用的層次,花點兒時間瞭解一下背後的原理會更讓你對該技術有個更深的理解,多學,多看,多思考,最終會有有所收穫的。
七、編譯指令碼及參考資料
1、編譯指令碼
gas-preprocessor指令碼地址: https://github.com/mansr/gas-preprocessor
FFmpeg 2.x一鍵化編譯指令碼: https://gist.github.com/m1entus/6983547
FFmpeg0.7一鍵化編譯指令碼: https://gist.github.com/smileEvday/7565260
2、參考資料
模擬器與真機下ffmpeg的編譯方法(總結版)
http://www.cocoachina.com/iphonedev/toolthain/2011/1020/3395.html
編譯在ios4.3中使用的ffmpeg庫(轉)
http://www.cocoachina.com/bbs/simple/?t70887.html
Installing ffmpeg ios libraries armv7, armv7s, i386 and universal on Mac with 10.8
轉自:http://www.cnblogs.com/smileEvday/archive/2013/11/21/ffmpeg.html
相關文章
- iOS FFmpeg XCode編譯報錯問題 AVMediaTypeiOSXCode編譯
- Android編譯通過,執行編譯錯誤問題總結Android編譯
- Ffmpeg分散式影片轉碼問題總結分散式
- 交叉編譯-Mac環境使用NDK編譯FFmpeg編譯Mac
- 【FFmpeg】Windows下FFmpeg編譯Windows編譯
- ffmpeg iOS平臺編譯 指令碼註釋iOS編譯指令碼
- FFmpeg系列(一)-Mac環境下使用NDK編譯FFmpegMac編譯
- 【FFmpeg】Windows下64位ffmpeg編譯Windows編譯
- FFmpeg編譯Android使用的so庫編譯Android
- mac上編譯FFmpegMac編譯
- 安裝編譯ffmpeg編譯
- 編譯ROCKSDB總結編譯
- FFmpeg iOS 音訊開發的小總結iOS音訊
- Make編譯之編譯32bit ffmpeg編譯
- Latex — 寫作編譯過程中遇到問題記錄與總結編譯
- FFmpeg學習之一(FFmpeg原始碼編譯)原始碼編譯
- Fiddler 使用問題總結
- Rust 交叉編譯與條件編譯總結Rust編譯
- SPI編譯問題編譯
- perl 編譯問題!編譯
- jive編譯問題編譯
- 丁香園iOS電話面試問題總結iOS面試
- iOS 面試題總結iOS面試題
- 編譯器後端總結編譯後端
- springboot使用問題總結Spring Boot
- FFmpeg學習總結
- libmemcached編譯問題IBM編譯
- EBS form編譯問題ORM編譯
- c++模板類的使用,編譯的問題C++編譯
- Flutter 混合開發實戰問題記錄(四)編譯執行時問題的一些總結Flutter編譯
- iOS IAP應用內購詳細步驟和問題總結指南iOS
- 29.FFmpeg+OpenGLES+OpenSLES播放器實現(三.FFmpeg配置和編譯指令碼)播放器編譯指令碼
- 問題總結
- NDKr20編譯ffmpeg-4.2.2編譯
- android反編譯工具總結Android編譯
- iOS面試題總結(七)iOS面試題
- iOS面試題總結(三)iOS面試題
- iOS面試題總結(五)iOS面試題