Jm86中的encode_one_macroblock注釋
/*!
?*************************************************************************************
?* /brief
?*??? Mode Decision for a macroblock
?*??? //+++該函數的作用是編碼一個宏塊(包括幀間、幀內、幀內預測的方式)。
?*??? NOTE:從上面程序段中可以看出JM8.5中對7種宏塊模式是采用全部遍歷的方式,所以導致的計算復雜度很高。
?*************************************************************************************
?*/
?void encode_one_macroblock ()
?{
?? static const int? b8_mode_table[6]? = {0, 4, 5, 6, 7};???????? // DO NOT CHANGE ORDER !!!???
?? // //++ B片子宏塊類型。0:Direct_8*8,4:8*8,5:8*4,6:4*8,7:4*4
?? static const int? mb_mode_table[7]? = {0, 1, 2, 3, P8x8, I16MB, I4MB}; // DO NOT CHANGE ORDER !!!
??? //+++//??? 0:16X16 Direct模式,在B幀中有效 ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 1:Inter16X16,在幀間有效??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 2:Inter16X8,在幀間有效??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 3:Inter8X16,在幀間有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // P8X8:幀間有效:包括Inter8x8,Inter8x4,Inter4x8,Inter4x4??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I16MB:Intra16X16幀內有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I4MB:Intra有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I8MB:Intra有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // IPCM:Intra有效,不要預測,直接對RAW數據編碼.??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??
?? int???????? valid[MAXMODE];
?? int???????? rerun, block, index, mode, i0, i1, j0, j1, pdir, ref, i, j, k, ctr16x16, dummy;
?? double????? qp, lambda_mode, lambda_motion, min_rdcost, rdcost = 0, max_rdcost=1e30;
?? int???????? lambda_motion_factor;
?? int???????? fw_mcost, bw_mcost, bid_mcost, mcost, max_mcost=(1<<30);
?? int???????? curr_cbp_blk/*+++當前宏塊每個 4*4 塊是否有非零系數,跟CBP功能類似,CBP 是表示的每個8*8 塊*/,
?????????????? cnt_nonz = 0, best_cnt_nonz = 0, best_fw_ref = 0, best_pdir;
?? int???????? cost=0;
?? int???????? min_cost = max_mcost, min_cost8x8, cost8x8, cost_direct=0, have_direct=0, i16mode;
?? //+++根據對下面代碼的閱讀,這兒有比較要說明一下上面聲明的一些變量,這對于理解代碼很重要.
?? //+++首先,要提到best_mode,我本來以為這個量是在本函數中聲明的一個變量,然后仔細在上面尋找,都沒有找到,后來才發現,
?? //+++wow,原來best_mode在這個文件(rdopt.c)的開頭聲明過,是本文件的一個全局變量,yes,終于明白這個了
?? //+++其次,對于上面的一些變量,介紹一下:
?? //+++min_rdcost是用來保存RDO模式下的最小代價;min_cost則是非RDO模式下的代價
?? //+++min_cost8x8是亞宏塊級(P8x8)非RDO模式下最小模式代價;cost8x8是宏塊(16x16)中4個8x8塊的代價和(每一個8x8都是最佳代價min_cost8x8)
?? //+++fw_mcost,bw_mcost和bid_mcost是中間變量用來記錄(前向,后向和雙向)最佳參考幀對應的代價
?? //+++cost是一個中間變量,主要是在非RDO模式下,(幀間預測)記錄宏塊級或亞宏塊級中某一個模式中所有塊(16x16是1塊,16x8是2塊...)的所有代價之和(參考幀代價,運動估計)
?? //+++mcost也是一個中間變量,也是非RDO模式下,在進行最優參考幀時,用于累加代價之和(參考幀代價,運動估計)
??
?? int???????? intra1 = 0;
??
?? int???????? intra?????? = (((img->type==P_SLICE||img->type==SP_SLICE) && img->mb_y==img->mb_y_upd && img->mb_y_upd!=img->mb_y_intra) || img->type==I_SLICE);
?? int???????? spframe???? = (img->type==SP_SLICE);
?? int???????? siframe???? = (img->type==SI_SLICE);
?? int???????? bframe????? = (img->type==B_SLICE);
?? int???????? runs??????? = (input->RestrictRef==1 && input->rdopt==2 && (img->type==P_SLICE || img->type==SP_SLICE || (img->type==B_SLICE && img->nal_reference_idc>0)) ? 2 : 1);
??
?? int???????? checkref??? = (input->rdopt && input->RestrictRef && (img->type==P_SLICE || img->type==SP_SLICE));
?? Macroblock* currMB????? = &img->mb_data[img->current_mb_nr];
?? Macroblock* prevMB????? = img->current_mb_nr ? &img->mb_data[img->current_mb_nr-1]:NULL ;
??
?? int???? **ipredmodes = img->ipredmode;//+++ipredmode幀內預測模式
?? int???? best_bw_ref = -1;
?? int???? ******allmvs = img->all_mv;
??
?? int? l,list_offset;
?? int curr_mb_field = ((img->MbaffFrameFlag)&&(currMB->mb_field));
?? // find out the correct list offsets
?? if (curr_mb_field)
?? {
???? if(img->current_mb_nr%2)
?????? list_offset = 4; // bottom field mb
???? else
?????? list_offset = 2; // top field mb
?? }
?? else
?? {
???? list_offset = 0;? // no mb aff or frame mb
?? }
?? if(input->FMEnable)
???? decide_intrabk_SAD();
??
?? intra |= RandomIntra (img->current_mb_nr);??? // Forced Pseudo-Random Intra
?? //===== SET VALID MODES =====
?? valid[I4MB]?? = 1;??? //++ 宏塊可以采用intra4*4模式編碼
?? valid[I16MB]? = 1;??? //++ 宏塊可以采用intra16*16模式編碼
??
?? valid[0]????? = (!intra );??? //++ 宏塊是否采用inter模式編碼
?? valid[1]????? = (!intra && input->InterSearch16x16);??? //++ 宏塊是否采用inter16*16模式編碼
?? valid[2]????? = (!intra && input->InterSearch16x8);??? //++ 宏塊是否采用inter16*8模式編碼
?? valid[3]????? = (!intra && input->InterSearch8x16);??? //++ 宏塊是否采用inter8*16模式編碼
?? valid[4]????? = (!intra && input->InterSearch8x8);??? //++ 宏塊是否采用inter8*8模式編碼
?? valid[5]????? = (!intra && input->InterSearch8x4);??? //++ 宏塊是否采用inter8*4模式編碼
?? valid[6]????? = (!intra && input->InterSearch4x8);??? //++ 宏塊是否采用inter4*8模式編碼
?? valid[7]????? = (!intra && input->InterSearch4x4);??? //++ 宏塊是否采用inter4*4模式編碼
?? valid[P8x8]?? = (valid[4] || valid[5] || valid[6] || valid[7]);??? //++ 宏塊是否采用亞宏塊模式編碼?? +++P8x8=8
?? valid[12]???? = (siframe);??? //++ 宏塊是否采用SI模式編碼
?? if (!img->MbaffFrameFlag)//+++//在非宏塊級幀場自適應且是場模式下 進行色度矢量校正
?? {
???? for (l=0+list_offset;l<(2+list_offset);l++)
???? {
?????? for(k = 0; k < listXsize[l]; k++)
?????? {
???????? listX[l][k]->chroma_vector_adjustment= 0;
???????? if(img->structure == TOP_FIELD && img->structure != listX[l][k]->structure)
?????????? listX[l][k]->chroma_vector_adjustment = -2;
???????? if(img->structure == BOTTOM_FIELD && img->structure != listX[l][k]->structure)
?????????? listX[l][k]->chroma_vector_adjustment = 2;
?????? }
???? }
?? }
?? else
?? {
???? if (curr_mb_field)
???? {
?????? for (l=0+list_offset;l<(2+list_offset);l++)
?????? {
???????? for(k = 0; k < listXsize[l]; k++)
???????? {
?????????? listX[l][k]->chroma_vector_adjustment= 0;
?????????? if(img->current_mb_nr % 2 == 0 && listX[l][k]->structure == BOTTOM_FIELD)
???????????? listX[l][k]->chroma_vector_adjustment = -2;
?????????? if(img->current_mb_nr % 2 == 1 && listX[l][k]->structure == TOP_FIELD)
???????????? listX[l][k]->chroma_vector_adjustment = 2;
???????? }
?????? }
???? }
???? else
???? {
?????? for (l=0+list_offset;l<(2+list_offset);l++)
?????? {
???????? for(k = 0; k < listXsize[l]; k++)
???????? {
?????????? listX[l][k]->chroma_vector_adjustment= 0;
???????? }
?????? }
???? }
????
?? }
//+++ 設置RDO與非RDO下的lambda系數
?? //===== SET LAGRANGE PARAMETERS =====
?? if (input->rdopt)
?? {
???? qp = (double)img->qp - SHIFT_QP;??? //++ ???
???? if (input->successive_Bframe>0)
?????? lambda_mode?? = 0.68 * pow (2, qp/3.0) * (img->type==B_SLICE? max(2.00,min(4.00,(qp / 6.0))):spframe?max(1.4,min(3.0,(qp / 12.0))):1.0);?
???? else
?????? lambda_mode?? = 0.85 * pow (2, qp/3.0) * (img->type==B_SLICE? 4.0:spframe?max(1.4,min(3.0,(qp / 12.0))):1.0);?
???? lambda_motion = sqrt (lambda_mode);
?? }
?? else
?? {
???? lambda_mode = lambda_motion = QP2QUANT[max(0,img->qp-SHIFT_QP)];
?? }
?? lambda_motion_factor = LAMBDA_FACTOR (lambda_motion);??? //++ 使用該變量的原因主要是為了在運算過程中使用定點運算但又能提高精度
??
??
?? for (rerun=0; rerun<runs; rerun++)??? //++ runs=2是針對loss rdo模式,其余的情況runs=1
?? {
???? if (runs==2)
???? {
?????? if (rerun==0)?? input->rdopt=1;
?????? else??????????? input->rdopt=2;
???? }
????
???? // reset chroma intra predictor to default
???? currMB->c_ipred_mode = DC_PRED_8;
//+++++++++++++++++++++++++++
//+++幀間預測,計算其選擇合適模式后的開銷
??? ?//+++(根據拉格朗日率失真準則)
???? if (!intra)
???? {
??? ??? ?//+++B幀的直接模式預測
?????? //===== set direct motion vectors =====
?????? if (bframe)//+++P幀無direct模式 但有skip模式
?????? {
???????? Get_Direct_Motion_Vectors ();//+++不返回direct模式代價
?????? }
?????? //+++//宏塊級運動估計
?????? //===== MOTION ESTIMATION FOR 16x16, 16x8, 8x16 BLOCKS =====
?????? for (min_cost=1<<20, best_mode=1, mode=1; mode<4; mode++)
?????? {
???????? if (valid[mode])//+++//對應于程序外部(即CFG文件中)的設置
???????? {
??? ??? ?//+++//對于16x16,MB只分一個塊;對于16x8和8x16,MB被分成兩個塊
?????????? for (cost=0, block=0; block<(mode==1?1:2); block++)??? //++ 16*16 分割方式只需要計算一次,16*8 和 8*16 分割方式需要計算兩次
?????????? {
??? ??? ?? //+++/塊匹配!!!lambda_motion用來求運動矢量消耗的碼率
???????????? PartitionMotionSearch (mode, block, lambda_motion);??? //++ 對 16*16、16*8、8*16 分割方式進行 ME
???????????? //--- set 4x4 block indizes (for getting MV) ---
???????????? j = (block==1 && mode==2 ? 2 : 0);??? //++ 如果現在處理的是 16*8 分割方式的第 2 個分割,則 j=2
???????????? i = (block==1 && mode==3 ? 2 : 0);??? //++ 如果現在處理的是 8*16 分割方式的第 2 個分割,則 i=2
??? ??? ??? ?//+++通過循環在list0中尋找前向預測的最佳參考幀(best_fw_ref),代價為fw_mcost,
???????????? //--- get cost and reference frame for forward prediction ---
???????????? for (fw_mcost=max_mcost, ref=0; ref<listXsize[LIST_0+list_offset]; ref++)
???????????? {
?????????????? if (!checkref || ref==0 || CheckReliabilityOfRef (block, LIST_0, ref, mode))
?????????????? {
??? ??? ??? ??? ??? //++ 參考幀索引號編碼所需要使用的比特數作為編碼代價的一部分
??? ??? ??? ??? ?? //+++這個地方就是利用拉格朗日進行計算開銷的函數,事實上,這個地方要考慮很多東西的開銷,可以發現,下面的代碼中還要加上其他的
??? ??? ??? ??? ?? //+++mcost->(1)REF_COST參考幀代價
???????????????? mcost? = (input->rdopt ? REF_COST (lambda_motion_factor, ref, LIST_0 + list_offset) : (int)(2*lambda_motion*min(ref,1)));
??? ??? ??? ??? ?//+++motion_cost(運動搜索代價)是一個全局變量,其值在PartitionMotionSearch函數內進行過改變
??? ??? ??? ??? ?//+++so 此時motion_cost就是保存的相應的運動搜索代價
??? ??? ??? ??? ?//+++那么,mcost->(2)motion_cost運動搜索代價
???????????????? mcost += motion_cost[mode][LIST_0][ref][block];//+++可以發現motion_cost數組的參數mode,block和
??? ??? ??? ??? ?????????????????????????????????????????????? //+++PartitionMotionSearch(PMS)函數的參數是一致的,并且在PMS函數中
??? ??? ??? ??? ????????????????????????????????????????????? //+++計算motion_cost時也是對ref(參考幀)進行循環的,所以將兩者聯系起來
??? ??? ??? ??? ???????????????????????????????????????????? //+++我們就可以理解這兒motion_cost的數組中參數的含義了.
??? ??? ??? ??? ??????????????????????????????????????????? //+++另外在[JM86核心函數研究]中有對motion_cost的詳細介紹
??? ??? ??? ??? ?????????????????????????????????????????? //+++該數組存儲了一個宏塊的分塊在不同幀間模式和參考幀下的運動估計的開銷值。
??? ??? ??? ??? ????????????????????????????????????????? //+++函數PartitionMotionSearch的主要任務就是更新該數組。同時,該數組也在決定最佳參考幀時被引用。
???????????????? if (mcost < fw_mcost)//+++根據參考代價選出該模式下的最佳參考幀
???????????????? {
??? ??? ??? ??? ??? ?//+++記錄最佳參考幀及預測代價
?????????????????? fw_mcost??? = mcost;
?????????????????? best_fw_ref = ref;
???????????????? }
?????????????? }
???????????? }
??? ??? ??? ?//+++B幀還需記錄向后及雙向預測的各個參考幀與參考代價
???????????? if (bframe)
???????????? {
?????????????? //--- get cost for bidirectional prediction ---
?????????????? for (bw_mcost=max_mcost, ref=0; ref<listXsize[LIST_1 + list_offset]; ref++)
?????????????? {//+++B幀的計算方法與I,P幀不一樣
???????????????? mcost? = (input->rdopt ? REF_COST (lambda_motion_factor, ref, LIST_1 + list_offset) : (int)(2*lambda_motion*min(ref,1)));
???????????????? mcost += motion_cost[mode][LIST_1][ref][block];
???????????????? if (mcost < bw_mcost)
???????????????? {
?????????????????? bw_mcost??? = mcost;
?????????????????? best_bw_ref = ref;
???????????????? }
?????????????? }
?????????????? // search bidirectional between best forward and ref_idx=0 backward
?????????????? bid_mcost? = (input->rdopt ? (REF_COST (lambda_motion_factor, best_fw_ref,LIST_0+list_offset)+REF_COST (lambda_motion_factor, 0,LIST_1+list_offset)) : (int)(2*lambda_motion*min(best_fw_ref,1)));
?????????????? bid_mcost += BIDPartitionCost (mode, block, best_fw_ref, 0, lambda_motion_factor);
?????????????? //--- get prediction direction ----
?????????????? if (fw_mcost<=bw_mcost && fw_mcost<=bid_mcost)
?????????????? {
???????????????? best_pdir = 0;
???????????????? best_bw_ref = 0;
???????????????? cost += fw_mcost;
?????????????? }
?????????????? else if (bw_mcost<=fw_mcost && bw_mcost<=bid_mcost)
?????????????? {
???????????????? best_pdir = 1;
???????????????? cost += bw_mcost;
???????????????? best_fw_ref = 0;
?????????????? }
?????????????? else
?????????????? {
???????????????? best_pdir = 2;
???????????????? cost += bid_mcost;
???????????????? best_bw_ref = 0;
?????????????? }
???????????? }
???????????? else // if (bframe)
???????????? {
?????????????? best_pdir? = 0;//+++best_pdir是最佳預測方向,對于非B幀(P幀)預測方向就一個直接設置為0,而對于
??? ??? ??? ????????????????? //+++B幀要從三種方式(前向,后向,雙向)中選擇一個,從上面if中的代碼中我們就可以看出來
?????????????? cost????? += fw_mcost;
???????????? }
??? ??? ??? ?//+++下面要記錄參考幀和MV信息,說明一下:這些全局變量是作為BlockMotionSearch()中運動搜索時運動向量預測的依據
??? ??? ??? ?//+++問:下一宏塊的運動向量等信息也用當前宏塊的運動向量預測嗎?答:ME 算法是開放部分,你想怎么做就怎么做。JM 在 ME 時會用到相鄰塊的 MV;
??? ??? ??? ?//+++對于MB是以4*4的塊為單位來記錄mv和ref的
???????????? if (mode==1)//+++16x16
???????????? {
?????????????? if (best_pdir==1)//+++后向參考
?????????????? {
???????????????? for (j=0; j<4; j++)
???????????????? {
?????????????????? for (i=0; i<4; i++)
?????????????????? {
??? ??? ??? ??? ??? ?? //+++保存參考信息至重建單元,B幀多做后項參考
??? ??? ??? ??? ?? //+++enc_picture 中好像是最終數據,img 中存的是中間數據
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = 0;
?????????????????? }
???????????????? }
?????????????? }
?????????????? else
?????????????? {
???????????????? for (j=0; j<4; j++)
???????????????? {
?????????????????? for (i=0; i<4; i++)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];?
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][1];
?????????????????? }
???????????????? }
?????????????? }
?????????????? if (bframe)
?????????????? {
???????????????? if (best_pdir==0)
???????????????? {
?????????????????? for (j=0; j<4; j++)
?????????????????? {
???????????????????? for (i=0; i<4; i++)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;??
?????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = 0;
???????????????????? }
?????????????????? }
???????????????? }
???????????????? else
???????????????? {
?????????????????? for (j=0; j<4; j++)
?????????????????? {
???????????????????? for (i=0; i<4; i++)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
???????????? else if (mode==2)//+++16x8
???????????? {
?????????????? for (j=0; j<2; j++)
?????????????? {
???????????????? for (i=0; i<4; i++)
???????????????? {
?????????????????? if (best_pdir==1)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+i][img->block_y+block*2+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][1] = 0;
?????????????????? }
?????????????????? else
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+i][img->block_y+block*2+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j]];
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][0] = img->all_mv[i][j+block*2][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][1] = img->all_mv[i][j+block*2][LIST_0][best_fw_ref][mode][1];
?????????????????? }
?????????????????? if (bframe)
?????????????????? {
???????????????????? if (best_pdir==0)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+i][img->block_y+block*2+j] = -1;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][1] = 0;
???????????????????? }
???????????????????? else
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+i][img->block_y+block*2+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
???????????? else//+++8x16
???????????? {
?????????????? for (j=0; j<4; j++)
?????????????? {
???????????????? for (i=0; i<2; i++)
???????????????? {
?????????????????? if (best_pdir==1)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+block*2+i][img->block_y+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][1] = 0;
?????????????????? }
?????????????????? else
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+block*2+i][img->block_y+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j]];
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][0] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][1] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][1];
?????????????????? }
?????????????????? if (bframe)
?????????????????? {
???????????????????? if (best_pdir==0)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+block*2+i][img->block_y+j] = -1;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][1] = 0;
???????????????????? }
???????????????????? else
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+block*2+i][img->block_y+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
??? ??? ??? ?//+++以8x8塊記錄各個模式的預測信息 每個分割的8x8相同
??? ??? ??? ?//+++此處解釋一下best8x8fwref:: 該2維數組存儲了一個宏塊的4個8x8block在各個幀間預測模式下的最佳前向參考幀。
??? ??? ??? ?//+++上面的代碼完成了最佳參考幀的選擇,所以這兒將最佳參考幀的信息存儲在這個數組中。在計算預測值時,程序會引用該數組作為參考。
???????????? //----- set reference frame and direction parameters -----
???????????? if (mode==3)//+++兩個16x8:如果以8x8為單位,分別擁有(0,2)和(1,3)
???????????? {
?????????????? best8x8fwref?? [3][block] = best8x8fwref?? [3][block+2] = best_fw_ref;
?????????????? best8x8pdir??? [3][block] = best8x8pdir??? [3][block+2] = best_pdir;
?????????????? best8x8bwref?? [3][block] = best8x8bwref?? [3][block+2] = best_bw_ref;
???????????? }
???????????? else if (mode==2)//+++兩個8x16:如果以8x8為單位,分別擁有(0,1)和(2,3)
???????????? {
?????????????? best8x8fwref?? [2][2*block] = best8x8fwref?? [2][2*block+1] = best_fw_ref;
?????????????? best8x8pdir??? [2][2*block] = best8x8pdir??? [2][2*block+1] = best_pdir;
?????????????? best8x8bwref?? [2][2*block] = best8x8bwref?? [2][2*block+1] = best_bw_ref;
???????????? }
???????????? else//+++一個16x16:如果以8x8為單位,(0,1,2,3)的設置是一樣的
???????????? {
?????????????? best8x8fwref?? [1][0] = best8x8fwref?? [1][1] = best8x8fwref?? [1][2] = best8x8fwref?? [1][3] = best_fw_ref;
?????????????? best8x8pdir??? [1][0] = best8x8pdir??? [1][1] = best8x8pdir??? [1][2] = best8x8pdir??? [1][3] = best_pdir;
?????????????? best8x8bwref?? [1][0] = best8x8bwref?? [1][1] = best8x8bwref?? [1][2] = best8x8bwref?? [1][3] = best_bw_ref;
???????????? }
??? ??? ??? ?
???????????? //--- set reference frames and motion vectors ---
???????????? if (mode>1 && block==0)? //+++mode>1,說明mode=2和3的時候執行,block==0,說明是對第一個分塊.
??? ??? ??? ???????????????????????? //+++這里說明一下:對于16x8,8x16來說,只有兩個宏塊分割,這里保存第一塊分割的運動信息,目的是給下一個分割做運動矢量預測使用
??? ??? ??? ??????????????????????? //+++由于前一個分割不需要下一個分割的運動矢量信息,因此只需要保存前一個分割即可.
??? ??? ??? ?????????????????????? //+++另外,在這之前,事實上已經保存過,所以這里是重復保存了
?????????????? SetRefAndMotionVectors (block, mode, best_pdir, best_fw_ref, best_bw_ref);
????????? } // for (block=0; block<(mode==1?1:2); block++)
??? ??? ? //+++我在這個地方解釋一下cost與min_cost:min_cost是為了尋找三種宏塊模式(16x16,16x8,8x16)中代價最小的模式
??? ??? ? //+++由于宏塊模式在計算的時候是進一步分成小塊計算的,所以cost就是用來保存一種宏塊模式下對應所有小塊的代價之和
??? ??? ? //+++模式16x16下:cost對應一個16x16大小的塊;模式16x8模式下:cost對應兩個16x8大小的塊......
??? ??? ? //+++所以下面這一個if語句就是在尋找代價最小的宏塊模式(best_mode)
????????? if (cost < min_cost)
????????? {
??????????? best_mode = mode;
??????????? min_cost? = cost;
????????? }
??????? } // if (valid[mode])
????? } // for (mode=1; mode<4; mode++)//+++宏塊級模式結束
????? //+++現在宏塊級運動估計結束,best_mode保存了最佳的宏塊模式,min_cost記錄其對應的代價
??? ? //+++亞宏塊級運動估計
????? if (valid[P8x8])
????? {
??????? cost8x8 = 0;
???????
??????? //===== store coding state of macroblock =====
??????? store_coding_state (cs_mb);
??????? //+++遍歷16x16宏塊的4個8x8塊
??????? //=====? LOOP OVER 8x8 SUB-PARTITIONS? (Motion Estimation & Mode Decision) =====
??????? for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++)
???????
??? ??? {
????????? //--- set coordinates ---
????????? j0 = ((block/2)<<3);??? j1 = (j0>>2);
????????? i0 = ((block%2)<<3);??? i1 = (i0>>2);
??? ??? ? //+++對宏塊中的每個8x8塊的模式循環
??? ??? ? //+++這個地方解釋一下:min_cost8x8用于記錄非RDO模式下的最小代價,而min_rdcost則是RDO模式下的最小代價
????????? //=====? LOOP OVER POSSIBLE CODING MODES FOR 8x8 SUB-PARTITION? =====
????????? for (min_cost8x8=(1<<20), min_rdcost=1e30, index=(bframe?0:1); index<5; index++)
????????? {
??????????? if (valid[mode=b8_mode_table[index]])//+++b8_mode_table[6] = {0, 4, 5, 6, 7};
??????????? {
??? ??? ??? ??? curr_cbp_blk = 0;//+++初始化當前cbp_blk
?????????????
????????????? if (mode==0)
????????????? {
??????????????? //--- Direct Mode ---
??????????????? if (!input->rdopt)
??????????????? {
????????????????? cost_direct += (cost = Get_Direct_Cost8x8 ( block, lambda_mode ));
????????????????? if (cost==1<<30)
??????????????????? cost_direct = (1<<30);
??? ??? ??? ??? ? have_direct ++;//+++記錄是否做過direct模式的標記
??????????????? }
??????????????? best_fw_ref = direct_ref_idx[LIST_0][img->block_x+(block&1)*2][img->block_y+(block&2)];
??????????????? best_bw_ref = direct_ref_idx[LIST_1][img->block_x+(block&1)*2][img->block_y+(block&2)];
??????????????? best_pdir?? = direct_pdir[img->block_x+(block&1)*2][img->block_y+(block&2)];
????????????? } // if (mode==0)
??? ??? ??? ? else//+++非direct模式下
????????????? {
??????????????? //--- motion estimation for all reference frames ---
??????????????? PartitionMotionSearch (mode, block, lambda_motion);
??????????????? //+++這一部分與宏塊級的類似
??????????????? //--- get cost and reference frame for forward prediction ---
??????????????? for (fw_mcost=max_mcost, ref=0; ref<listXsize[LIST_0+list_offset]; ref++)
??????????????? {
????????????????? if (!checkref || ref==0 || CheckReliabilityOfRef (block, LIST_0, ref, mode))
????????????????? {
??? ??? ??? ??? ? //+++(1)參考幀代價
??????????????????? mcost? = (input->rdopt ? REF_COST(lambda_motion_factor,ref,LIST_0+list_offset) : (int)(2*lambda_motion*min(ref,1)));
??????????????????? //+++(2)MV代價
??????????????????? mcost += motion_cost[mode][LIST_0][ref][block];
??????????????????? if (mcost < fw_mcost)
??????????????????? {
????????????????????? fw_mcost??? = mcost;
????????????????????? best_fw_ref = ref;
??????????????????? }
????????????????? }
??????????????? }
???????????????
??????????????? //store forward reference index for every block
??????????????? for (j=0; j<2; j++)
????????????????? for (i=0; i<2; i++)
????????????????? {
??????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
??????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];
????????????????? }
??????????????? //+++B幀有所不同,還要考慮后向和雙向模式,其實與上面的代碼是相似的
??????????????? if (bframe)
??????????????? {
??? ??? ??? ???
????????????????? for (bw_mcost=max_mcost, ref=0; ref<listXsize[LIST_1+list_offset]; ref++)
????????????????? {
??????????????????? mcost? = (input->rdopt ? REF_COST(lambda_motion_factor,ref,LIST_1+list_offset) : (int)(2*lambda_motion*min(ref,1)));
???????????????????
??????????????????? mcost += motion_cost[mode][LIST_1][ref][block];
??????????????????? if (mcost < bw_mcost)
??????????????????? {
????????????????????? bw_mcost??? = mcost;
????????????????????? best_bw_ref = ref;
??????????????????? }
????????????????? }
?????????????????
????????????????? // bidirectional uses best forward and zero backward reference
????????????????? bid_mcost? = (input->rdopt ? (REF_COST (lambda_motion_factor, best_fw_ref, LIST_0 + list_offset)+REF_COST (lambda_motion_factor, 0, LIST_1 + list_offset)) : (int)(2*lambda_motion*min(best_fw_ref,1)));
????????????????? bid_mcost += BIDPartitionCost (mode, block, best_fw_ref, 0, lambda_motion_factor );
?????????????????
????????????????? //--- get prediction direction ----
????????????????? if????? (fw_mcost<=bw_mcost && fw_mcost<=bid_mcost)
????????????????? {
??????????????????? best_pdir = 0;
??????????????????? cost = fw_mcost;
??????????????????? best_bw_ref = -1;
????????????????? }
????????????????? else if (bw_mcost<=fw_mcost && bw_mcost<=bid_mcost)
????????????????? {
??????????????????? best_pdir = 1;
??????????????????? cost = bw_mcost;
??????????????????? best_fw_ref = -1;
????????????????? }
????????????????? else
????????????????? {
??????????????????? best_pdir = 2;
??????????????????? cost = bid_mcost;
??????????????????? best_bw_ref = 0;
????????????????? }
??????????????????? //store backward reference index for every block
????????????????? for (j=0; j<2; j++)
??????????????????? for (i=0; i<2; i++)
??????????????????? {
????????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_bw_ref;
????????????????????? //enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];?
??????????????????? }
??????????????? } // if (bframe)
??????????????? else
??????????????? {
????????????????? best_pdir = 0;
????????????????? cost????? = fw_mcost;
??????????????? }
????????????? } // if (mode!=0)
?????????????
????????????? //--- store coding state before coding with current mode ---
????????????? store_coding_state (cs_cm);
?????????????
??? ??? ??? ? //+++計算RDO模式代價rdcost或非RDO模式代價cost
????????????? if (input->rdopt)
????????????? {
??? ??? ??? ???? //+++RDCost_for_8x8blocks是在4種亞宏塊模式中選擇最佳的模式(代價)
??? ??? ??? ??? //+++準確來說RDCost_for_8x8blocks主要是得到編號為block的8x8塊,在mode模式下的代價
??????????????? //--- get and check rate-distortion cost ---
??????????????? rdcost = RDCost_for_8x8blocks (&cnt_nonz, &curr_cbp_blk, lambda_mode,
?????????????????????????????????????????????? block, mode, best_pdir, best_fw_ref, best_bw_ref);
??? ??? ??? ??? ????????????????????????????? //+++block:8x8塊在16x16大小的宏塊中的位置
??? ??? ??? ??? ????????????????????????????? //+++mode:亞宏塊模式
????????????? }
????????????? else
????????????? {
??????????????? cost += (REF_COST (lambda_motion_factor, B8Mode2Value (mode, best_pdir), list_offset + (best_pdir<1?0:1)) - 1);
????????????? }
??? ??? ??? ? //+++根據cost(非RDO模式)或rdcost(RDO模式)選擇最佳模式
????????????? //--- set variables if best mode has changed ---
????????????? if (( input->rdopt && rdcost < min_rdcost) ||
????????????????? (!input->rdopt && cost?? < min_cost8x8? )?? )
????????????? {
??????????????? min_cost8x8????????????????? = cost;//+++非RDO代價
??????????????? min_rdcost?????????????????? = rdcost;//+++RDO代價
??????????????? best8x8mode????????? [block] = mode;//最佳的亞宏塊模式
??????????????? best8x8pdir??? [P8x8][block] = best_pdir;
??????????????? best8x8fwref?? [P8x8][block] = best_fw_ref;
??????????????? best8x8bwref?? [P8x8][block] = best_bw_ref;
???????????????
??????????????? //--- store number of nonzero coefficients ---
??????????????? best_cnt_nonz? = cnt_nonz;
??????????????? //+++存儲cbp、殘差AC系數和重建幀中的預測值
??????????????? if (input->rdopt)
??????????????? {??? ??? ??? ??? ???
????????????????? //--- store block cbp ---
????????????????? cbp_blk8x8??? &= (~(0x33 << (((block>>1)<<3)+((block%2)<<1)))); // delete bits for block
????????????????? cbp_blk8x8??? |= curr_cbp_blk;
?????????????????
????????????????? //--- store coefficients ---
????????????????? for (k=0; k< 4; k++)
??????????????????? for (j=0; j< 2; j++)
????????????????????? for (i=0; i<65; i++)? cofAC8x8[block][k][j][i] = img->cofAC[block][k][j][i]; // 18->65 for ABT
?????????????????????
????????????????????? //--- store reconstruction and prediction ---
????????????????? for (j=j0; j<j0+8; j++)
??????????????????? for (i=i0; i<i0+8; i++)
??????????????????? {
????????????????????? rec_mbY8x8[j][i] = enc_picture->imgY[img->pix_y+j][img->pix_x+i];
????????????????????? mpr8x8??? [j][i] = img->mpr[i][j];
??????????????????? }
??????????????? }
???????????????
??????????????? //--- store coding state ---
??????????????? store_coding_state (cs_b8);
????????????? } // if (rdcost <= min_rdcost)
?????????????
????????????? //--- re-set coding state as it was before coding with current mode was performed ---
????????????? reset_coding_state (cs_cm);
??????????? } // if (valid[mode=b8_mode_table[index]])
??? ??? ? } // for (min_rdcost=1e30, index=(bframe?0:1); index<6; index++)//+++5種8x8模式循環結束
??? ??? ? //+++cost8x8:非RDO模式下的代價,其實cost8x8是一個宏塊中的4個8x8塊的代價和,
??? ??? ? //+++換句話說,其實cost8x8就是一個宏塊(16x16)在亞宏塊模式下的總的代價和.
??? ??? ? //+++這個量主要用來和上面計算的最佳宏塊級模式(非RDO情況下)對應的最小代價min_cost來進行比較,
??? ??? ? //+++看宏塊級模式或亞宏塊級模式哪個更好,從下面的代碼中我們也可以看出來.
????????? cost8x8 += min_cost8x8;
//????????? if (!input->rdopt) cost8x8+= min_cost8x8;
//????????? else cost8x8 += min_rdcost;?????????
?????????
????????? if (!input->rdopt)
????????? {
??????????? mode = best8x8mode[block];
??????????? pdir = best8x8pdir[P8x8][block];
??????????? //+++編碼殘差系數
??????????? curr_cbp_blk? = 0;
??? ??? ??? //+++cnt_nonz表示非零系數的編碼代價;
??????????? best_cnt_nonz = LumaResidualCoding8x8 (&dummy, &curr_cbp_blk, block, pdir,
?????????????????????????????????????????????????? (pdir==0||pdir==2?mode:0),
?????????????????????????????????????????????????? (pdir==1||pdir==2?mode:0),
?????????????????????????????????????????????????? (best8x8fwref[P8x8][block]),
?????????????????????????????????????????????????? (best8x8bwref[P8x8][block]));
??????????? cbp_blk8x8?? &= (~(0x33 << (((block>>1)<<3)+((block%2)<<1)))); // delete bits for block
??????????? cbp_blk8x8?? |= curr_cbp_blk;
???????????
??????????? //--- store coefficients ---
??????????? for (k=0; k< 4; k++)
????????????? for (j=0; j< 2; j++)
??????????????? for (i=0; i<65; i++)? cofAC8x8[block][k][j][i] = img->cofAC[block][k][j][i]; // 18->65 for ABT
???????????????
??????????????? //--- store reconstruction and prediction ---
??????????? for (j=j0; j<j0+8; j++)
????????????? for (i=i0; i<i0+8; i++)
????????????? {
??????????????? rec_mbY8x8[j][i] = enc_picture->imgY[img->pix_y+j][img->pix_x+i];
??????????????? mpr8x8??? [j][i] = img->mpr[i][j];
????????????? }
????????? }
?????????
????????? //----- set cbp and count of nonzero coefficients ---
????????? if (best_cnt_nonz)
????????? {
??????????? cbp8x8??????? |= (1<<block);
??????????? cnt_nonz_8x8? += best_cnt_nonz;
????????? }
?????????
????????? mode=best8x8mode[block];//第2396行會用到mode,best8x8mode[block]應該是第block號8x8塊所選取的最佳亞宏塊級模式
????????? //===== reset intra prediction modes (needed for prediction, must be stored after 8x8 mode dec.) =====
????????? j0 = img->block_y+2*(block/2);
????????? i0 = img->block_x+2*(block%2);
????????? for (j=j0; j<j0+2; j++)
??????????? for (i=i0; i<i0+2; i++)
????????????? ipredmodes[i][j]???????? = DC_PRED;
????????? i0 = 4*block;
????????? for (i=i0; i<i0+4; i++)??? currMB->intra_pred_modes[i]? = DC_PRED;
???????????
????????? if (block<3)
????????? {
??????????? //===== re-set reconstructed block =====
??????????? j0?? = 8*(block/2);
??????????? i0?? = 8*(block%2);
??????????? for (j=j0; j<j0+8; j++)
????????????? for (i=i0; i<i0+8; i++)?
??????????????? enc_picture->imgY[img->pix_y+j][img->pix_x+i] = rec_mbY8x8[j][i];
????????? } // if (block<3)
??????????? //+++這兒與宏塊級類似,要設置MV和參考幀
????????? //===== set motion vectors and reference frames (prediction) =====
????????? SetRefAndMotionVectors (block, mode, best8x8pdir[P8x8][block], best8x8fwref[P8x8][block], best8x8bwref[P8x8][block]);
????????? //===== set the coding state after current block =====
????????? reset_coding_state (cs_b8);
??????? } // for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++)
??????? //+++此刻完成了對一個宏塊(16x16)在亞宏塊模式下的計算,或者說對宏塊中每個8x8塊完成亞宏塊模式的選擇
??? ??? //+++并且在亞宏塊模式下的代價(4個8x8塊代價之和)也計算完畢,在cost8x8中,下面會用到,和宏塊級模式(min_cost)進行比較
??????? //===== store intra prediction modes for 8x8+ macroblock mode =====
??????? for (k=0, j=img->block_y; j<img->block_y+4; j++)
??????? {
????????? for (???? i=img->block_x; i<img->block_x+4; i++, k++)
????????? {
??????????? b8_ipredmode?????? [k] = ipredmodes??? [i][j];
??????????? b8_intra_pred_modes[k] = currMB->intra_pred_modes[k];
????????? }
??????? }
???????
??????? //--- re-set coding state (as it was before 8x8 block coding) ---
??????? reset_coding_state (cs_mb);
??????? for (i=0; i<16; i++)
????????? for(j=0; j<16; j++)
??? ??? ??? ? //++ 原代碼中這里 img->mpr 的下標寫反了
//????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i]-img->mpr[j][i];
??????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i]-img->mpr[i][j];
??? ??? ???
??? ??? ???
??? //+++到這兒應該是一個結點了啊
??? ??? //+++(在非RDO模式下)對一個宏塊(當前宏塊),此時宏塊級(16x16,16x8,8x16)的最小開銷已經計算出來,即min_cost
??? ??? //+++子宏塊級(8x8,8x4,4x8和4x4)的開銷也計算出來(4個8x8塊代價之和),即cost8x8
??? ??? //+++這樣可以比較這兩種方式,選擇開銷更小的那種宏塊分割方式
??? ??? if(cost8x8 < min_cost)//+++// 幀間8x8模式與幀間16x16代價相比
??????? {
?????????? best_mode = P8x8;
?????????? min_cost = cost8x8;
??????? }
??? ??? //+++到這兒我們也可以看到,在非RDO模式下,best_mode保存的是一個宏塊(當前宏塊)幀間預測的最優模式,是(16x16,16x8,8x16和P8x8)之一.
??? ??? //+++(16x16,16x8,8x16)這三種宏塊級的模式是選擇最優模式后再與P8x8模式比較.min_cost現在保存的是一個宏塊(當前宏塊)幀間預測的最小代價
??? ??? //+++從下面幀內預測的代碼我們也可以看到,min_cost作為幀間最小代價是要和幀內兩種模式I4MB和I16MB進行比較的.
????? }
????? else // if (valid[P8x8])
????? {
??? ??? //+++這個地方是不用子宏塊劃分的方法時,將其開銷設為很大
??????? cost8x8 = (1<<20);
????? }
??
????? // Find a motion vector for the Skip mode
????? if((img->type == P_SLICE)||(img->type == SP_SLICE))
??????? FindSkipModeMotionVector ();//+++用于計算MV預測值
??? }
??? else // if (img->type!=I_SLICE)//+++不進行幀間預測
??? {
????? min_cost = (1<<20);
??? }
//+++幀間預測的相關開銷計算完畢
//++++++++++++++++++++++++++++
//===================================
?//+++下面是對幀內預測進行求其開銷
??? if (input->rdopt)
??? {//+++使用RDO準則的情況
????? int mb_available_up;
????? int mb_available_left;
????? int mb_available_up_left;
?????
????? min_rdcost = max_rdcost;
?????
????? // precompute all new chroma intra prediction modes
??? ? //++ 對色度進行幀內預測,并求出最優模式,
??? ? //+++RDO模式下,需要色度預測,保存在currMB->c_ipred_mode中
????? IntraChromaPrediction8x8(&mb_available_up, &mb_available_left, &mb_available_up_left);
??? ? //+++閱讀完IntraChromaPrediction8x8函數的代碼,并且結合下面的代碼,我們可以看到:
??? ? //+++這個函數不做任何運動估計和補償,而僅僅是求出要進行幀內編碼的色度宏塊需要的參考塊
??? ? //+++本來在currMB->c_ipred_mode保存了最佳的模式,但是下面卻被覆蓋掉了
?????
??? ? //++ 分別在四種色度模式下進行 RDO 計算,如果是 inter 模式,因為色度預測模式與 SSD 計算
??? ? //++ 無關,因此只需要計算一次(利用 currMB->c_ipred_mode == DC_PRED_8 條件限制來實現)
????? for (currMB->c_ipred_mode=DC_PRED_8; currMB->c_ipred_mode<=PLANE_8; currMB->c_ipred_mode++)
????? {
???????
??????? // bypass if c_ipred_mode is not allowed
??? ??? ? //+++若當前 c_ipred_mode 模式不被允許,則考慮下一個 c_ipred_mode 模式;
??????? if ((currMB->c_ipred_mode==VERT_PRED_8 && !mb_available_up) ||
????????? (currMB->c_ipred_mode==HOR_PRED_8 && !mb_available_left) ||
????????? (currMB->c_ipred_mode==PLANE_8 && (!mb_available_left || !mb_available_up || !mb_available_up_left)))
????????? continue;
???????
???????
??????? //===== GET BEST MACROBLOCK MODE =====
??????? for (ctr16x16=0, index=0; index<7; index++)
??????? {
??? ??? ??? //+++mb_mode_table[7]? = {0, 1, 2, 3, P8x8, I16MB, I4MB};
????????? mode = mb_mode_table[index];
?????????
????????? //--- for INTER16x16 check all prediction directions ---
????????? if (mode==1 && img->type==B_SLICE)
????????? {
??????????? best8x8pdir[1][0] = best8x8pdir[1][1] = best8x8pdir[1][2] = best8x8pdir[1][3] = ctr16x16;
??????????? if (ctr16x16 < 2) index--;
??????????? ctr16x16++;
????????? }
?????????
????????? img->NoResidueDirect = 0;
?????????
????????? if (valid[mode])
????????? {
??????????? // bypass if c_ipred_mode not used
??? ??? ??? //++ 設置當前宏塊類型以及其中每個8*8塊的分割方式和預測方向,每個4*4塊的參考幀索引
??? ??? ??? //++ 該函數在下面的 RDCost_for_macroblocks 函數內再次調用,進行了重復操作
??????????? SetModesAndRefframeForBlocks (mode);
??????????? if (currMB->c_ipred_mode == DC_PRED_8 ||??? //++ 利用這個條件限制來實現 inter 模式時只計算一次 RDO
????????????? (IS_INTRA(currMB) ))
??????????? {
??? ??? ??? //+++此刻我的理解是:RDCost_for_macroblocks是在模式0-3,P8x8,Intra4x4和Intra16x16之間選擇一個最佳模式
??? ??? ??? //+++這是利用RDO的方法.上面再幀間預測時其實已經將在1-3中選擇出了最佳模式,但那是在非RDO模式下的
??? ??? ??? ??? //+++關于這個地方的RDCost_for_macroblocks我要說明一下:該函數是求出對應mode模式下的RDO代價,然后將這個代價與min_rdcost進行比較
??? ??? ??? ??? //+++如果此時RDO的代價比較小,返回1,執行if,保存相關參數,并且修改min_rdcost,否則返回0,這樣下面的if語句不執行,接著再比較下一個模式.
??? ??? ??? ??? //+++所以我們可以看到(0-3,P8x8,Intra4x4和Intra16x16)這些模式的比較是隨著外面的這個for循環,依次在RDCost_fo...函數中完成的,
????????????? if (RDCost_for_macroblocks (lambda_mode, mode, &min_rdcost))??? //++ 幀內模式時亮度存在重復計算情況:因為色度預測模式與亮度預測模式無關,所以在該色度模
????????????? {??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? //++ 式循環中每次計算得到的 intra16*16 和 intra4*4 宏塊類型的最佳亮度模式都是完全相同的
??????????????? //Rate control
??????????????? if(mode == P8x8)
??????????????? {
????????????????? for (i=0; i<16; i++)
??????????????????? for(j=0; j<16; j++)
????????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - mpr8x8[j][i];
??????????????? }else
??????????????? {
????????????????? for (i=0; i<16; i++)
??????????????????? for(j=0; j<16; j++)
????????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - pred[j][i];
??????????????? }
??????????????? //+++存儲該模式下的一些參數:因為RDCost_for_macroblocks的計算結果是mode模式的預測開銷小于min_rdcost,
??? ??? ??? ??? //+++所以mode模式其實更好,所以現在要保存該模式的一些參數.
??????????????? store_macroblock_parameters (mode);
????????????? }
??????????? }
????????? }
????????? if (valid[0] && bframe && mode == 0 && currMB->cbp && (currMB->cbp&15) != 15) //g050
????????? {
??????????? img->NoResidueDirect = 1;
??????????? if (RDCost_for_macroblocks (lambda_mode, mode, &min_rdcost))
??????????? {
????????????? //Rate control
????????????? for (i=0; i<16; i++)
??????????????? for(j=0; j<16; j++)
????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - pred[j][i];
??????????????? store_macroblock_parameters (mode);
??????????? }
????????? }
??????? }
????? }
??? }
??? else//+++不使用RDO準則的情況
??? {
??? //+++從下面的代碼可以看到,在不同模式下計算出的cost都要和min_cost(幀間預測代價)進行比較
??? //+++然后決定是否更新min_cost和best_mode,所以我們也可以看到,最終的代價也是保存在min_cost中,
??? //+++best_mode對應保存最佳模式,從而用于最后的熵編碼
???
??? //+++下面對Direct,I4MB和I16MB三種模式進行依次比較,代碼是類似的.
????? if (valid[0] && bframe) // check DIRECT MODE
????? {
??????? cost? = (have_direct?cost_direct:Get_Direct_CostMB (lambda_mode));
??????? cost -= (int)floor(16*lambda_motion+0.4999);
??????? if (cost <= min_cost)
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];
??????????? //+++更新min_cost和best_mode
??????????? min_cost? = cost;
??????????? best_mode = 0;
??????? }
????? }
????? if (valid[I4MB]) // check INTRA4x4
????? {
??? ? //+++從Intra4x4的9中模式中選擇最佳的模式,函數Mode_Dec..中的cost就是當前宏塊的代價
??? ? //+++追蹤各個函數,我們可以看到函數調用順序如下:在非RDO模式下調用
??? ? //+++Mode_Decision_for_Intra4x4Macroblock(得到一個宏塊的代價)
??? ? //+++->Mode_Decision_for_8x8IntraBlocks(得到一個8x8塊代價)
??? ? //+++->Mode_Decision_for_Intra4x4Macroblock(得到一個4x4塊代價),
??? ? //+++其實最后一個函數才是真正的Intra4x4模式選擇的核心,在這個函數中包含9中模式的比較(RDO和非RDO)
??????? currMB->cbp = Mode_Decision_for_Intra4x4Macroblock (lambda_mode, &cost);//++ 計算當前宏塊采用intra4*4編碼時的代價和CBP
??????? if (cost <= min_cost)
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];//++ 保存采用intra4*4編碼時最佳模式的殘差塊
???????????? //+++更新min_cost和best_mode
??????????? min_cost? = cost;
??????????? best_mode = I4MB;
??????? }
????? }
????? if (valid[I16MB]) // check INTRA16x16
????? {
??? ? //+++比較與RDO模式下代碼可以發現,其實在RDO模式下進行Intra16x16預測時,調用的函數Intra16x16_Mode_Decision的代碼
??? ? //+++與這兒類似:也是先intrapred_luma_16x16,再find_sad_16x16,最后dct_luma_16x16
??? ? //+++同時這也說明:intra16*16 在進行4種模式選擇時候,無論是否在RDO情況下,其選擇過程是相同的。
??????? intrapred_luma_16x16 ();??? //++ 分別計算當前宏塊在4種intra16*16幀內預測模式下的預測塊
??? ??? ??????????????????????????? //+++intrapred_luma_16x16執行完后,預測的結果保存在數組img->mprr_2中
??????? cost = find_sad_16x16 (&i16mode);??? //++ 計算intra16*16類型的代價(以SATD作為判斷標準,因為該段代碼是不采用RDO的處理過程)
??? ??? ??????????????????????????????????? //+++此時i16mode保存的是Intra16x16的最佳模式,cost是對應的代價
??? ???
??????? if (cost < min_cost)??? //++ 如果采用intra16*16類型編碼的代價小于采用intra4*4類型編碼的代價,則對當前宏塊采用intra16*16類型編碼
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mprr_2[i16mode][j][i];
???????????? //+++更新min_cost和best_mode
??????????? best_mode?? = I16MB;
??? ??? ??? //+++這里說明一下:find_sad_16x16函數中求sad時已經做過DCT變換,但在dct_luma_16x16函數中又要重新做一遍呢?
??? ??? ??? //+++答:前者是對每種預測模式都要做,后者是對最佳模式才做。每種模式做了之后并沒有把結果都保存起來,所以要對最佳模式重新再做一次。
??????????? currMB->cbp = dct_luma_16x16 (i16mode);??? //++ 對當前宏塊采用intra16*16類型進行編碼,并計算CBP
??????? }
????? }
??? }
??? //+++通過比較RDO模式與非RDO模式我們可以發現,
??? //+++在intra4*4與intra16*16之間做選擇時,RDO情況下色度要參與計算,而非RDO情況下色度不參與計算
??? //+++并且我們可以看到在非RDO模式下,具體的幀內預測還是幀間預測的選擇在這兒完成(可以在這兒看到具體的代碼)
??? //+++但是對于RDO模式,具體的幀內還是幀間的選擇卻是在函數RDCost_for_macroblocks中完成的.
//+++幀內預測結束
//===================================
??? if (rerun==0)
??? {
????? intra1 = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? }
? } // for (rerun=0; rerun<runs; rerun++)
? //+++到現在,幀內和幀間模式的選擇終于結束
?
? //+++下面的要進行存儲編碼參數,分RDO和非RDO
? //+++印證了[h264率失真RDO研究]一文中的一句:
? //+++"如果用RDO代價函數,因為計算代價時已經編碼,擇優后僅需對編碼進行存儲;
? //+++如果用非RDO代價函數,則擇優后還要進行編碼過程,編碼后存儲參數."
? //+++從下面的代碼我們也可清楚的看到
? if (input->rdopt)
? {
???
??? if ((cbp!=0 || best_mode==I16MB ))
????? currMB->prev_cbp = 1;
??? else if (cbp==0 && !input->RCEnable)
??? {
????? currMB->delta_qp = 0;
????? currMB->qp = currMB->prev_qp;
????? img->qp = currMB->qp;
????? currMB->prev_cbp = 0;
??? }
//+++存儲編碼參數
??? set_stored_macroblock_parameters ();
//+++??? (1)保存重建圖像
//+++??? rdopt->rec_mbY[j][i] = rec_mbY[j][i];
//+++??? rdopt->rec_mbU[j][i] = rec_mbU[j][i];??
//+++??? rdopt->rec_mbV[j][i] = rec_mbV[j][i];?
//+++??? (2)變換系數和cbp
//+++??? img->cofAC=i4p(cofAC);
//+++??? img->cofDC=i3p(cofDC);
//+++??? currMB->cbp????? = cbp;
//+++??? currMB->cbp_blk = cbp_blk;
//+++??? (3)宏塊模式
//+++??? currMB->mb_type = mode(best_mode);
//+++??? (4)參考幀保存
//+++??? rdopt.c 1511行,對前向參考,后向參考幀分別進行了保存
//+++??? (5)幀內預測模式
//+++??? currMB->c_ipred_mode = best_c_imode;
//+++??? (6)為當前塊保存運動向量
//+++??? SetMotionVectorsMB (currMB, bframe);
//+++??? 從上面其實可以看到"="右邊的量在rdopt.c中都是全局變量,在完成encode_one_macroblock之前,對這些參數進行一下保存.
? }
? else
? {
??? //===== set parameters for chosen mode =====
??? SetModesAndRefframeForBlocks (best_mode);??? //++ 設置當前宏塊的參數,包括:宏塊類型(mb_type)、4個8*8塊的分割模式和預測方向(b8mode,b8pdir)、16個4*4塊的參考幀索引(ref_idx,ref_pic_id)
??? if (best_mode==P8x8)
??? {
????? SetCoeffAndReconstruction8x8 (currMB);
??? }
??? else
??? {
????? if (best_mode!=I4MB)
????? {
??????? for (k=0, j=img->block_y; j<img->block_y+4; j++)
????????? for (???? i=img->block_x; i<img->block_x+4; i++, k++)
????????? {
??????????? ipredmodes??? [i][j] = DC_PRED;
??????????? currMB->intra_pred_modes[k] = DC_PRED;
????????? }
????????? if (best_mode!=I16MB)
????????? {
??????????? LumaResidualCoding ();
??????????? //Rate control
??????????? for (i=0; i<16; i++)
????????????? for(j=0; j<16; j++)
??????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];
????????? }
????? }
??? }
??? //+++
??? // precompute all chroma intra prediction modes
??? IntraChromaPrediction8x8(NULL, NULL, NULL);??? //++ 對色度塊進行處理,包括:分別計算4種色度幀內預測模式下的預測塊、代價(該分支未采用RDO,因此以SATD作為判斷標準)、最佳預測模式
??? img->i16offset = 0;
??? dummy = 0;
??? ChromaResidualCoding (&dummy);
??? if (best_mode==I16MB)
??? {
????? img->i16offset = I16Offset? (currMB->cbp, i16mode);
??? }
??? SetMotionVectorsMB (currMB, bframe);
???
??? //===== check for SKIP mode =====
??? if ((img->type==P_SLICE || img->type==SP_SLICE) && best_mode==1 && currMB->cbp==0 &&
????? enc_picture->ref_idx[LIST_0][img->block_x][img->block_y]==0 &&
????? enc_picture->mv[LIST_0][img->block_x][img->block_y][0]==allmvs[0][0][0][0][0][0] &&
????? enc_picture->mv[LIST_0][img->block_x][img->block_y][1]==allmvs[0][0][0][0][0][1]?????????????? )
??? {
????? currMB->mb_type=currMB->b8mode[0]=currMB->b8mode[1]=currMB->b8mode[2]=currMB->b8mode[3]=0;
??? }
???
??? if(img->MbaffFrameFlag)
????? set_mbaff_parameters();
? }
?
? // Rate control
? if(input->RCEnable)
? {??
??? if(img->type==P_SLICE)
??? {
????? img->MADofMB[img->current_mb_nr] = calc_MAD();
?????
????? if(input->basicunit<img->Frame_Total_Number_MB)
????? {
??????? img->TotalMADBasicUnit +=img->MADofMB[img->current_mb_nr];
???????
??????? /* delta_qp is present only for non-skipped macroblocks*/
??????? if ((cbp!=0 || best_mode==I16MB))
????????? currMB->prev_cbp = 1;
??????? else
??????? {
????????? img->qp -= currMB->delta_qp;
????????? currMB->delta_qp = 0;
????????? currMB->qp = img->qp;
????????? currMB->prev_cbp = 0;
??????? }
??????? /* When MBAFF is used, delta_qp is only present for the first non-skipped macroblock of each
??????? macroblock pair*/
??????? if (input->MbInterlace)
??????? {
????????? if(!currMB->mb_field)
????????? {
??????????? DELTA_QP = currMB->delta_qp;
??????????? QP????? = currMB->qp;
????????? }
????????? else
????????? {
??????????? DELTA_QP2 = currMB->delta_qp;
??????????? QP2????? = currMB->qp;
????????? }
??????? }??????
????? }
??? }
? }
?
?? //+++保存最佳代價在rdopt->min_rdcost中
? if(input->rdopt)
??? rdopt->min_rdcost = min_rdcost;
? else
??? rdopt->min_rdcost = min_cost;
? if(img->MbaffFrameFlag)
? {
??? if (img->current_mb_nr%2) //bottom
??? {
????? if ((currMB->mb_type ? 0:((img->type == B_SLICE) ? !currMB->cbp:1))? // bottom is skip
??????? &&(prevMB->mb_type ? 0:((img->type == B_SLICE) ? !prevMB->cbp:1))) // top is skip
????? {
??????? if (!(field_flag_inference() == curr_mb_field))
??????? {
????????? rdopt->min_rdcost = 1e30;? // don't allow coding of an MB pair as skip if wrong inference
??????? }
????? }
??? }
? }
?
? //+++RestrictRefFrames應該是和容錯有關系的。我的理解是,如果某個區域在后面幀里被intra方式update(從而可以避免錯誤傳播),
? //+++這個區域很可能是出現錯誤的區域,因此,不使用這個區域作參考以避免錯誤傳播。請大家指正
? //===== Decide if this MB will restrict the reference frames =====
? if (input->RestrictRef==1)
? {
??? if (input->rdopt==1)
??? {
????? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (intra ? 1 : 0);
??? }
??? else if (input->rdopt==2)
??? {
????? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
??? }
? }
? else if (input->RestrictRef==2)
? {
??? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
? }
?
? if(input->FMEnable)
??? skip_intrabk_SAD(best_mode, listXsize[LIST_0+list_offset]);
}//+++void encode_one_macroblock(),該函數終于完成了
?*************************************************************************************
?* /brief
?*??? Mode Decision for a macroblock
?*??? //+++該函數的作用是編碼一個宏塊(包括幀間、幀內、幀內預測的方式)。
?*??? NOTE:從上面程序段中可以看出JM8.5中對7種宏塊模式是采用全部遍歷的方式,所以導致的計算復雜度很高。
?*************************************************************************************
?*/
?void encode_one_macroblock ()
?{
?? static const int? b8_mode_table[6]? = {0, 4, 5, 6, 7};???????? // DO NOT CHANGE ORDER !!!???
?? // //++ B片子宏塊類型。0:Direct_8*8,4:8*8,5:8*4,6:4*8,7:4*4
?? static const int? mb_mode_table[7]? = {0, 1, 2, 3, P8x8, I16MB, I4MB}; // DO NOT CHANGE ORDER !!!
??? //+++//??? 0:16X16 Direct模式,在B幀中有效 ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 1:Inter16X16,在幀間有效??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 2:Inter16X8,在幀間有效??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // ??? ?? 3:Inter8X16,在幀間有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // P8X8:幀間有效:包括Inter8x8,Inter8x4,Inter4x8,Inter4x4??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I16MB:Intra16X16幀內有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I4MB:Intra有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // I8MB:Intra有效??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??? ??? // IPCM:Intra有效,不要預測,直接對RAW數據編碼.??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
??
?? int???????? valid[MAXMODE];
?? int???????? rerun, block, index, mode, i0, i1, j0, j1, pdir, ref, i, j, k, ctr16x16, dummy;
?? double????? qp, lambda_mode, lambda_motion, min_rdcost, rdcost = 0, max_rdcost=1e30;
?? int???????? lambda_motion_factor;
?? int???????? fw_mcost, bw_mcost, bid_mcost, mcost, max_mcost=(1<<30);
?? int???????? curr_cbp_blk/*+++當前宏塊每個 4*4 塊是否有非零系數,跟CBP功能類似,CBP 是表示的每個8*8 塊*/,
?????????????? cnt_nonz = 0, best_cnt_nonz = 0, best_fw_ref = 0, best_pdir;
?? int???????? cost=0;
?? int???????? min_cost = max_mcost, min_cost8x8, cost8x8, cost_direct=0, have_direct=0, i16mode;
?? //+++根據對下面代碼的閱讀,這兒有比較要說明一下上面聲明的一些變量,這對于理解代碼很重要.
?? //+++首先,要提到best_mode,我本來以為這個量是在本函數中聲明的一個變量,然后仔細在上面尋找,都沒有找到,后來才發現,
?? //+++wow,原來best_mode在這個文件(rdopt.c)的開頭聲明過,是本文件的一個全局變量,yes,終于明白這個了
?? //+++其次,對于上面的一些變量,介紹一下:
?? //+++min_rdcost是用來保存RDO模式下的最小代價;min_cost則是非RDO模式下的代價
?? //+++min_cost8x8是亞宏塊級(P8x8)非RDO模式下最小模式代價;cost8x8是宏塊(16x16)中4個8x8塊的代價和(每一個8x8都是最佳代價min_cost8x8)
?? //+++fw_mcost,bw_mcost和bid_mcost是中間變量用來記錄(前向,后向和雙向)最佳參考幀對應的代價
?? //+++cost是一個中間變量,主要是在非RDO模式下,(幀間預測)記錄宏塊級或亞宏塊級中某一個模式中所有塊(16x16是1塊,16x8是2塊...)的所有代價之和(參考幀代價,運動估計)
?? //+++mcost也是一個中間變量,也是非RDO模式下,在進行最優參考幀時,用于累加代價之和(參考幀代價,運動估計)
??
?? int???????? intra1 = 0;
??
?? int???????? intra?????? = (((img->type==P_SLICE||img->type==SP_SLICE) && img->mb_y==img->mb_y_upd && img->mb_y_upd!=img->mb_y_intra) || img->type==I_SLICE);
?? int???????? spframe???? = (img->type==SP_SLICE);
?? int???????? siframe???? = (img->type==SI_SLICE);
?? int???????? bframe????? = (img->type==B_SLICE);
?? int???????? runs??????? = (input->RestrictRef==1 && input->rdopt==2 && (img->type==P_SLICE || img->type==SP_SLICE || (img->type==B_SLICE && img->nal_reference_idc>0)) ? 2 : 1);
??
?? int???????? checkref??? = (input->rdopt && input->RestrictRef && (img->type==P_SLICE || img->type==SP_SLICE));
?? Macroblock* currMB????? = &img->mb_data[img->current_mb_nr];
?? Macroblock* prevMB????? = img->current_mb_nr ? &img->mb_data[img->current_mb_nr-1]:NULL ;
??
?? int???? **ipredmodes = img->ipredmode;//+++ipredmode幀內預測模式
?? int???? best_bw_ref = -1;
?? int???? ******allmvs = img->all_mv;
??
?? int? l,list_offset;
?? int curr_mb_field = ((img->MbaffFrameFlag)&&(currMB->mb_field));
?? // find out the correct list offsets
?? if (curr_mb_field)
?? {
???? if(img->current_mb_nr%2)
?????? list_offset = 4; // bottom field mb
???? else
?????? list_offset = 2; // top field mb
?? }
?? else
?? {
???? list_offset = 0;? // no mb aff or frame mb
?? }
?? if(input->FMEnable)
???? decide_intrabk_SAD();
??
?? intra |= RandomIntra (img->current_mb_nr);??? // Forced Pseudo-Random Intra
?? //===== SET VALID MODES =====
?? valid[I4MB]?? = 1;??? //++ 宏塊可以采用intra4*4模式編碼
?? valid[I16MB]? = 1;??? //++ 宏塊可以采用intra16*16模式編碼
??
?? valid[0]????? = (!intra );??? //++ 宏塊是否采用inter模式編碼
?? valid[1]????? = (!intra && input->InterSearch16x16);??? //++ 宏塊是否采用inter16*16模式編碼
?? valid[2]????? = (!intra && input->InterSearch16x8);??? //++ 宏塊是否采用inter16*8模式編碼
?? valid[3]????? = (!intra && input->InterSearch8x16);??? //++ 宏塊是否采用inter8*16模式編碼
?? valid[4]????? = (!intra && input->InterSearch8x8);??? //++ 宏塊是否采用inter8*8模式編碼
?? valid[5]????? = (!intra && input->InterSearch8x4);??? //++ 宏塊是否采用inter8*4模式編碼
?? valid[6]????? = (!intra && input->InterSearch4x8);??? //++ 宏塊是否采用inter4*8模式編碼
?? valid[7]????? = (!intra && input->InterSearch4x4);??? //++ 宏塊是否采用inter4*4模式編碼
?? valid[P8x8]?? = (valid[4] || valid[5] || valid[6] || valid[7]);??? //++ 宏塊是否采用亞宏塊模式編碼?? +++P8x8=8
?? valid[12]???? = (siframe);??? //++ 宏塊是否采用SI模式編碼
?? if (!img->MbaffFrameFlag)//+++//在非宏塊級幀場自適應且是場模式下 進行色度矢量校正
?? {
???? for (l=0+list_offset;l<(2+list_offset);l++)
???? {
?????? for(k = 0; k < listXsize[l]; k++)
?????? {
???????? listX[l][k]->chroma_vector_adjustment= 0;
???????? if(img->structure == TOP_FIELD && img->structure != listX[l][k]->structure)
?????????? listX[l][k]->chroma_vector_adjustment = -2;
???????? if(img->structure == BOTTOM_FIELD && img->structure != listX[l][k]->structure)
?????????? listX[l][k]->chroma_vector_adjustment = 2;
?????? }
???? }
?? }
?? else
?? {
???? if (curr_mb_field)
???? {
?????? for (l=0+list_offset;l<(2+list_offset);l++)
?????? {
???????? for(k = 0; k < listXsize[l]; k++)
???????? {
?????????? listX[l][k]->chroma_vector_adjustment= 0;
?????????? if(img->current_mb_nr % 2 == 0 && listX[l][k]->structure == BOTTOM_FIELD)
???????????? listX[l][k]->chroma_vector_adjustment = -2;
?????????? if(img->current_mb_nr % 2 == 1 && listX[l][k]->structure == TOP_FIELD)
???????????? listX[l][k]->chroma_vector_adjustment = 2;
???????? }
?????? }
???? }
???? else
???? {
?????? for (l=0+list_offset;l<(2+list_offset);l++)
?????? {
???????? for(k = 0; k < listXsize[l]; k++)
???????? {
?????????? listX[l][k]->chroma_vector_adjustment= 0;
???????? }
?????? }
???? }
????
?? }
//+++ 設置RDO與非RDO下的lambda系數
?? //===== SET LAGRANGE PARAMETERS =====
?? if (input->rdopt)
?? {
???? qp = (double)img->qp - SHIFT_QP;??? //++ ???
???? if (input->successive_Bframe>0)
?????? lambda_mode?? = 0.68 * pow (2, qp/3.0) * (img->type==B_SLICE? max(2.00,min(4.00,(qp / 6.0))):spframe?max(1.4,min(3.0,(qp / 12.0))):1.0);?
???? else
?????? lambda_mode?? = 0.85 * pow (2, qp/3.0) * (img->type==B_SLICE? 4.0:spframe?max(1.4,min(3.0,(qp / 12.0))):1.0);?
???? lambda_motion = sqrt (lambda_mode);
?? }
?? else
?? {
???? lambda_mode = lambda_motion = QP2QUANT[max(0,img->qp-SHIFT_QP)];
?? }
?? lambda_motion_factor = LAMBDA_FACTOR (lambda_motion);??? //++ 使用該變量的原因主要是為了在運算過程中使用定點運算但又能提高精度
??
??
?? for (rerun=0; rerun<runs; rerun++)??? //++ runs=2是針對loss rdo模式,其余的情況runs=1
?? {
???? if (runs==2)
???? {
?????? if (rerun==0)?? input->rdopt=1;
?????? else??????????? input->rdopt=2;
???? }
????
???? // reset chroma intra predictor to default
???? currMB->c_ipred_mode = DC_PRED_8;
//+++++++++++++++++++++++++++
//+++幀間預測,計算其選擇合適模式后的開銷
??? ?//+++(根據拉格朗日率失真準則)
???? if (!intra)
???? {
??? ??? ?//+++B幀的直接模式預測
?????? //===== set direct motion vectors =====
?????? if (bframe)//+++P幀無direct模式 但有skip模式
?????? {
???????? Get_Direct_Motion_Vectors ();//+++不返回direct模式代價
?????? }
?????? //+++//宏塊級運動估計
?????? //===== MOTION ESTIMATION FOR 16x16, 16x8, 8x16 BLOCKS =====
?????? for (min_cost=1<<20, best_mode=1, mode=1; mode<4; mode++)
?????? {
???????? if (valid[mode])//+++//對應于程序外部(即CFG文件中)的設置
???????? {
??? ??? ?//+++//對于16x16,MB只分一個塊;對于16x8和8x16,MB被分成兩個塊
?????????? for (cost=0, block=0; block<(mode==1?1:2); block++)??? //++ 16*16 分割方式只需要計算一次,16*8 和 8*16 分割方式需要計算兩次
?????????? {
??? ??? ?? //+++/塊匹配!!!lambda_motion用來求運動矢量消耗的碼率
???????????? PartitionMotionSearch (mode, block, lambda_motion);??? //++ 對 16*16、16*8、8*16 分割方式進行 ME
???????????? //--- set 4x4 block indizes (for getting MV) ---
???????????? j = (block==1 && mode==2 ? 2 : 0);??? //++ 如果現在處理的是 16*8 分割方式的第 2 個分割,則 j=2
???????????? i = (block==1 && mode==3 ? 2 : 0);??? //++ 如果現在處理的是 8*16 分割方式的第 2 個分割,則 i=2
??? ??? ??? ?//+++通過循環在list0中尋找前向預測的最佳參考幀(best_fw_ref),代價為fw_mcost,
???????????? //--- get cost and reference frame for forward prediction ---
???????????? for (fw_mcost=max_mcost, ref=0; ref<listXsize[LIST_0+list_offset]; ref++)
???????????? {
?????????????? if (!checkref || ref==0 || CheckReliabilityOfRef (block, LIST_0, ref, mode))
?????????????? {
??? ??? ??? ??? ??? //++ 參考幀索引號編碼所需要使用的比特數作為編碼代價的一部分
??? ??? ??? ??? ?? //+++這個地方就是利用拉格朗日進行計算開銷的函數,事實上,這個地方要考慮很多東西的開銷,可以發現,下面的代碼中還要加上其他的
??? ??? ??? ??? ?? //+++mcost->(1)REF_COST參考幀代價
???????????????? mcost? = (input->rdopt ? REF_COST (lambda_motion_factor, ref, LIST_0 + list_offset) : (int)(2*lambda_motion*min(ref,1)));
??? ??? ??? ??? ?//+++motion_cost(運動搜索代價)是一個全局變量,其值在PartitionMotionSearch函數內進行過改變
??? ??? ??? ??? ?//+++so 此時motion_cost就是保存的相應的運動搜索代價
??? ??? ??? ??? ?//+++那么,mcost->(2)motion_cost運動搜索代價
???????????????? mcost += motion_cost[mode][LIST_0][ref][block];//+++可以發現motion_cost數組的參數mode,block和
??? ??? ??? ??? ?????????????????????????????????????????????? //+++PartitionMotionSearch(PMS)函數的參數是一致的,并且在PMS函數中
??? ??? ??? ??? ????????????????????????????????????????????? //+++計算motion_cost時也是對ref(參考幀)進行循環的,所以將兩者聯系起來
??? ??? ??? ??? ???????????????????????????????????????????? //+++我們就可以理解這兒motion_cost的數組中參數的含義了.
??? ??? ??? ??? ??????????????????????????????????????????? //+++另外在[JM86核心函數研究]中有對motion_cost的詳細介紹
??? ??? ??? ??? ?????????????????????????????????????????? //+++該數組存儲了一個宏塊的分塊在不同幀間模式和參考幀下的運動估計的開銷值。
??? ??? ??? ??? ????????????????????????????????????????? //+++函數PartitionMotionSearch的主要任務就是更新該數組。同時,該數組也在決定最佳參考幀時被引用。
???????????????? if (mcost < fw_mcost)//+++根據參考代價選出該模式下的最佳參考幀
???????????????? {
??? ??? ??? ??? ??? ?//+++記錄最佳參考幀及預測代價
?????????????????? fw_mcost??? = mcost;
?????????????????? best_fw_ref = ref;
???????????????? }
?????????????? }
???????????? }
??? ??? ??? ?//+++B幀還需記錄向后及雙向預測的各個參考幀與參考代價
???????????? if (bframe)
???????????? {
?????????????? //--- get cost for bidirectional prediction ---
?????????????? for (bw_mcost=max_mcost, ref=0; ref<listXsize[LIST_1 + list_offset]; ref++)
?????????????? {//+++B幀的計算方法與I,P幀不一樣
???????????????? mcost? = (input->rdopt ? REF_COST (lambda_motion_factor, ref, LIST_1 + list_offset) : (int)(2*lambda_motion*min(ref,1)));
???????????????? mcost += motion_cost[mode][LIST_1][ref][block];
???????????????? if (mcost < bw_mcost)
???????????????? {
?????????????????? bw_mcost??? = mcost;
?????????????????? best_bw_ref = ref;
???????????????? }
?????????????? }
?????????????? // search bidirectional between best forward and ref_idx=0 backward
?????????????? bid_mcost? = (input->rdopt ? (REF_COST (lambda_motion_factor, best_fw_ref,LIST_0+list_offset)+REF_COST (lambda_motion_factor, 0,LIST_1+list_offset)) : (int)(2*lambda_motion*min(best_fw_ref,1)));
?????????????? bid_mcost += BIDPartitionCost (mode, block, best_fw_ref, 0, lambda_motion_factor);
?????????????? //--- get prediction direction ----
?????????????? if (fw_mcost<=bw_mcost && fw_mcost<=bid_mcost)
?????????????? {
???????????????? best_pdir = 0;
???????????????? best_bw_ref = 0;
???????????????? cost += fw_mcost;
?????????????? }
?????????????? else if (bw_mcost<=fw_mcost && bw_mcost<=bid_mcost)
?????????????? {
???????????????? best_pdir = 1;
???????????????? cost += bw_mcost;
???????????????? best_fw_ref = 0;
?????????????? }
?????????????? else
?????????????? {
???????????????? best_pdir = 2;
???????????????? cost += bid_mcost;
???????????????? best_bw_ref = 0;
?????????????? }
???????????? }
???????????? else // if (bframe)
???????????? {
?????????????? best_pdir? = 0;//+++best_pdir是最佳預測方向,對于非B幀(P幀)預測方向就一個直接設置為0,而對于
??? ??? ??? ????????????????? //+++B幀要從三種方式(前向,后向,雙向)中選擇一個,從上面if中的代碼中我們就可以看出來
?????????????? cost????? += fw_mcost;
???????????? }
??? ??? ??? ?//+++下面要記錄參考幀和MV信息,說明一下:這些全局變量是作為BlockMotionSearch()中運動搜索時運動向量預測的依據
??? ??? ??? ?//+++問:下一宏塊的運動向量等信息也用當前宏塊的運動向量預測嗎?答:ME 算法是開放部分,你想怎么做就怎么做。JM 在 ME 時會用到相鄰塊的 MV;
??? ??? ??? ?//+++對于MB是以4*4的塊為單位來記錄mv和ref的
???????????? if (mode==1)//+++16x16
???????????? {
?????????????? if (best_pdir==1)//+++后向參考
?????????????? {
???????????????? for (j=0; j<4; j++)
???????????????? {
?????????????????? for (i=0; i<4; i++)
?????????????????? {
??? ??? ??? ??? ??? ?? //+++保存參考信息至重建單元,B幀多做后項參考
??? ??? ??? ??? ?? //+++enc_picture 中好像是最終數據,img 中存的是中間數據
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = 0;
?????????????????? }
???????????????? }
?????????????? }
?????????????? else
?????????????? {
???????????????? for (j=0; j<4; j++)
???????????????? {
?????????????????? for (i=0; i<4; i++)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];?
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][1];
?????????????????? }
???????????????? }
?????????????? }
?????????????? if (bframe)
?????????????? {
???????????????? if (best_pdir==0)
???????????????? {
?????????????????? for (j=0; j<4; j++)
?????????????????? {
???????????????????? for (i=0; i<4; i++)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = -1;??
?????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = 0;
???????????????????? }
?????????????????? }
???????????????? }
???????????????? else
???????????????? {
?????????????????? for (j=0; j<4; j++)
?????????????????? {
???????????????????? for (i=0; i<4; i++)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
???????????? else if (mode==2)//+++16x8
???????????? {
?????????????? for (j=0; j<2; j++)
?????????????? {
???????????????? for (i=0; i<4; i++)
???????????????? {
?????????????????? if (best_pdir==1)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+i][img->block_y+block*2+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][1] = 0;
?????????????????? }
?????????????????? else
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+i][img->block_y+block*2+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+i][img->block_y+block*2+j]];
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][0] = img->all_mv[i][j+block*2][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+i][img->block_y+block*2+j][1] = img->all_mv[i][j+block*2][LIST_0][best_fw_ref][mode][1];
?????????????????? }
?????????????????? if (bframe)
?????????????????? {
???????????????????? if (best_pdir==0)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+i][img->block_y+block*2+j] = -1;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][1] = 0;
???????????????????? }
???????????????????? else
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+i][img->block_y+block*2+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+i][img->block_y+block*2+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+i][img->block_y+block*2+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
???????????? else//+++8x16
???????????? {
?????????????? for (j=0; j<4; j++)
?????????????? {
???????????????? for (i=0; i<2; i++)
???????????????? {
?????????????????? if (best_pdir==1)
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j] = -1;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+block*2+i][img->block_y+j] = -1;
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][0] = 0;
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][1] = 0;
?????????????????? }
?????????????????? else
?????????????????? {
???????????????????? enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j] = best_fw_ref;
???????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+block*2+i][img->block_y+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+block*2+i][img->block_y+j]];
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][0] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][0];
???????????????????? enc_picture->mv[LIST_0][img->block_x+block*2+i][img->block_y+j][1] = img->all_mv[i][j][LIST_0][best_fw_ref][mode][1];
?????????????????? }
?????????????????? if (bframe)
?????????????????? {
???????????????????? if (best_pdir==0)
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j] = -1;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+block*2+i][img->block_y+j] = -1;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][0] = 0;
?????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][1] = 0;
???????????????????? }
???????????????????? else
???????????????????? {
?????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j] = best_bw_ref;
?????????????????????? enc_picture->ref_pic_id [LIST_1][img->block_x+block*2+i][img->block_y+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+block*2+i][img->block_y+j]];
?????????????????????? if(best_bw_ref>=0)
?????????????????????? {
???????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][0] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][0];
???????????????????????? enc_picture->mv[LIST_1][img->block_x+block*2+i][img->block_y+j][1] = img->all_mv[i][j][LIST_1][best_bw_ref][mode][1];
?????????????????????? }
???????????????????? }
?????????????????? }
???????????????? }
?????????????? }
???????????? }
??? ??? ??? ?//+++以8x8塊記錄各個模式的預測信息 每個分割的8x8相同
??? ??? ??? ?//+++此處解釋一下best8x8fwref:: 該2維數組存儲了一個宏塊的4個8x8block在各個幀間預測模式下的最佳前向參考幀。
??? ??? ??? ?//+++上面的代碼完成了最佳參考幀的選擇,所以這兒將最佳參考幀的信息存儲在這個數組中。在計算預測值時,程序會引用該數組作為參考。
???????????? //----- set reference frame and direction parameters -----
???????????? if (mode==3)//+++兩個16x8:如果以8x8為單位,分別擁有(0,2)和(1,3)
???????????? {
?????????????? best8x8fwref?? [3][block] = best8x8fwref?? [3][block+2] = best_fw_ref;
?????????????? best8x8pdir??? [3][block] = best8x8pdir??? [3][block+2] = best_pdir;
?????????????? best8x8bwref?? [3][block] = best8x8bwref?? [3][block+2] = best_bw_ref;
???????????? }
???????????? else if (mode==2)//+++兩個8x16:如果以8x8為單位,分別擁有(0,1)和(2,3)
???????????? {
?????????????? best8x8fwref?? [2][2*block] = best8x8fwref?? [2][2*block+1] = best_fw_ref;
?????????????? best8x8pdir??? [2][2*block] = best8x8pdir??? [2][2*block+1] = best_pdir;
?????????????? best8x8bwref?? [2][2*block] = best8x8bwref?? [2][2*block+1] = best_bw_ref;
???????????? }
???????????? else//+++一個16x16:如果以8x8為單位,(0,1,2,3)的設置是一樣的
???????????? {
?????????????? best8x8fwref?? [1][0] = best8x8fwref?? [1][1] = best8x8fwref?? [1][2] = best8x8fwref?? [1][3] = best_fw_ref;
?????????????? best8x8pdir??? [1][0] = best8x8pdir??? [1][1] = best8x8pdir??? [1][2] = best8x8pdir??? [1][3] = best_pdir;
?????????????? best8x8bwref?? [1][0] = best8x8bwref?? [1][1] = best8x8bwref?? [1][2] = best8x8bwref?? [1][3] = best_bw_ref;
???????????? }
??? ??? ??? ?
???????????? //--- set reference frames and motion vectors ---
???????????? if (mode>1 && block==0)? //+++mode>1,說明mode=2和3的時候執行,block==0,說明是對第一個分塊.
??? ??? ??? ???????????????????????? //+++這里說明一下:對于16x8,8x16來說,只有兩個宏塊分割,這里保存第一塊分割的運動信息,目的是給下一個分割做運動矢量預測使用
??? ??? ??? ??????????????????????? //+++由于前一個分割不需要下一個分割的運動矢量信息,因此只需要保存前一個分割即可.
??? ??? ??? ?????????????????????? //+++另外,在這之前,事實上已經保存過,所以這里是重復保存了
?????????????? SetRefAndMotionVectors (block, mode, best_pdir, best_fw_ref, best_bw_ref);
????????? } // for (block=0; block<(mode==1?1:2); block++)
??? ??? ? //+++我在這個地方解釋一下cost與min_cost:min_cost是為了尋找三種宏塊模式(16x16,16x8,8x16)中代價最小的模式
??? ??? ? //+++由于宏塊模式在計算的時候是進一步分成小塊計算的,所以cost就是用來保存一種宏塊模式下對應所有小塊的代價之和
??? ??? ? //+++模式16x16下:cost對應一個16x16大小的塊;模式16x8模式下:cost對應兩個16x8大小的塊......
??? ??? ? //+++所以下面這一個if語句就是在尋找代價最小的宏塊模式(best_mode)
????????? if (cost < min_cost)
????????? {
??????????? best_mode = mode;
??????????? min_cost? = cost;
????????? }
??????? } // if (valid[mode])
????? } // for (mode=1; mode<4; mode++)//+++宏塊級模式結束
????? //+++現在宏塊級運動估計結束,best_mode保存了最佳的宏塊模式,min_cost記錄其對應的代價
??? ? //+++亞宏塊級運動估計
????? if (valid[P8x8])
????? {
??????? cost8x8 = 0;
???????
??????? //===== store coding state of macroblock =====
??????? store_coding_state (cs_mb);
??????? //+++遍歷16x16宏塊的4個8x8塊
??????? //=====? LOOP OVER 8x8 SUB-PARTITIONS? (Motion Estimation & Mode Decision) =====
??????? for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++)
???????
??? ??? {
????????? //--- set coordinates ---
????????? j0 = ((block/2)<<3);??? j1 = (j0>>2);
????????? i0 = ((block%2)<<3);??? i1 = (i0>>2);
??? ??? ? //+++對宏塊中的每個8x8塊的模式循環
??? ??? ? //+++這個地方解釋一下:min_cost8x8用于記錄非RDO模式下的最小代價,而min_rdcost則是RDO模式下的最小代價
????????? //=====? LOOP OVER POSSIBLE CODING MODES FOR 8x8 SUB-PARTITION? =====
????????? for (min_cost8x8=(1<<20), min_rdcost=1e30, index=(bframe?0:1); index<5; index++)
????????? {
??????????? if (valid[mode=b8_mode_table[index]])//+++b8_mode_table[6] = {0, 4, 5, 6, 7};
??????????? {
??? ??? ??? ??? curr_cbp_blk = 0;//+++初始化當前cbp_blk
?????????????
????????????? if (mode==0)
????????????? {
??????????????? //--- Direct Mode ---
??????????????? if (!input->rdopt)
??????????????? {
????????????????? cost_direct += (cost = Get_Direct_Cost8x8 ( block, lambda_mode ));
????????????????? if (cost==1<<30)
??????????????????? cost_direct = (1<<30);
??? ??? ??? ??? ? have_direct ++;//+++記錄是否做過direct模式的標記
??????????????? }
??????????????? best_fw_ref = direct_ref_idx[LIST_0][img->block_x+(block&1)*2][img->block_y+(block&2)];
??????????????? best_bw_ref = direct_ref_idx[LIST_1][img->block_x+(block&1)*2][img->block_y+(block&2)];
??????????????? best_pdir?? = direct_pdir[img->block_x+(block&1)*2][img->block_y+(block&2)];
????????????? } // if (mode==0)
??? ??? ??? ? else//+++非direct模式下
????????????? {
??????????????? //--- motion estimation for all reference frames ---
??????????????? PartitionMotionSearch (mode, block, lambda_motion);
??????????????? //+++這一部分與宏塊級的類似
??????????????? //--- get cost and reference frame for forward prediction ---
??????????????? for (fw_mcost=max_mcost, ref=0; ref<listXsize[LIST_0+list_offset]; ref++)
??????????????? {
????????????????? if (!checkref || ref==0 || CheckReliabilityOfRef (block, LIST_0, ref, mode))
????????????????? {
??? ??? ??? ??? ? //+++(1)參考幀代價
??????????????????? mcost? = (input->rdopt ? REF_COST(lambda_motion_factor,ref,LIST_0+list_offset) : (int)(2*lambda_motion*min(ref,1)));
??????????????????? //+++(2)MV代價
??????????????????? mcost += motion_cost[mode][LIST_0][ref][block];
??????????????????? if (mcost < fw_mcost)
??????????????????? {
????????????????????? fw_mcost??? = mcost;
????????????????????? best_fw_ref = ref;
??????????????????? }
????????????????? }
??????????????? }
???????????????
??????????????? //store forward reference index for every block
??????????????? for (j=0; j<2; j++)
????????????????? for (i=0; i<2; i++)
????????????????? {
??????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
??????????????????? enc_picture->ref_pic_id [LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_0 + list_offset][enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];
????????????????? }
??????????????? //+++B幀有所不同,還要考慮后向和雙向模式,其實與上面的代碼是相似的
??????????????? if (bframe)
??????????????? {
??? ??? ??? ???
????????????????? for (bw_mcost=max_mcost, ref=0; ref<listXsize[LIST_1+list_offset]; ref++)
????????????????? {
??????????????????? mcost? = (input->rdopt ? REF_COST(lambda_motion_factor,ref,LIST_1+list_offset) : (int)(2*lambda_motion*min(ref,1)));
???????????????????
??????????????????? mcost += motion_cost[mode][LIST_1][ref][block];
??????????????????? if (mcost < bw_mcost)
??????????????????? {
????????????????????? bw_mcost??? = mcost;
????????????????????? best_bw_ref = ref;
??????????????????? }
????????????????? }
?????????????????
????????????????? // bidirectional uses best forward and zero backward reference
????????????????? bid_mcost? = (input->rdopt ? (REF_COST (lambda_motion_factor, best_fw_ref, LIST_0 + list_offset)+REF_COST (lambda_motion_factor, 0, LIST_1 + list_offset)) : (int)(2*lambda_motion*min(best_fw_ref,1)));
????????????????? bid_mcost += BIDPartitionCost (mode, block, best_fw_ref, 0, lambda_motion_factor );
?????????????????
????????????????? //--- get prediction direction ----
????????????????? if????? (fw_mcost<=bw_mcost && fw_mcost<=bid_mcost)
????????????????? {
??????????????????? best_pdir = 0;
??????????????????? cost = fw_mcost;
??????????????????? best_bw_ref = -1;
????????????????? }
????????????????? else if (bw_mcost<=fw_mcost && bw_mcost<=bid_mcost)
????????????????? {
??????????????????? best_pdir = 1;
??????????????????? cost = bw_mcost;
??????????????????? best_fw_ref = -1;
????????????????? }
????????????????? else
????????????????? {
??????????????????? best_pdir = 2;
??????????????????? cost = bid_mcost;
??????????????????? best_bw_ref = 0;
????????????????? }
??????????????????? //store backward reference index for every block
????????????????? for (j=0; j<2; j++)
??????????????????? for (i=0; i<2; i++)
??????????????????? {
????????????????????? enc_picture->ref_idx[LIST_0][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_fw_ref;
????????????????????? enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = best_bw_ref;
????????????????????? //enc_picture->ref_pic_id [LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j] = enc_picture->ref_pic_num[LIST_1 + list_offset][enc_picture->ref_idx[LIST_1][img->block_x+(block&1)*2+i][img->block_y+(block&2)+j]];?
??????????????????? }
??????????????? } // if (bframe)
??????????????? else
??????????????? {
????????????????? best_pdir = 0;
????????????????? cost????? = fw_mcost;
??????????????? }
????????????? } // if (mode!=0)
?????????????
????????????? //--- store coding state before coding with current mode ---
????????????? store_coding_state (cs_cm);
?????????????
??? ??? ??? ? //+++計算RDO模式代價rdcost或非RDO模式代價cost
????????????? if (input->rdopt)
????????????? {
??? ??? ??? ???? //+++RDCost_for_8x8blocks是在4種亞宏塊模式中選擇最佳的模式(代價)
??? ??? ??? ??? //+++準確來說RDCost_for_8x8blocks主要是得到編號為block的8x8塊,在mode模式下的代價
??????????????? //--- get and check rate-distortion cost ---
??????????????? rdcost = RDCost_for_8x8blocks (&cnt_nonz, &curr_cbp_blk, lambda_mode,
?????????????????????????????????????????????? block, mode, best_pdir, best_fw_ref, best_bw_ref);
??? ??? ??? ??? ????????????????????????????? //+++block:8x8塊在16x16大小的宏塊中的位置
??? ??? ??? ??? ????????????????????????????? //+++mode:亞宏塊模式
????????????? }
????????????? else
????????????? {
??????????????? cost += (REF_COST (lambda_motion_factor, B8Mode2Value (mode, best_pdir), list_offset + (best_pdir<1?0:1)) - 1);
????????????? }
??? ??? ??? ? //+++根據cost(非RDO模式)或rdcost(RDO模式)選擇最佳模式
????????????? //--- set variables if best mode has changed ---
????????????? if (( input->rdopt && rdcost < min_rdcost) ||
????????????????? (!input->rdopt && cost?? < min_cost8x8? )?? )
????????????? {
??????????????? min_cost8x8????????????????? = cost;//+++非RDO代價
??????????????? min_rdcost?????????????????? = rdcost;//+++RDO代價
??????????????? best8x8mode????????? [block] = mode;//最佳的亞宏塊模式
??????????????? best8x8pdir??? [P8x8][block] = best_pdir;
??????????????? best8x8fwref?? [P8x8][block] = best_fw_ref;
??????????????? best8x8bwref?? [P8x8][block] = best_bw_ref;
???????????????
??????????????? //--- store number of nonzero coefficients ---
??????????????? best_cnt_nonz? = cnt_nonz;
??????????????? //+++存儲cbp、殘差AC系數和重建幀中的預測值
??????????????? if (input->rdopt)
??????????????? {??? ??? ??? ??? ???
????????????????? //--- store block cbp ---
????????????????? cbp_blk8x8??? &= (~(0x33 << (((block>>1)<<3)+((block%2)<<1)))); // delete bits for block
????????????????? cbp_blk8x8??? |= curr_cbp_blk;
?????????????????
????????????????? //--- store coefficients ---
????????????????? for (k=0; k< 4; k++)
??????????????????? for (j=0; j< 2; j++)
????????????????????? for (i=0; i<65; i++)? cofAC8x8[block][k][j][i] = img->cofAC[block][k][j][i]; // 18->65 for ABT
?????????????????????
????????????????????? //--- store reconstruction and prediction ---
????????????????? for (j=j0; j<j0+8; j++)
??????????????????? for (i=i0; i<i0+8; i++)
??????????????????? {
????????????????????? rec_mbY8x8[j][i] = enc_picture->imgY[img->pix_y+j][img->pix_x+i];
????????????????????? mpr8x8??? [j][i] = img->mpr[i][j];
??????????????????? }
??????????????? }
???????????????
??????????????? //--- store coding state ---
??????????????? store_coding_state (cs_b8);
????????????? } // if (rdcost <= min_rdcost)
?????????????
????????????? //--- re-set coding state as it was before coding with current mode was performed ---
????????????? reset_coding_state (cs_cm);
??????????? } // if (valid[mode=b8_mode_table[index]])
??? ??? ? } // for (min_rdcost=1e30, index=(bframe?0:1); index<6; index++)//+++5種8x8模式循環結束
??? ??? ? //+++cost8x8:非RDO模式下的代價,其實cost8x8是一個宏塊中的4個8x8塊的代價和,
??? ??? ? //+++換句話說,其實cost8x8就是一個宏塊(16x16)在亞宏塊模式下的總的代價和.
??? ??? ? //+++這個量主要用來和上面計算的最佳宏塊級模式(非RDO情況下)對應的最小代價min_cost來進行比較,
??? ??? ? //+++看宏塊級模式或亞宏塊級模式哪個更好,從下面的代碼中我們也可以看出來.
????????? cost8x8 += min_cost8x8;
//????????? if (!input->rdopt) cost8x8+= min_cost8x8;
//????????? else cost8x8 += min_rdcost;?????????
?????????
????????? if (!input->rdopt)
????????? {
??????????? mode = best8x8mode[block];
??????????? pdir = best8x8pdir[P8x8][block];
??????????? //+++編碼殘差系數
??????????? curr_cbp_blk? = 0;
??? ??? ??? //+++cnt_nonz表示非零系數的編碼代價;
??????????? best_cnt_nonz = LumaResidualCoding8x8 (&dummy, &curr_cbp_blk, block, pdir,
?????????????????????????????????????????????????? (pdir==0||pdir==2?mode:0),
?????????????????????????????????????????????????? (pdir==1||pdir==2?mode:0),
?????????????????????????????????????????????????? (best8x8fwref[P8x8][block]),
?????????????????????????????????????????????????? (best8x8bwref[P8x8][block]));
??????????? cbp_blk8x8?? &= (~(0x33 << (((block>>1)<<3)+((block%2)<<1)))); // delete bits for block
??????????? cbp_blk8x8?? |= curr_cbp_blk;
???????????
??????????? //--- store coefficients ---
??????????? for (k=0; k< 4; k++)
????????????? for (j=0; j< 2; j++)
??????????????? for (i=0; i<65; i++)? cofAC8x8[block][k][j][i] = img->cofAC[block][k][j][i]; // 18->65 for ABT
???????????????
??????????????? //--- store reconstruction and prediction ---
??????????? for (j=j0; j<j0+8; j++)
????????????? for (i=i0; i<i0+8; i++)
????????????? {
??????????????? rec_mbY8x8[j][i] = enc_picture->imgY[img->pix_y+j][img->pix_x+i];
??????????????? mpr8x8??? [j][i] = img->mpr[i][j];
????????????? }
????????? }
?????????
????????? //----- set cbp and count of nonzero coefficients ---
????????? if (best_cnt_nonz)
????????? {
??????????? cbp8x8??????? |= (1<<block);
??????????? cnt_nonz_8x8? += best_cnt_nonz;
????????? }
?????????
????????? mode=best8x8mode[block];//第2396行會用到mode,best8x8mode[block]應該是第block號8x8塊所選取的最佳亞宏塊級模式
????????? //===== reset intra prediction modes (needed for prediction, must be stored after 8x8 mode dec.) =====
????????? j0 = img->block_y+2*(block/2);
????????? i0 = img->block_x+2*(block%2);
????????? for (j=j0; j<j0+2; j++)
??????????? for (i=i0; i<i0+2; i++)
????????????? ipredmodes[i][j]???????? = DC_PRED;
????????? i0 = 4*block;
????????? for (i=i0; i<i0+4; i++)??? currMB->intra_pred_modes[i]? = DC_PRED;
???????????
????????? if (block<3)
????????? {
??????????? //===== re-set reconstructed block =====
??????????? j0?? = 8*(block/2);
??????????? i0?? = 8*(block%2);
??????????? for (j=j0; j<j0+8; j++)
????????????? for (i=i0; i<i0+8; i++)?
??????????????? enc_picture->imgY[img->pix_y+j][img->pix_x+i] = rec_mbY8x8[j][i];
????????? } // if (block<3)
??????????? //+++這兒與宏塊級類似,要設置MV和參考幀
????????? //===== set motion vectors and reference frames (prediction) =====
????????? SetRefAndMotionVectors (block, mode, best8x8pdir[P8x8][block], best8x8fwref[P8x8][block], best8x8bwref[P8x8][block]);
????????? //===== set the coding state after current block =====
????????? reset_coding_state (cs_b8);
??????? } // for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++)
??????? //+++此刻完成了對一個宏塊(16x16)在亞宏塊模式下的計算,或者說對宏塊中每個8x8塊完成亞宏塊模式的選擇
??? ??? //+++并且在亞宏塊模式下的代價(4個8x8塊代價之和)也計算完畢,在cost8x8中,下面會用到,和宏塊級模式(min_cost)進行比較
??????? //===== store intra prediction modes for 8x8+ macroblock mode =====
??????? for (k=0, j=img->block_y; j<img->block_y+4; j++)
??????? {
????????? for (???? i=img->block_x; i<img->block_x+4; i++, k++)
????????? {
??????????? b8_ipredmode?????? [k] = ipredmodes??? [i][j];
??????????? b8_intra_pred_modes[k] = currMB->intra_pred_modes[k];
????????? }
??????? }
???????
??????? //--- re-set coding state (as it was before 8x8 block coding) ---
??????? reset_coding_state (cs_mb);
??????? for (i=0; i<16; i++)
????????? for(j=0; j<16; j++)
??? ??? ??? ? //++ 原代碼中這里 img->mpr 的下標寫反了
//????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i]-img->mpr[j][i];
??????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i]-img->mpr[i][j];
??? ??? ???
??? ??? ???
??? //+++到這兒應該是一個結點了啊
??? ??? //+++(在非RDO模式下)對一個宏塊(當前宏塊),此時宏塊級(16x16,16x8,8x16)的最小開銷已經計算出來,即min_cost
??? ??? //+++子宏塊級(8x8,8x4,4x8和4x4)的開銷也計算出來(4個8x8塊代價之和),即cost8x8
??? ??? //+++這樣可以比較這兩種方式,選擇開銷更小的那種宏塊分割方式
??? ??? if(cost8x8 < min_cost)//+++// 幀間8x8模式與幀間16x16代價相比
??????? {
?????????? best_mode = P8x8;
?????????? min_cost = cost8x8;
??????? }
??? ??? //+++到這兒我們也可以看到,在非RDO模式下,best_mode保存的是一個宏塊(當前宏塊)幀間預測的最優模式,是(16x16,16x8,8x16和P8x8)之一.
??? ??? //+++(16x16,16x8,8x16)這三種宏塊級的模式是選擇最優模式后再與P8x8模式比較.min_cost現在保存的是一個宏塊(當前宏塊)幀間預測的最小代價
??? ??? //+++從下面幀內預測的代碼我們也可以看到,min_cost作為幀間最小代價是要和幀內兩種模式I4MB和I16MB進行比較的.
????? }
????? else // if (valid[P8x8])
????? {
??? ??? //+++這個地方是不用子宏塊劃分的方法時,將其開銷設為很大
??????? cost8x8 = (1<<20);
????? }
??
????? // Find a motion vector for the Skip mode
????? if((img->type == P_SLICE)||(img->type == SP_SLICE))
??????? FindSkipModeMotionVector ();//+++用于計算MV預測值
??? }
??? else // if (img->type!=I_SLICE)//+++不進行幀間預測
??? {
????? min_cost = (1<<20);
??? }
//+++幀間預測的相關開銷計算完畢
//++++++++++++++++++++++++++++
//===================================
?//+++下面是對幀內預測進行求其開銷
??? if (input->rdopt)
??? {//+++使用RDO準則的情況
????? int mb_available_up;
????? int mb_available_left;
????? int mb_available_up_left;
?????
????? min_rdcost = max_rdcost;
?????
????? // precompute all new chroma intra prediction modes
??? ? //++ 對色度進行幀內預測,并求出最優模式,
??? ? //+++RDO模式下,需要色度預測,保存在currMB->c_ipred_mode中
????? IntraChromaPrediction8x8(&mb_available_up, &mb_available_left, &mb_available_up_left);
??? ? //+++閱讀完IntraChromaPrediction8x8函數的代碼,并且結合下面的代碼,我們可以看到:
??? ? //+++這個函數不做任何運動估計和補償,而僅僅是求出要進行幀內編碼的色度宏塊需要的參考塊
??? ? //+++本來在currMB->c_ipred_mode保存了最佳的模式,但是下面卻被覆蓋掉了
?????
??? ? //++ 分別在四種色度模式下進行 RDO 計算,如果是 inter 模式,因為色度預測模式與 SSD 計算
??? ? //++ 無關,因此只需要計算一次(利用 currMB->c_ipred_mode == DC_PRED_8 條件限制來實現)
????? for (currMB->c_ipred_mode=DC_PRED_8; currMB->c_ipred_mode<=PLANE_8; currMB->c_ipred_mode++)
????? {
???????
??????? // bypass if c_ipred_mode is not allowed
??? ??? ? //+++若當前 c_ipred_mode 模式不被允許,則考慮下一個 c_ipred_mode 模式;
??????? if ((currMB->c_ipred_mode==VERT_PRED_8 && !mb_available_up) ||
????????? (currMB->c_ipred_mode==HOR_PRED_8 && !mb_available_left) ||
????????? (currMB->c_ipred_mode==PLANE_8 && (!mb_available_left || !mb_available_up || !mb_available_up_left)))
????????? continue;
???????
???????
??????? //===== GET BEST MACROBLOCK MODE =====
??????? for (ctr16x16=0, index=0; index<7; index++)
??????? {
??? ??? ??? //+++mb_mode_table[7]? = {0, 1, 2, 3, P8x8, I16MB, I4MB};
????????? mode = mb_mode_table[index];
?????????
????????? //--- for INTER16x16 check all prediction directions ---
????????? if (mode==1 && img->type==B_SLICE)
????????? {
??????????? best8x8pdir[1][0] = best8x8pdir[1][1] = best8x8pdir[1][2] = best8x8pdir[1][3] = ctr16x16;
??????????? if (ctr16x16 < 2) index--;
??????????? ctr16x16++;
????????? }
?????????
????????? img->NoResidueDirect = 0;
?????????
????????? if (valid[mode])
????????? {
??????????? // bypass if c_ipred_mode not used
??? ??? ??? //++ 設置當前宏塊類型以及其中每個8*8塊的分割方式和預測方向,每個4*4塊的參考幀索引
??? ??? ??? //++ 該函數在下面的 RDCost_for_macroblocks 函數內再次調用,進行了重復操作
??????????? SetModesAndRefframeForBlocks (mode);
??????????? if (currMB->c_ipred_mode == DC_PRED_8 ||??? //++ 利用這個條件限制來實現 inter 模式時只計算一次 RDO
????????????? (IS_INTRA(currMB) ))
??????????? {
??? ??? ??? //+++此刻我的理解是:RDCost_for_macroblocks是在模式0-3,P8x8,Intra4x4和Intra16x16之間選擇一個最佳模式
??? ??? ??? //+++這是利用RDO的方法.上面再幀間預測時其實已經將在1-3中選擇出了最佳模式,但那是在非RDO模式下的
??? ??? ??? ??? //+++關于這個地方的RDCost_for_macroblocks我要說明一下:該函數是求出對應mode模式下的RDO代價,然后將這個代價與min_rdcost進行比較
??? ??? ??? ??? //+++如果此時RDO的代價比較小,返回1,執行if,保存相關參數,并且修改min_rdcost,否則返回0,這樣下面的if語句不執行,接著再比較下一個模式.
??? ??? ??? ??? //+++所以我們可以看到(0-3,P8x8,Intra4x4和Intra16x16)這些模式的比較是隨著外面的這個for循環,依次在RDCost_fo...函數中完成的,
????????????? if (RDCost_for_macroblocks (lambda_mode, mode, &min_rdcost))??? //++ 幀內模式時亮度存在重復計算情況:因為色度預測模式與亮度預測模式無關,所以在該色度模
????????????? {??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? //++ 式循環中每次計算得到的 intra16*16 和 intra4*4 宏塊類型的最佳亮度模式都是完全相同的
??????????????? //Rate control
??????????????? if(mode == P8x8)
??????????????? {
????????????????? for (i=0; i<16; i++)
??????????????????? for(j=0; j<16; j++)
????????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - mpr8x8[j][i];
??????????????? }else
??????????????? {
????????????????? for (i=0; i<16; i++)
??????????????????? for(j=0; j<16; j++)
????????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - pred[j][i];
??????????????? }
??????????????? //+++存儲該模式下的一些參數:因為RDCost_for_macroblocks的計算結果是mode模式的預測開銷小于min_rdcost,
??? ??? ??? ??? //+++所以mode模式其實更好,所以現在要保存該模式的一些參數.
??????????????? store_macroblock_parameters (mode);
????????????? }
??????????? }
????????? }
????????? if (valid[0] && bframe && mode == 0 && currMB->cbp && (currMB->cbp&15) != 15) //g050
????????? {
??????????? img->NoResidueDirect = 1;
??????????? if (RDCost_for_macroblocks (lambda_mode, mode, &min_rdcost))
??????????? {
????????????? //Rate control
????????????? for (i=0; i<16; i++)
??????????????? for(j=0; j<16; j++)
????????????????? diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i] - pred[j][i];
??????????????? store_macroblock_parameters (mode);
??????????? }
????????? }
??????? }
????? }
??? }
??? else//+++不使用RDO準則的情況
??? {
??? //+++從下面的代碼可以看到,在不同模式下計算出的cost都要和min_cost(幀間預測代價)進行比較
??? //+++然后決定是否更新min_cost和best_mode,所以我們也可以看到,最終的代價也是保存在min_cost中,
??? //+++best_mode對應保存最佳模式,從而用于最后的熵編碼
???
??? //+++下面對Direct,I4MB和I16MB三種模式進行依次比較,代碼是類似的.
????? if (valid[0] && bframe) // check DIRECT MODE
????? {
??????? cost? = (have_direct?cost_direct:Get_Direct_CostMB (lambda_mode));
??????? cost -= (int)floor(16*lambda_motion+0.4999);
??????? if (cost <= min_cost)
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];
??????????? //+++更新min_cost和best_mode
??????????? min_cost? = cost;
??????????? best_mode = 0;
??????? }
????? }
????? if (valid[I4MB]) // check INTRA4x4
????? {
??? ? //+++從Intra4x4的9中模式中選擇最佳的模式,函數Mode_Dec..中的cost就是當前宏塊的代價
??? ? //+++追蹤各個函數,我們可以看到函數調用順序如下:在非RDO模式下調用
??? ? //+++Mode_Decision_for_Intra4x4Macroblock(得到一個宏塊的代價)
??? ? //+++->Mode_Decision_for_8x8IntraBlocks(得到一個8x8塊代價)
??? ? //+++->Mode_Decision_for_Intra4x4Macroblock(得到一個4x4塊代價),
??? ? //+++其實最后一個函數才是真正的Intra4x4模式選擇的核心,在這個函數中包含9中模式的比較(RDO和非RDO)
??????? currMB->cbp = Mode_Decision_for_Intra4x4Macroblock (lambda_mode, &cost);//++ 計算當前宏塊采用intra4*4編碼時的代價和CBP
??????? if (cost <= min_cost)
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];//++ 保存采用intra4*4編碼時最佳模式的殘差塊
???????????? //+++更新min_cost和best_mode
??????????? min_cost? = cost;
??????????? best_mode = I4MB;
??????? }
????? }
????? if (valid[I16MB]) // check INTRA16x16
????? {
??? ? //+++比較與RDO模式下代碼可以發現,其實在RDO模式下進行Intra16x16預測時,調用的函數Intra16x16_Mode_Decision的代碼
??? ? //+++與這兒類似:也是先intrapred_luma_16x16,再find_sad_16x16,最后dct_luma_16x16
??? ? //+++同時這也說明:intra16*16 在進行4種模式選擇時候,無論是否在RDO情況下,其選擇過程是相同的。
??????? intrapred_luma_16x16 ();??? //++ 分別計算當前宏塊在4種intra16*16幀內預測模式下的預測塊
??? ??? ??????????????????????????? //+++intrapred_luma_16x16執行完后,預測的結果保存在數組img->mprr_2中
??????? cost = find_sad_16x16 (&i16mode);??? //++ 計算intra16*16類型的代價(以SATD作為判斷標準,因為該段代碼是不采用RDO的處理過程)
??? ??? ??????????????????????????????????? //+++此時i16mode保存的是Intra16x16的最佳模式,cost是對應的代價
??? ???
??????? if (cost < min_cost)??? //++ 如果采用intra16*16類型編碼的代價小于采用intra4*4類型編碼的代價,則對當前宏塊采用intra16*16類型編碼
??????? {
????????? //Rate control
????????? for (i=0; i<16; i++)
??????????? for(j=0; j<16; j++)
????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mprr_2[i16mode][j][i];
???????????? //+++更新min_cost和best_mode
??????????? best_mode?? = I16MB;
??? ??? ??? //+++這里說明一下:find_sad_16x16函數中求sad時已經做過DCT變換,但在dct_luma_16x16函數中又要重新做一遍呢?
??? ??? ??? //+++答:前者是對每種預測模式都要做,后者是對最佳模式才做。每種模式做了之后并沒有把結果都保存起來,所以要對最佳模式重新再做一次。
??????????? currMB->cbp = dct_luma_16x16 (i16mode);??? //++ 對當前宏塊采用intra16*16類型進行編碼,并計算CBP
??????? }
????? }
??? }
??? //+++通過比較RDO模式與非RDO模式我們可以發現,
??? //+++在intra4*4與intra16*16之間做選擇時,RDO情況下色度要參與計算,而非RDO情況下色度不參與計算
??? //+++并且我們可以看到在非RDO模式下,具體的幀內預測還是幀間預測的選擇在這兒完成(可以在這兒看到具體的代碼)
??? //+++但是對于RDO模式,具體的幀內還是幀間的選擇卻是在函數RDCost_for_macroblocks中完成的.
//+++幀內預測結束
//===================================
??? if (rerun==0)
??? {
????? intra1 = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? }
? } // for (rerun=0; rerun<runs; rerun++)
? //+++到現在,幀內和幀間模式的選擇終于結束
?
? //+++下面的要進行存儲編碼參數,分RDO和非RDO
? //+++印證了[h264率失真RDO研究]一文中的一句:
? //+++"如果用RDO代價函數,因為計算代價時已經編碼,擇優后僅需對編碼進行存儲;
? //+++如果用非RDO代價函數,則擇優后還要進行編碼過程,編碼后存儲參數."
? //+++從下面的代碼我們也可清楚的看到
? if (input->rdopt)
? {
???
??? if ((cbp!=0 || best_mode==I16MB ))
????? currMB->prev_cbp = 1;
??? else if (cbp==0 && !input->RCEnable)
??? {
????? currMB->delta_qp = 0;
????? currMB->qp = currMB->prev_qp;
????? img->qp = currMB->qp;
????? currMB->prev_cbp = 0;
??? }
//+++存儲編碼參數
??? set_stored_macroblock_parameters ();
//+++??? (1)保存重建圖像
//+++??? rdopt->rec_mbY[j][i] = rec_mbY[j][i];
//+++??? rdopt->rec_mbU[j][i] = rec_mbU[j][i];??
//+++??? rdopt->rec_mbV[j][i] = rec_mbV[j][i];?
//+++??? (2)變換系數和cbp
//+++??? img->cofAC=i4p(cofAC);
//+++??? img->cofDC=i3p(cofDC);
//+++??? currMB->cbp????? = cbp;
//+++??? currMB->cbp_blk = cbp_blk;
//+++??? (3)宏塊模式
//+++??? currMB->mb_type = mode(best_mode);
//+++??? (4)參考幀保存
//+++??? rdopt.c 1511行,對前向參考,后向參考幀分別進行了保存
//+++??? (5)幀內預測模式
//+++??? currMB->c_ipred_mode = best_c_imode;
//+++??? (6)為當前塊保存運動向量
//+++??? SetMotionVectorsMB (currMB, bframe);
//+++??? 從上面其實可以看到"="右邊的量在rdopt.c中都是全局變量,在完成encode_one_macroblock之前,對這些參數進行一下保存.
? }
? else
? {
??? //===== set parameters for chosen mode =====
??? SetModesAndRefframeForBlocks (best_mode);??? //++ 設置當前宏塊的參數,包括:宏塊類型(mb_type)、4個8*8塊的分割模式和預測方向(b8mode,b8pdir)、16個4*4塊的參考幀索引(ref_idx,ref_pic_id)
??? if (best_mode==P8x8)
??? {
????? SetCoeffAndReconstruction8x8 (currMB);
??? }
??? else
??? {
????? if (best_mode!=I4MB)
????? {
??????? for (k=0, j=img->block_y; j<img->block_y+4; j++)
????????? for (???? i=img->block_x; i<img->block_x+4; i++, k++)
????????? {
??????????? ipredmodes??? [i][j] = DC_PRED;
??????????? currMB->intra_pred_modes[k] = DC_PRED;
????????? }
????????? if (best_mode!=I16MB)
????????? {
??????????? LumaResidualCoding ();
??????????? //Rate control
??????????? for (i=0; i<16; i++)
????????????? for(j=0; j<16; j++)
??????????????? diffy[j][i] = imgY_org[img->pix_y+j][img->pix_x+i]-img->mpr[i][j];
????????? }
????? }
??? }
??? //+++
??? // precompute all chroma intra prediction modes
??? IntraChromaPrediction8x8(NULL, NULL, NULL);??? //++ 對色度塊進行處理,包括:分別計算4種色度幀內預測模式下的預測塊、代價(該分支未采用RDO,因此以SATD作為判斷標準)、最佳預測模式
??? img->i16offset = 0;
??? dummy = 0;
??? ChromaResidualCoding (&dummy);
??? if (best_mode==I16MB)
??? {
????? img->i16offset = I16Offset? (currMB->cbp, i16mode);
??? }
??? SetMotionVectorsMB (currMB, bframe);
???
??? //===== check for SKIP mode =====
??? if ((img->type==P_SLICE || img->type==SP_SLICE) && best_mode==1 && currMB->cbp==0 &&
????? enc_picture->ref_idx[LIST_0][img->block_x][img->block_y]==0 &&
????? enc_picture->mv[LIST_0][img->block_x][img->block_y][0]==allmvs[0][0][0][0][0][0] &&
????? enc_picture->mv[LIST_0][img->block_x][img->block_y][1]==allmvs[0][0][0][0][0][1]?????????????? )
??? {
????? currMB->mb_type=currMB->b8mode[0]=currMB->b8mode[1]=currMB->b8mode[2]=currMB->b8mode[3]=0;
??? }
???
??? if(img->MbaffFrameFlag)
????? set_mbaff_parameters();
? }
?
? // Rate control
? if(input->RCEnable)
? {??
??? if(img->type==P_SLICE)
??? {
????? img->MADofMB[img->current_mb_nr] = calc_MAD();
?????
????? if(input->basicunit<img->Frame_Total_Number_MB)
????? {
??????? img->TotalMADBasicUnit +=img->MADofMB[img->current_mb_nr];
???????
??????? /* delta_qp is present only for non-skipped macroblocks*/
??????? if ((cbp!=0 || best_mode==I16MB))
????????? currMB->prev_cbp = 1;
??????? else
??????? {
????????? img->qp -= currMB->delta_qp;
????????? currMB->delta_qp = 0;
????????? currMB->qp = img->qp;
????????? currMB->prev_cbp = 0;
??????? }
??????? /* When MBAFF is used, delta_qp is only present for the first non-skipped macroblock of each
??????? macroblock pair*/
??????? if (input->MbInterlace)
??????? {
????????? if(!currMB->mb_field)
????????? {
??????????? DELTA_QP = currMB->delta_qp;
??????????? QP????? = currMB->qp;
????????? }
????????? else
????????? {
??????????? DELTA_QP2 = currMB->delta_qp;
??????????? QP2????? = currMB->qp;
????????? }
??????? }??????
????? }
??? }
? }
?
?? //+++保存最佳代價在rdopt->min_rdcost中
? if(input->rdopt)
??? rdopt->min_rdcost = min_rdcost;
? else
??? rdopt->min_rdcost = min_cost;
? if(img->MbaffFrameFlag)
? {
??? if (img->current_mb_nr%2) //bottom
??? {
????? if ((currMB->mb_type ? 0:((img->type == B_SLICE) ? !currMB->cbp:1))? // bottom is skip
??????? &&(prevMB->mb_type ? 0:((img->type == B_SLICE) ? !prevMB->cbp:1))) // top is skip
????? {
??????? if (!(field_flag_inference() == curr_mb_field))
??????? {
????????? rdopt->min_rdcost = 1e30;? // don't allow coding of an MB pair as skip if wrong inference
??????? }
????? }
??? }
? }
?
? //+++RestrictRefFrames應該是和容錯有關系的。我的理解是,如果某個區域在后面幀里被intra方式update(從而可以避免錯誤傳播),
? //+++這個區域很可能是出現錯誤的區域,因此,不使用這個區域作參考以避免錯誤傳播。請大家指正
? //===== Decide if this MB will restrict the reference frames =====
? if (input->RestrictRef==1)
? {
??? if (input->rdopt==1)
??? {
????? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (intra ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (intra ? 1 : 0);
??? }
??? else if (input->rdopt==2)
??? {
????? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
????? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0);
??? }
? }
? else if (input->RestrictRef==2)
? {
??? refresh_map[2*img->mb_y? ][2*img->mb_x? ] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y? ][2*img->mb_x+1] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y+1][2*img->mb_x? ] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
??? refresh_map[2*img->mb_y+1][2*img->mb_x+1] = (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0);
? }
?
? if(input->FMEnable)
??? skip_intrabk_SAD(best_mode, listXsize[LIST_0+list_offset]);
}//+++void encode_one_macroblock(),該函數終于完成了