採用x264版本是x264-snapshot-20060316-2245。 數組
1. main函數 框架
x264的main函數位於x264.c中,下面是main函數調用狀況: 函數
(1)_setmode函數和_fileno函數 學習
這兩個函數是微軟提供的兩個庫函數。 ui
_setmode函數位於io.h文件中,主要做用是設置特定模式匹配的文件。http://msdn.microsoft.com/zh-cn/library/vstudio/tw4k6df8.aspx 編碼
_fileno函數位於stdio.h文件中,用於獲取文件流所對應的描述符。http://msdn.microsoft.com/zh-cn/library/vstudio/zs6wbdhx.aspx spa
下面的語句主要實現的是將Windows下默認的Text模式,按須要設置爲BINARY模式, .net
_setmode(_fileno (stdin ), _O_BINARY ); 命令行
還有一點,這個語句位於預編譯命令中,其中涉及到一個宏_MSC_VER。這個宏是VC編譯環境的預約義宏,主要是計算爲編譯器的主版本號和次版本號元素。 專業數字爲句點分隔的版本號的第一個元素,而且該次版本號是第二個元素。
所以,若是Visual C++編譯器的版本號爲15.00.20706.01,_MSC_VER 宏計算結果爲1500。在 Visual Studio 2010中,_MSC_VER 定義爲1600。http://msdn.microsoft.com/zh-cn/library/vstudio/b0084kay.aspx
_MSC_VER實際就是 Microsoft visual c++ version. 具體對應以下:
MS VC++ 10.0 _MSC_VER = 1600
MS VC++ 9.0 _MSC_VER = 1500
MS VC++ 8.0 _MSC_VER = 1400
MS VC++ 7.1 _MSC_VER = 1310
MS VC++ 7.0 _MSC_VER = 1300
MS VC++ 6.0 _MSC_VER = 1200
MS VC++ 5.0 _MSC_VER = 1100
其主要做用是實現版本判斷,從而實現兼容性控制. http://blog.csdn.net/stpeace/article/details/8282710
(2) x264_param_default 函數
這個函數用於對編碼器的一些參數進行默認設置。
(3) Parse函數
這個函數主要是進行命令行參數的解析工做。
(4) signal函數
這個是系統調用,用於設置中斷通知處理。本程序中主要是對Ctrl-C信號進行處理。
/* Control-C handler */
signal( SIGINT, SigIntHandler );
採用的處理函數爲SigIntHandler,即:
static void SigIntHandler( int a ) { if( b_exit_on_ctrl_c ) exit(0); b_ctrl_c = 1; } |
(5)Encode函數
這個函數就是x264具體進行編碼的函數。全部的編碼相關的都是在這個函數中完成的。
2. x264_param_default 函數
該函數的調用狀況以下:
這個函數完成參數的設置。全部的參數都是在x264_param_t這個結構體中有定義的。最早調用的memset函數就是對這個結構體進行初始化。
(1)x264_cpu_detect函數
這個是對編碼器所使用的cpu進行檢測,返回的是CPU的編號,主要做用是肯定CPU所支持的指令集,由於在x264中有不少代碼是直接採用彙編寫的。肯定了CPU的型號以後就能夠選擇相應的彙編代碼了。
在該函數中所調用的兩個函數x264_cpu_cpuid_test和x264_cpu_cpuid都是直接用匯編寫成的。
具體的對這個函數的註釋能夠看【X264中x264_cpu_detect函數註解】。
(2)x264_log_default函數
這個函數是爲了設置缺省日誌。其實這兒這是進行了函數指針的賦值:
/* Log */ param-> pf_log = x264_log_default ; param-> p_log_private = NULL ; param-> i_log_level = X264_LOG_INFO ; |
3. Parse函數
這個函數是對命令行參數進行分析,而後將給定的參數值賦值給x264_param_t結構體中相應的變量。
下圖是該函數的調用狀況,能夠看到涉及到了不少函數。
查看代碼能夠發現,其中有不少的函數並非直接調用,而是對一些全局的函數指針進行了賦值,即:
/* Default input file driver */ p_open_infile = open_file_yuv; p_get_frame_total = get_frame_total_yuv; p_read_frame = read_frame_yuv; p_close_infile = close_file_yuv;
/* Default output file driver */ p_open_outfile = open_file_bsf; p_set_outfile_param = set_param_bsf; p_write_nalu = write_nalu_bsf; p_set_eop = set_eop_bsf; p_close_outfile = close_file_bsf; |
具體是在for循環中進行的命令行解析。
其中包括了swtich語句,對分析出的參數進行相應的設置。
(1)getopt_long函數
linux下的命令行操做很是強大,而其中支持命令行的很重要函數就是getopt_long和getopt。這兩個函數都是用來對命令行進行解析。其函數調用以下:
調用的函數比較多。函數內部也挺複雜,再也不作分析。
(2)Help函數
很簡單,主要是打印出相應的幫助信息,即命令行參數的使用方式。
4. Encode函數
該函數完成對整個序列的編碼。其調用狀況以下:
(1)p_get_frame_total
用於計算序列中含有的幀的數目。
這是一個函數指針,具體應用中根據狀況選擇不一樣的函數:
A. get_frame_total_yuv:raw 420 yuv file
B. get_frame_total_avis:avs/avi input file support under cygwin
(2)x264_encoder_open
這個函數主要完成對編碼器的初始化配置。這個函數也是一個比較大的函數,調用了不少其餘函數。後面會有具體分析。
(3)p_set_outfile_param
設置輸出文件格式,這是一個函數指針,可選擇的包括mp4和mkv格式。
(4)x264_picture_alloc
這個函數主要是爲一幀圖像分配內存空間,因爲不一樣的顏色空間下,一幀圖像的大小是不同的,因此在這個函數中是按顏色空間的不一樣來進行區分的。
(6)x264_mdate
這個函數中獲取了系統時間。根據系統的不一樣,選用不一樣的系統調用來獲得當前時間。
int64_t x264_mdate ( void )
{
#if !(defined (_MSC_VER ) || defined( __MINGW32__))
struct timeval tv_date;
gettimeofday( &tv_date, NULL );
return( (int64_t) tv_date.tv_sec * 1000000 + (int64_t) tv_date.tv_usec );
#else
struct _timeb tb ;
_ftime(& tb);
return (( int64_t)tb .time * (1000) + (int64_t)tb .millitm ) * (1000);
#endif
}
(7)Encode_frame
在一個for循環中經過調用Encode_frame函數來完成對序列中每一幀的編碼。
經過調用p_read_frame所指向的函數來將所要編碼的當前幀讀入到所分配的空間中去。
Encode_frame函數是完成一幀編碼的重要函數,在後面詳細的分析。
當前幀編碼結束後,要進行nalu打包了。根據編碼時肯定的nalu個數,用x264_nal_encode進行打包。
這兒須要注意的一個問題是:在for循環以後有一個do-while循環再次調用Encode_frame來進行編碼。根據註釋/* Flush delayed B-frames */,這是和B幀相關的,因此在進一步查看編碼過程式時,要注意具體遇到B幀時是怎麼處理的。(這兒的合理解釋應該是在緩衝區中若是還有B幀須要編碼,就調用Encode_frame進行編碼。)
(8)x264_picture_clean
該函數就是釋放存放一幀圖像所申請的空間。
(9)x264_encoder_close關閉編碼器
該函數是對編碼進行收尾工做,輸出一些碼流相關信息,而且釋放編碼器開始時所申請的空間。
5. x264_encoder_open 函數
函數調用狀況以下:
能夠看到調用了不少函數。而且在該函數中設置了VUI高級編碼屬性。
(1)x264_malloc
x264_t 是一個比較大的結構體,用於保存X264編碼器在編碼過程當中所須要的維護的信息。x264_malloc函數完成對這個結構體空間的分配。
(2)x264_validate_parameters
該函數完成對命令行參數的檢查。
(3)x264_free
與x264_malloc相對應,釋放所分配的空間。
(4)x264_cqm_parse_file
該函數 解析量化矩陣配置文件。
(5)x264_sps_init
此函數爲序列量化集的初始化。主要對結構體x264_sps_t中參數的初始化。
(6)x264_pps_init
該函數完成對PPS參數的設置,其中大部分變量均可以在200503版標準7.4.2.2小節中找到相應的解釋。
(7) x264_validate_levels
主要是檢查變量的值是否合法,編碼標準中的level和profile。
(8)x264_cqm_init
完成量化矩陣的初始化。
(9)x264_macroblock_cache_init
這個函數主要對cache中與宏塊相關的變量進行初始化,包括爲它們分配對應的內存空間。
(10)x264_rdo_init
主要是進行RDO相關的初始化。
(11)x264_predict_16x16_init, x264_predict_8x8c_init, x264_predict_8x8_init, x264_predict_4x4_init
這些函數是對預測所使用到的函數進行初始化。後面在具體進行幀間預測的時候就會使用到。
x264_predict_t是一個函數指針類型,在代碼中對於不一樣的塊大小定義了相應的預測函數,即:
/* CPU functions dependants */
x264_predict_t predict_16x16[4+3];
x264_predict_t predict_8x8c[4+3];
x264_predict8x8_t predict_8x8[9+3];
x264_predict_t predict_4x4[9+3];
此處的4個函數就是對上面的四個函數指針數組進行賦值的:
/* init CPU functions */
x264_predict_16x16_init( h->param.cpu, h->predict_16x16 );
x264_predict_8x8c_init( h->param.cpu, h->predict_8x8c );
x264_predict_8x8_init( h->param.cpu, h->predict_8x8 );
x264_predict_4x4_init( h->param.cpu, h->predict_4x4 );
由於x264中對幀內不一樣塊大小所對應的預測模式都定義了相關的函數,因此這兒須要對相應的模式設定相應的預測函數。
(11)x264_pixel_init
這個函數也是對一些函數指針進行賦值。
這兒須要瞭解一下x264_pixel_function_t這個結構體:
typedef struct
{
x264_pixel_cmp_t sad[7];
x264_pixel_cmp_t ssd[7];
x264_pixel_cmp_t satd[7];
x264_pixel_cmp_t sa8d[4];
x264_pixel_cmp_t mbcmp[7]; /* either satd or sad for subpel refine and mode decision */
/* partial distortion elimination:
* terminate early if partial score is worse than a threshold.
* may be NULL, in which case just use sad instead. */
x264_pixel_cmp_pde_t sad_pde[7]; // No c Source code
} x264_pixel_function_t;
結構體中的原始都是函數指針數組。x264_pixel_cmp_t 和x264_pixel_cmp_pde_t 都是函數指針,從其成員變量的名字能夠發現這些函數指針主要是用於計算像素之間的差值,包括sad,ssd和satd等。
再回過頭來看x264_pixel_init函數能夠發現,該函數主要是對這些函數指針數組的賦值操做。而所賦的值固然是函數。不過這兒還有一些技巧:
PIXEL_SAD_C( pixel_sad_16x16 , 16, 16 )
PIXEL_SAD_C( pixel_sad_16x8 , 16, 8 )
PIXEL_SAD_C( pixel_sad_8x16 , 8, 16 )
PIXEL_SAD_C( pixel_sad_8x8 , 8, 8 )
PIXEL_SAD_C( pixel_sad_8x4 , 8, 4 )
PIXEL_SAD_C( pixel_sad_4x8 , 4, 8 )
PIXEL_SAD_C( pixel_sad_4x4 , 4, 4 )
因爲PIXEL_SAD_C是一個宏,這個宏的做用就是定義一些函數。從這兒所定義的函數名咱們應該能夠猜想到,這些函數就是對應於幀間預測時所須要的一些函數。
ps:這兒利用宏來定義的技巧能夠學習一下。
(12)x264_dct_init
相似上面的函數,主要是對與dct操做相關的函數指針進行賦值。
這兒涉及到的是x264_dct_function_t這個結構體。這個結構體的成員都是與DCT變換相關的一些函數指針,具體可見dct.h文件。
從下圖能夠看到具體調用的函數:
(13)x264_mc_init
完成運動補償相關函數指針的賦值,涉及到的結構體是x264_mc_functions_t,具體可見mc.h文件。
(14)x264_csp_init
這是不一樣顏色空間轉換相關的一些函數。結構體x264_csp_function_t中是相關的轉換函數指針。
pf->i420 = i420_to_i420;
pf->i422 = i422_to_i420;
pf->i444 = i444_to_i420;
pf->yv12 = yv12_to_i420;
pf->yuyv = yuyv_to_i420;
pf->rgb = rgb_to_i420;
pf->bgr = bgr_to_i420;
pf->bgra = bgra_to_i420;
帶顏色的函數都是直接定義的,而最後的三個函數則是利用宏來定義的。
(15)x264_quant_init
量化相關的函數設置。x264_quant_function_t結構體用於保存相關的函數指針。
(16)x264_deblock_init
設置與deblocking相關的函數。
(17)x264_ratecontrol_new
這是和碼率控制相關的函數。該函數建立碼率控制結構體並初始化。x264_ratecontrol_t是與碼率控制相關的結構體。
其調用x264_cpu_restore函數來恢復CPU的狀態。
這樣這個函數框架就分析完畢了。
6. Encode_frame函數解析
這個函數並非很長,主要調用了下面的函數:
函數中涉及到了兩個相關的結構體:x264_picture_t和x264_nal_t。x264_picture_t是存儲輸入/輸出圖像的結構體,x264_nal_t存儲編碼結束後的全部的nal包的信息。
根據該函數的代碼,能夠猜想其主要過程應該是先調用x264_encoder_encode對一幀圖像進行編碼,而且將編碼完成的碼率信息放入到nal列表中,而後調用x264_nal_encode對nal進行打包,最後調用p_write_nalu將碼率寫入文件。
(1)x264_encoder_encode
這是編碼的核心函數。
int x264_encoder_encode( x264_t *h,
x264_nal_t **pp_nal, int *pi_nal,
x264_picture_t *pic_in,
x264_picture_t *pic_out )
結構體*h中是編碼器相關的參數配置,**pp_nal主要用於存儲nal包,*pi_nal是nal包的個數,*pic_in和*pic_out是輸入和輸出圖像。注意pic_in的值是能夠爲NULL的。
這是一個大函數,後面有對其的詳細分析。
(2)x264_nal_encode
int x264_nal_encode ( void *p_data , int *pi_data , int b_annexeb, x264_nal_t *nal )
這個函數就是講nal中的數據根據H.264規定的格式進行打包,存儲在p_data指向的區域。其實主要是添加起始碼,NAL頭和類型信息
(3)p_write_nalu
該函數將打包完成的NALU寫入到文件中去。x264中給出了3種不一樣的類型文件:write_nalu_bsf,write_nalu_mp4和write_nalu_mkv。