舒达床垫有哪些系列:[转]H.264中宏块编码函数encode_one_macroblock()分析_hain...
来源:百度文库 编辑:中财网 时间:2024/05/12 15:53:46
void encode_on
{
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 { 。。。 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< 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所以放在后面做