轉自:http://alphamailpost.blog.163.com/blog/static/20111808120128111160728/
http://www.usr.cc/thread-52674-1-1.html
Main函數中包含三個函數:Init,Encode,Fini,分別用來初始化,編碼和編碼后內存處理。
Init:
I(1)X264_param_default: 參數初始化,包括:CPU,視頻參數,編碼參數,碼率控制參數,日志,分析參數和量化參數等。需要注意的是:
param->rc.i_qp_constant = 26; //量化步長;
param->b_cabac=0;// 關閉CABAC編碼;
param->analyse.i_me_method = X264_ME_DIA; // 菱形搜索
(2)x264_encode_open: 對不正確的參數進行修改,並對各結構體的參數和預測等需要的參數進行初始化。
x264_validate_parameters參數有效性檢驗
1. x264_cpu_num_processors:根據不同的系統確定使用的CPU個數
2. x264_clip3:取三者之間的最大值
Fini:
x264_picture_clean:釋放一副圖像所占內存
x264_encoder_close:計算每個宏塊的數量和其對應的PSNR值,刪除一些關鍵數據(包括幀的有關信息,量化矩陣和碼率控制信息)
/*率失真理論:對有損壓縮編碼下的失真和編碼性能之間的關系
碼率控制方法:利用半精度的SATD(sum of absolute transformed differrence)作為模式選擇的依據。SATD是將殘差經哈達曼變換4*4塊的預測殘差絕對值總和*/
Encode:
Efseek:重定位文件流上的內部位置指針
fread:從文件流中讀數據
x264_encoder_encode:
編碼時,維持着三個隊列:frame_next隊列(臨時緩存,幀類型沒確定,待編碼的幀隊列),frame_current隊列(按編碼順序排放,已經確定了幀的類型,正在編碼的幀隊列)和frame_unused隊列(空白隊列,將要編碼的幀放入該隊列)。
1.x264_reference_update:(更新參考幀隊列,若為B幀則不更新)將上一個參考幀放入參考幀隊列,並從空閑隊列中取出一幀作為當前參考工作幀;
2.x264_frame_pop_unused:(獲取一幀的空間fenc,用來存放待編碼的幀)若unused隊列不為空,則將取出的幀放入unused隊列(x264_frame_pop),否則,分配一幀空間(x264_frame_new);
3. x264_frame_copy_picture:將該幀圖像拷貝到fenc中
4.判斷是否需要進行邊界擴展(x264_frame_expand_border_mod16),不能被16整除的都需要進行擴展。
5.將fenc放入frame_next中(x264_frame_push)
6.如果用到半精度亮度塊,需要進行1/2像素擴展(x264_frame_init_lowres)
7.若frame.current[0]==NULL(當前隊列中沒有幀需要編碼)
I.若frame.next[0]==NULL,結束編碼(x264_encoder_frame_end)
II. 判斷幀類型(x264_slicetype_decide)
III.將幀類型確定的幀重新排列存放在frame.current隊列中
8. 調整當前隊列中幀的順序,開始編碼
9.對編碼之后的nal封裝成NAL單元(x264_nal_encode);
10.將NALU單元寫入輸出文件(p_write_nalu)
do_encode:
(1). 根據幀類型設置NAL的類型和優先級,若是IDR幀,則清空所有參考幀(x264_reference_reset)。
(2). 初始化參考隊列(x264_reference_build_list),list0 前向參考隊列,P幀參考;list1,后向參考隊列(B幀參考list0和list1)
(3). 碼率控制初始化(x264_ratecontrol_start),得到該幀所使用的量化步長QP(x264_ratecontrol_qp)
(4). 創建片頭數據(x264_slice_init)
(5). 初始化比特流(bs_init)
(6). 當前幀為IDR幀時,NAL單元更新SPS(x264_sps_write)和PPS(x264_pps_write)
(7). 寫片操作,返回編完一幀之后的比特流(x264_slices_write)
(8). 恢復CPU狀態(x264_cpu_restore)
(9). 若幀類型是P幀,分別計算幀內編碼開銷和幀間編碼開銷,若幀間>幀內,則將P幀重新按I幀進行編碼(若圖片組的大小>=最小關鍵幀的個數,則按IDR幀編碼)。
(10). 編碼結束(x264_encoder_frame_end)
x264_slices_write:
1. 幀內幀間編碼(x264_slice_write)
2. 去塊濾波(x264_fdec_filter_row)
x264_slice_write:
1. 初始化當前幀的狀態
2. 當前進行的是幀編碼,因此NAL單元攜帶的是一個編碼片,一個NAL單元應由一組對應於視頻編碼的頭信息和一個壓縮編碼后的視頻數據序列。 寫當前NAL單元的頭信息(x264_nal_start)
3. 寫片頭信息(x264_slice_header_write),包括:片中第一宏塊的地址,片的類型,參考幀索引及一些幀編碼模式的選擇
4. 循環對每個宏塊進行編碼:
I. 先獲得宏塊的位置坐標(i_mb_x,i_mb_y),若i_mb_x為0,則進行去塊濾波;
II. 將當前宏塊的上和左邊的宏塊加載進來存入數組(x264_macroblock_cache_load)。
III. 對宏塊進行分析(x264_macroblock_analyse),通過計算SAD值,決定宏塊預測類型
A. I幀:只使用幀內預測,分別計算亮度16x16(4種)和4x4(9種)色度8x8(3種)所有模式的代價值,選 出SAT值最小的模式
B. P幀:計算幀內模式(同A)和幀間模式。幀間預測:對P幀的每一種分割進行幀間預測,得到最佳的運動矢量及最佳匹配塊。過程:尋找當前塊的后續矢量—— >選出最佳矢量——>找到最佳的整像素點——>找到最佳的二分之一像素點——>找到最佳的1/4像素點,取代碼最小的為最佳MV 和分割方式。最后從幀內模式和幀間模式中選擇小者。
IV. 對宏塊進行編碼
A、 幀內預測模式時,用所選的預測模式對宏塊中的像素值進行預測,若當前塊是第一塊,則預測值為128
B、 幀間預測模式,用所選的運動矢量進行運動補償得到宏塊的預測值。對殘差矩陣進行變換量化,掃描和CAVLC熵編碼。
V. 將CAVLC編碼結果寫入h->out.bs(x264_macroblock_write_cavlc);保存宏塊信息 (x264_macroblock_cache_save);通過調整QP進行碼率控制;RBSP比特填充(bs_rbsp_trailing),一次 nal編碼結束,指向下一個nal(x264_nal_end);