void encode_one_macroblock ()
{
static const int b8_mode_table[6] = {0, 4, 5, 6, 7}; // DO NOT CHANGE ORDER !!! B8x8模式
static const int mb_mode_table[7] = {0, 1, 2, 3, P8x8, I16MB, I4MB};
。。。
--初始化参数
int **ipredmodes = img->ipredmode;
int best_bw_ref = -1;
int ******allmvs = img->all_mv;
。。。
--初始化参考帧偏移量
if (curr_mb_field)
{
if(img->current_mb_nr%2)//current_mb_nr当前宏块索引号
list_offset = 4; // bottom field mb
else
list_offset = 2; // top field mb
}
else
{
list_offset = 0; // no mb aff or frame mb
}
--随即强制转变为帧内模式
intra |= RandomIntra (img->current_mb_nr);
--模式可用性分析
//===== SET VALID MODES =====
valid[I4MB] = 1;
。。。
if (!img->MbaffFrameFlag)//在非宏块级帧场自适应且是场模式下 进行色度矢量校正
{
。。。
。。。
}
else
{
。。。
}
--设置RDO与非RDO下的lambda系数
//===== SET LAGRANGE PARAMETERS =====
if (input->rdopt)//在率失真模式下
{
。。。
}
else
{
。。。
}
--设置帧内默认模式
// reset chroma intra predictor to default
currMB->c_ipred_mode = DC_PRED_8;//c_ipred_mode 色度帧内预测模式
--帧间预测
if (!intra)//帧间预测模式
{
--B帧的直接模式预测
//===== set direct motion vectors =====
if (bframe)//P帧无direct模式 但有skip模式
{
Get_Direct_Motion_Vectors ()[qj1] ;//不返回direct模式代价
}
--16x16, 16x8, 8x16的帧间预测
//===== MOTION ESTIMATION FOR 16x16, 16x8, 8x16 BLOCKS =====
for (min_cost=1<<20, best_mode=1, mode=1; mode<4; mode++)
{
if (valid[mode])
{
for (cost=0, block=0; block<(mode==1?1:2); block++)//16x8 8x16模式下循环2次
{
PartitionMotionSearch[qj2] (mode, block, lambda_motion);//运动估计 有STAD
for (fw_mcost=max_mcost, ref=0; ref<listXsize[LIST_0+list_offset]; ref++)
{
。。。
mcost += motion_cost[mode][LIST_0][ref][block][qj3] ;
--根据参考代价选出该模式下的最佳参考帧
--记录最佳参考帧及预测代价
--B帧还需记录向后及双向预测的各个参考帧与参考代价
。。。
}
//--- get prediction direction ----
--记录最佳预测方向及其代价,参考帧等信息
if (fw_mcost<=bw_mcost && fw_mcost<=bid_mcost)
{
best_pdir = 0;
best_bw_ref = 0;
cost[qj4] += fw_mcost;
。。。
}
if (mode==1)//16x16
{
。。。
--保存参考信息至重建单元,B帧多做后项参考
enc_picture->ref_idxref_idx[LIST_0][img->block_x+(block&1)*2+i][img- >block_y+(block&2)+j] = -1;
。。。
}
--以8x8块记录各个模式的预测信息 每个分割的8x8相同
//----- set reference frame and direction parameters -----
if (mode==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)
{
。。。
}
。。。
--重载预测信息
//--- set reference frames and motion vectors ---
if (mode>1 && block==0)
SetRefAndMotionVectors (block, mode, best_pdir, best_fw_ref, best_bw_ref);//重载
} // for (block=0; block<(mode==1?1:2); block++) --块循环结束
--比较记录该模式下的各个块
if (cost[qj5] < min_cost)
{
best_mode = mode;
min_cost = cost;
}
} // if (valid[mode])
} // for (mode=1; mode<4; mode++) --16x16帧间模式结束
--8x8帧间模式
if (valid[P8x8])
{
cost8x8 = 0;
。。。
for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++) //遍历16x16MB中每个
{
//--- set coordinates ---
j0 = ((block/2)<<3); j1 = (j0>>2);[qj6]
i0 = ((block%2)<<3); i1 = (i0>>2);
--16x16中的每个8x8块的模式循环
//===== 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]])
{
curr_cbp_blk[qj7] = 0;//初始化当前cbp_blk
if (mode==0)
{
//--- Direct Mode ---
if (!input->rdopt)
{
cost_direct += (cost = Get_Direct_Cost8x8[qj8] ( 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) --非RDO模式下8x8模式单独做
--非direct模式下
else//if(mode!=0)
{
//--- motion estimation for all reference frames ---
PartitionMotionSearch [qj9] (mode, block, lambda_motion);
--选择最佳参考帧
//--- get cost and reference frame for forward prediction ---
。。。
--记录最佳参考帧及预测代价
//--- get prediction direction ----
。。。
与16x16类似
。。。
}// if (mode!=0)
if (input->rdopt)
{
//--- get and check rate-distortion cost ---
rdcost = RDCost_for_8x8blocks [qj10] (&cnt_nonz, &curr_cbp_blk, lambda_mode,
block, mode, best_pdir, best_fw_ref,
best_bw_ref);//计算8x8块的RDcost
}
else
{
cost += (REF_COST (lambda_motion_factor, B8Mode2Value (mode, best_pdir),
list_offset + (best_pdir<1?0:1)) - 1);
}
--根据cost或rdcost记录最佳模式
//--- set variables if best mode has changed ---
if (( input->rdopt && rdcost < min_rdcost) ||
(!input->rdopt && cost < min_cost8x8 ) )
{
min_cost8x8 = cost;
min_rdcost = rdcost;
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;//储存非零系数的数量
if (input->rdopt)
{
。。。
--存储cbp、残差AC系数和重建帧中的预测值
。。。
}
} // if (rdcost <= min_rdcost)
} // if (valid[mode=b8_mode_table[index]])
} // for (min_rdcost=1e30, index=(bframe?0:1); index<5; index++)--5种8x8模式循环结束
cost8x8 += min_cost8x8;//记录4块8x8的代价
if (!input->rdopt)
{
mode = best8x8mode[block];
pdir = best8x8pdir[P8x8][block];
--编码残差系数
curr_cbp_blk = 0;
best_cnt_nonz = LumaResidualCoding8x8 [qj11] (&dummy, &curr_cbp_blk, block, pdir,
(pdir==0||pdir==2?mode:0),
(pdir==1||pdir==2?mode:0),
(best8x8fwref[P8x8][block]),
(best8x8bwref[P8x8][block]));
。。。
--存储AC系数,保存重建帧中的预测值
。。
}
--设置最佳模式的参数
if (best_cnt_nonz)
{
cbp8x8 |= (1<<block);
cnt_nonz_8x8 += best_cnt_nonz;
}
mode=best8x8mode[block];
} // for (cbp8x8=cbp_blk8x8=cnt_nonz_8x8=0, block=0; block<4; block++) --8x8block循环结束
。。。
--
//--- 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++)
diffy[j][i] = imgY_org[img->opix_y+j][img->opix_x+i]-img->mpr[j][i];
if(cost8x8 < min_cost) [qj12] // 帧间8x8模式与帧间16x16代价相比
{
best_mode = P8x8;
min_cost = cost8x8;
}
else // if (valid[P8x8])
{
cost8x8 = (1<<20);//如果该块的8x8模式不被允许则该块代价置最大
}
--寻找Skip模式的MV
// Find a motion vector for the Skip mode
if((img->type == P_SLICE)||(img->type == SP_SLICE))
FindSkipModeMotionVector ();
}if (!intra) --帧间结束
else // if (img->type!=I_SLICE)
{
min_cost = (1<<20);//不为帧间就把帧间的代价设为最大
}
if (input->rdopt)
{
int mb_available_up;
int mb_available_left;
int mb_available_up_left;
min_rdcost = max_rdcost;//max_rdcost=1e30
// p recompute all new chroma intra prediction modes
IntraChromaPrediction8x8(&mb_available_up, &mb_available_left, &mb_available_up_left);
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
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++)
{
mode = mb_mode_table[index];//{0, 1, 2, 3, P8x8, I16MB, I4MB}
//--- 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;//mode==1 做了三次循环
if (ctr16x16 < 2) index--;//???????????????????????
ctr16x16++;
}
img->NoResidueDirect = 0;//是否传残差 0为传残差
该函数只记录预测MV到direct_ref_idx等,代价则在后续代码中计算
此函数包含了每个块分割的SATD(即hadamard变换后再绝对值求和)在RDO模式下需要单独求RDcost
motion_cost在PartitionMotionSearch函数中已经得到
mcost对每个16x16模式下的分割进行累加
此cost已是该模式下16x16宏块的非RDO代价 RDO模式下单独考虑
这个什么用?
初始化cbp_blk说明要做DCT变换,或者在RDO模式下计算RDcost代价
在非RDO下此函数中包含了LumaPrediction8x8()函数来计算direct代价即cost_direct和非direct的RDcost
包含了每个8x8分割的SATD(即hadamard变换后再绝对值求和)
包含direct8x8及帧间8x8的4种模式
在ODP模式下LumaResidualCoding8x8()在RD_cost中调用
对于RDO模式来说由于帧间16x16还未算rdcost所以放在后面做