Outline:
1、 CFG文件中有關多參考幀的相關選項
2、 多參考幀涉及到的數據結構和全局變量
3、 保存重建圖像為參考幀
4、 編碼一幀前,設置參考幀列表
5、 多參考幀的使用(即參考幀的選擇策略問題)
6、 遺留問題
1、CFG文件中有關多參考幀的相關選項
############################################################################### #Encoder Control
###############################################################################
…
NumberReferenceFrames = 10 # Number of previous frames used for inter motion search (1-16)
解釋:
a、 首先通過Configure()轉換成input->num_reference_frames
b、 input->num_reference_frames再通過parset.c文件中的IdentifyNumRefFrames()返回給同一文件的FillParameterSetStructures()中的sps->num_ref_frames。
c、 FillParameterSetStructures()其實被parset.c文件中的GenerateParameterSets()函數調用,所以sps又被賦給了active_sps,active_sps是全局變量。
d、 active_sps->num_ref_frames又會在lencod.c中的init_img()函數中被賦給img->num_reference_frames。
PList0References????? = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames)
解釋:
用于限制LIST0中參考幀的數目
…
###############################################################################
# B Frames
###############################################################################
…
BList0References????? = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames)
BList1References????? = 0 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames)
…
2、 多參考幀涉及到的數據結構和全局變量
a、 概要
多參考幀相關的重要的數據結構都在mbuffer.h文件中。
其中重要的數據結構有:StorblePicture, FrameStore, DecodedPictureBuffer
重要的全局變量有:
extern DecodedPictureBuffer dpb;
extern StorablePicture **listX[6];
extern int listXsize[6];
b、 各數據結構的作用和相互之間的關系
StorblePicture存放的是一幀幀方式或場方式的重建圖像
FrameStore嵌套了StorblePicture,同時增加了一些標志信息,如是否已輸出到文件等,所以它可以用于通用的表示一幀的數據結構(不分場或幀)
DecodedPictureBuffer又嵌套了FrameStore,它用于保存所有的重建圖像(應該保存的),其中設置很多輔助的參數,如used_size用來表示已經保存的重建圖像數。
c、 各全局變量的作用
dpb的作用從上面對DecodedPictureBuffer的解釋中,已經可以看出是用來存儲所有的重建圖像。值的提醒的是它可能保存了非參考幀重建圖像。
listX[6]:該變量的作用是用來在每次編碼一幀圖像時,將所要用到的參考幀保存在其中。但真正所要用到的參考幀圖像數據是指向到dpb對應的結構元素中。
對于P幀,只要用到listX[0]。
對于B幀,要用到listX[0],listX[1]
對于Mbaff的編碼方式,可能還會用到listX[2-5]。
3、?? 保存重建圖像為參考幀
所用到的函數是:void store_picture_in_dpb(StorablePicture* p),mbuffer.c
該函數在image.c的encode_one_frame()的后段被調要到。
其中重要的程序段如下:
// first try to remove unused frames 當緩沖已滿時
if (dpb.used_size==dpb.size)
{
??? remove_unused_frame_from_dpb();//只刪除一幀。這種策略是否有效呢?懷疑???
}
// then output frames until one can be removed
while (dpb.used_size==dpb.size)
{
??? // non-reference frames may be output directly
??? if (!p->used_for_reference) //如果當前幀不作為參卡幀,可以直接輸出到重建序列文件
??? {
??????? get_smallest_poc(&poc, &pos);
??????? if ((-1==pos) || (p->poc < poc))
??????? {
??????????? direct_output(p, p_dec);
??????????? return
??????? }
??? }
??? // flush a frame
??? output_one_frame_from_dpb();//輸出一幀到文件
}
…
insert_picture_in_dpb(dpb.fs[dpb.used_size],p); //將當前解碼幀插入到dpb尾部
4、 編碼一幀前,設置參考幀列表
所用到的函數是:init_lists(), mbuffer.c
該函數在image.c中的code_a_picture()的開始部分被調用到。
其中重要的程序段如下:(只舉例分析幀模式的情況)
…
//將dpb中參考幀寫入ListX中去
if ((currSliceType == I_SLICE)||(currSliceType == SI_SLICE))
{
??? listXsize[0] = 0;
??? listXsize[1] = 0;
??? return;
}
if ((currSliceType == P_SLICE)||(currSliceType == SP_SLICE))
{
??? // Calculate FrameNumWrap and PicNum
??? if (currPicStructure == FRAME)
??? {
??????? for (i=0; i<dpb.ref_frames_in_buffer; i++)
??????? {
??????????? if (dpb.fs_ref[i]->is_used==3)
??????????? {
??????????????? if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
??????????????? {
??????????????????? listX[0][list0idx++] = dpb.fs_ref[i]->frame;
??????????????? }
??????????? }
??????? }
??????? // order list 0 by PicNum
??????? qsort((void *)listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc);
??????? listXsize[0] = list0idx;
…
}
else//B_SLICE
{
??? …
}
5、 多參考幀的使用(即參考幀的選擇策略問題)
所用到的函數是:PartitionMotionSearch(), mv_search.c 該函數的作用是對各種尺寸的宏塊或亞宏塊尋找匹配塊。
其中涉及到多參考幀的程序段如下:
//===== LOOP OVER REFERENCE FRAMES =====
for (list=0; list<numlists;list++)
{
??? for (ref=0; ref < listXsize[list+list_offset]; ref++)//list_offset和場模式有關
??? {
…
NOTE:從上面的程序可以看出,JM8.5對多參考幀的選擇,是采用的是一種完全遍歷的方式,所以其計算復雜度會很高。
6、 遺留問題
a、 在init_lists()對于ListX[0]和ListX[1]中參考幀數相同時,會采用一種交換機制,不知其目的如何?
b、 dpb的參考幀有short_term或long_term這樣的屬性,這屬性會影響多參考幀機制的整個過程,但不知其具體作用和原理?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zhoujunming/archive/2008/07/31/2747316.aspx
?
PartitionMotionSearch()函數&&宏塊分割
encode_one_macroblock()函數中的運動估計分為兩大塊,對于宏塊級的三種模式,分塊后直接對patition依次調用PartitionMotionSearch()函數;而對于亞宏塊級的(含8x8, 8x4,4x8,4x4)模式,首先將宏塊拆分為4個8×8子宏塊,針對每個8×8子宏塊調用PartitionMotionSearch()函數。
void
PartitionMotionSearch (int??? blocktype, //塊模式
?????????????????? int??? block8x8, //當前partition在宏塊的序號
?????????????????? double lambda)?? // λ
{
static int bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}};
static int by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}}; //參見注釋[1]
int?? **ref_array, ***mv_array; //參考幀列表和運動向量列表
int?? parttype = (blocktype<4?blocktype:4);
int?? step_h0?? = (input->blc_size[ parttype][0]>>2);
int?? step_v0?? = (input->blc_size[ parttype][1]>>2);
//partition的尺寸,用于決定block的邊界,對非P8×8模式無意義。
int?? step_h??? = (input->blc_size[blocktype][0]>>2); //子塊的尺寸
int?? step_v??? = (input->blc_size[blocktype][1]>>2);
int?? v, h; // BlockMotionSearch()函數要處理的子塊在當前宏塊中的相對塊坐標
//以上尺寸全部以4×4block為單位
numlists=bslice?2:1;
for (list=0; list
{
for (ref=0; ref < listXsize[list+list_offset]; ref++)
{
ref_array = enc_picture->ref_idx[list];
??? mv_array = enc_picture->mv[list];
//遍歷partition中的每一個
for (v=by0[parttype][block8x8]; v??????? {
????????? pic_block_y = img->block_y + v;// 當前子塊在圖像中的塊坐標=當前宏塊的塊坐標+當前子塊在宏塊中的相對塊坐標
????????? for (h=bx0[parttype][block8x8]; h????????? {
??????????? pic_block_x = img->block_x + h; // 當前子塊在圖像中的塊坐標=當前宏塊的塊坐標+當前子塊在宏塊中的相對塊坐標
??????????? mcost = BlockMotionSearch (ref, list, h<<2, v<<2, blocktype, search_range, lambda); //對當前子塊作運動向量搜索
??????????? motion_cost[blocktype][list][ref][block8x8] += mcost; //保存代價值
???????????
????????? for (j=0; j
???????????? for (i=0; i
???????????? {
???????? mv_array [pic_block_x+i][pic_block_y+j][0] = img->all_mv[h][v][list][ref][blocktype][0];
???????? mv_array [pic_block_x+i][pic_block_y+j][1] = img->all_mv[h][v][list][ref][blocktype][1];
//以4×4block為單位保存運動向量
???????? ref_array [pic_block_x+i][pic_block_y+j]??? = ref;
//保存參考幀序號
???????????? }
????????? }
?????? }
??? }
}
}
[1] static int bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}};
??? static int by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}};
這里的bx0, by0兩個數組分別對應了SKIP模式,16×16,16×8,8×16,P8×8這四種模式的橫坐標和縱坐標。舉兩個例子
如圖所示的16×16宏塊,首先劃分為4個8×8子塊(因為PartitionMotionSearch()函數處理的最小塊的尺寸為8×8),以4×4block為單位設定坐標,圖上已標出4個8×8子塊左上角的塊坐標。SKIP模式實際上并不牽涉到這個函數,因此坐標全部置零;16×16模式只有第一個坐標起作用,后三個置零;16×8只有前兩個有意義,標出兩個partition的左上角坐標,如圖標出了(0,0),(0,2),對照bx0, by0可以看到相應坐標值;最多子塊情況為4個8×8,即最后一組坐標。
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zhoujunming/archive/2008/09/11/2915084.aspx