舒达床垫有哪些系列:[转]H.264中宏块编码函数encode_one_macroblock()分析_hain...

来源:百度文库 编辑:中财网 时间:2024/05/12 15:53:46
[转]H.264中宏块编码函数encode_one_macroblock()分析2009-12-19 21:07

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

           {

               。。。

              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所以放在后面做