在VC2010下編譯ffmpeg.c(版本2.1.4)

經過N天的折騰,今天終於把ffmpeg.c這個文件編譯過了,經試驗與官方的一致。下面總結一些要點如下:


1、從 http://www.ffmpeg.org/download.html
下載官方的ffmpeg原文件,這一堆原文件本質上是for linux的,而我並不是想編譯整個ffmpeg,我想要的只是其中的某些頭文件,以及步驟3中的那些源文件。


2、從http://ffmpeg.zeranoe.com/builds/ 
下載官方提供的for win32的頭文件和lib和dll。這裏我有點不解的是,此處的頭文件不全,這也是爲什麼我們需要第一步的原因。


3、 生成 config.h
這一步其實很折騰的,需要安裝mingw,msys,yasm等工具軟件,然後進入到mingw命令行下執行./configure命令,參數有點複雜要講就講遠了,看客需要自己百度。執行後會生成一個config.h文件。這個文件中定義了一堆開關宏用於指示你編譯時打開什麼選項。把下面兩個選項關閉:

#define CONFIG_AVDEVICE 0
#define CONFIG_AVFILTER 0


在config.h裏面加上
#define PRIu64       "I64u"
#define PRId64       "I64d"


4、新建vc2010 console空工程,把ffmpeg.h,ffmpeg.c,cmdutils.c,cmdutils.h,cmdutils_common_opts.h,ffmpeg_filter.c,ffmpeg_opt.c加到工程。因爲vc2010的c編譯器是老掉牙的C89標準,而ffmpeg用的是較新的C99標準,所以很多地方需要我們手工改代碼。
在工程中建一個include目錄,把第二步下載的那些頭文件放到這裏。在工程中建一個lib目錄,把第二步下載的那些lib文件放到這裏。還有dll文件,放到編譯時生成的debug和release目錄下


5、從mingw下複製inttypes.h到系統目錄下:C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include。如果你用的是VC2010以下的版本,還需要拷貝stdint.h這個文件。




6、 把.h裏的inline換成__inline

#if defined(WIN32) && !defined(__cplusplus)
#define inline __inline
#endif

project->[setting]->[c/c++]->Preprocessor definitions:編輯框裏輸入inline=__inline
解釋:inline在C99標準中是一個關鍵字,但是在C89中還不是,VC採用的是__inline,所以。。。。。。


7、試着編譯一次,會有很多錯誤,不急,我們慢慢來搞定它們。最低級的錯誤是找不到XXX.h文件,那麼你就到第一步下載的那一堆原碼中去找,然後拷貝到include下對應的目錄。


8、如果遇到winstock.h與win2def.h重定義報錯,說明你頭文件順序有錯,windows.h文件要放到winstock.h後面。


9、遇到有些函數找不到,可能是config.h中的開關宏的問題,試着打開或關閉之,比如
#define HAVE_LOG2 0
剛開始是1,導致找不到log2函數,改爲0就好了。


10、宏AV_TIME_BASE_Q是一個煩人的東西,它在avutil.h文件中,ffmpeg中太多地方使用它了,我們看看它的定義:
#define AV_TIME_BASE_Q          (AVRational){1, AV_TIME_BASE}
這顯然不符合VC的寫法,我採用這個辦法:在用到AV_TIME_BASE_Q 的地方,手寫AVRational r = {1,AV_TIME_BASE };,再用上這個r.


11、在文件ffmpeg_opt.c中,有const OptionDef options[] 這個數組的初值處理,主要是裏面的函數,參考ffmpeg_vc5的代碼,把每一行改成這樣:{ "f",  HAS_ARG | OPT_STRING | OPT_OFFSET,   { (void*)OFFSET(format) },
就是把原來函數的地方{.fun = xxx}改成 {(void*)xxx}。編譯通過了,常規的一些輸入參數都好用。
文件cmdutils_common_opts.h文件也一樣


12、還有一個在timestamp.h文件中定義了兩個C99標準的宏:
#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts)
#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb)
這兩個宏在VC2010中都是無法使用的,我嘗試了幾種變種的宏都沒搞定,最後我笨辦法,修改ffmpeg.c中所有用到的地方,把他們改爲先定義char數組,再直接使用av_ts_make_string函數或av_ts_make_time_string函數。


13、在ffmpeg_filter.c文件中也有一處難懂的C99語法,就是第一個函數choose_pixel_fmt,裏面有一個enum指針:
p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };
從沒見過這種用法,怎麼辦,改:
在函數開關定義:
const enum AVPixelFormat avp1[5] = { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };

const enum AVPixelFormat avp2[8] = { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
然後在使用的時候賦值:
p = avp1;


14、最後是引用lib文件:
#pragma comment(lib,"../lib/avutil.lib")  
#pragma comment(lib,"../lib/avcodec.lib")  
#pragma comment(lib,"../lib/avformat.lib")  
#pragma comment(lib,"../lib/avfilter.lib") 
#pragma comment(lib,"../lib/swscale.lib") 
//#pragma comment(lib, "../lib/SDL.lib") //編譯ffplay時需要
//#pragma comment(lib, "../lib/SDLmain.lib") //編譯ffplay時需要
#pragma comment(lib, "../lib/swresample.lib")
#pragma comment(lib, "../lib/postproc.lib")
#pragma comment(lib, "../lib/unistdd.lib")
#pragma comment(lib,"Psapi.lib")


15、到此,ffmpeg.exe應該可以編譯出來了。順便多講兩句,如果要編譯ffplay也差不多,但記得下載SDL的1.2.15版,我開始下載最新的2-2.0.1版本發現用不了。


先寫這麼多,以後想到了再添加。有問題請聯繫QQ4991464

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章