zoukankan      html  css  js  c++  java
  • Quantization Method

    如上一篇Quantization所说,可以在编码端通过设置offset来调整量化后的值,从而趋向于期望的量化值,而且在逆量化公式可以看出offset值在逆量化的时候是不会用到的。

    目前来说,确定offset的算法有三种:static offset、around offset、trellis offset。

    Static Offset

    H.264参考模型建议:当帧内预测时:$f = frac{1}{3}igtriangleup$;当帧间预测时$f = frac{1}{6}igtriangleup$。这种采用固定的比例作为量化的offset。

    Around Offset

    量化的时候加上Offset,目的是为了通过Offset的调整,使量化能趋向于得到最优结果。那么如何才是最优?当然是对量化后level进行反量化后,得到的数值与量化前的数值保持一致。当然这是不可能的,不过我们可以对第i次的量化结果,反馈到第i+1次量化计算中。通过这种自行反馈的方式,调整量化offset,使其趋向于最优的量化结果。

    Around Offset会采用当前位置的上一次量化结果对这次的量化offset进行调整。

    $ M_{i+1} = M_i + weight imes ((coeff_i – level_i << Qbits_i) >> (Qbits_i + 1))$

    $ f_{i+1} = M_{i+1} << Qbits_{i+1}$

     

    //Q_offsets.c
    //fi+1 = Mi+1 << Qbitsi+1
    static inline void update_q_offset4x4(LevelQuantParams **q_params, short *offsetList, int q_bits)  
    {
      int i, j;
      short *p_list = &offsetList[0];
      for (j = 0; j < 4; j++)
      {
        for (i = 0; i < 4; i++)
        {          
          q_params[j][i].OffsetComp = (int) *p_list++ << q_bits;
        }
      }
    }
    
    
    
    
    /*!
     ************************************************************************
     * rief
     *    Calculation of the quantization offset parameters at the frame level
     *
     * par Input:
     *    none
     *
     * par Output:
     *    none
     ************************************************************************
     */
    void CalculateOffset4x4Param (VideoParameters *p_Vid)
    {
      QuantParameters *p_Quant = p_Vid->p_Quant;
      int k;  
      int qp_per, qp;
      int img_type = ((p_Vid->type == SI_SLICE) ? I_SLICE : (p_Vid->type == SP_SLICE ? P_SLICE : p_Vid->type));
    
      int max_qp_scale = imax(p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_chroma_qp_scale);
      int max_qp = 51 + max_qp_scale;
      InputParameters *p_Inp = p_Vid->p_Inp;
    
      p_Vid->AdaptRndWeight   = p_Inp->AdaptRndWFactor  [p_Vid->nal_reference_idc != 0][img_type];
      p_Vid->AdaptRndCrWeight = p_Inp->AdaptRndCrWFactor[p_Vid->nal_reference_idc != 0][img_type];
    
      if (img_type == I_SLICE )
      {
        for (qp = 0; qp < max_qp + 1; qp++)
        {
          k = p_Quant->qp_per_matrix [qp];
          qp_per = Q_BITS + k - OffsetBits;
          k = p_Inp->AdaptRoundingFixed ? 0 : qp;
    
          // Intra4x4 luma
          update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 0], qp_per);
          // Intra4x4 chroma u
          update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 1], qp_per);
          // Intra4x4 chroma v
          update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 2], qp_per);
        }
      }
      else if (img_type == B_SLICE)
      {
        for (qp = 0; qp < max_qp + 1; qp++)
        {
          k = p_Quant->qp_per_matrix [qp];
          qp_per = Q_BITS + k - OffsetBits;
          k = p_Inp->AdaptRoundingFixed ? 0 : qp;
    
          // Inter4x4 luma
          update_q_offset4x4(p_Quant->q_params_4x4[0][0][qp], p_Quant->OffsetList4x4[k][12], qp_per);
          // Intra4x4 luma
          update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 6], qp_per);
          // Inter4x4 chroma u
          update_q_offset4x4(p_Quant->q_params_4x4[1][0][qp], p_Quant->OffsetList4x4[k][13], qp_per);
          // Intra4x4 chroma u
          update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 7], qp_per);
          // Inter4x4 chroma v
          update_q_offset4x4(p_Quant->q_params_4x4[2][0][qp], p_Quant->OffsetList4x4[k][14], qp_per);      
          // Intra4x4 chroma v
          update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 8], qp_per);
        }
      }
      else
      {
        for (qp = 0; qp < max_qp + 1; qp++)
        {
          k = p_Quant->qp_per_matrix [qp];
          qp_per = Q_BITS + k - OffsetBits;
          k = p_Inp->AdaptRoundingFixed ? 0 : qp;
    
          // Inter4x4 luma
          update_q_offset4x4(p_Quant->q_params_4x4[0][0][qp], p_Quant->OffsetList4x4[k][ 9], qp_per);
          // Intra4x4 luma
          update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 3], qp_per);
          // Inter4x4 chroma u
          update_q_offset4x4(p_Quant->q_params_4x4[1][0][qp], p_Quant->OffsetList4x4[k][10], qp_per);
          // Intra4x4 chroma u
          update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 4], qp_per);
          // Inter4x4 chroma v
          update_q_offset4x4(p_Quant->q_params_4x4[2][0][qp], p_Quant->OffsetList4x4[k][11], qp_per);      
          // Intra4x4 chroma v
          update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 5], qp_per);
        }
      }
    }
    
    
    //Q_around.c
    //Mi+1 = Mi + k
    /*!
    ************************************************************************
    * rief
    *    update rounding offsets based on JVT-N011
    ************************************************************************
    */
    void update_offset_params(Macroblock *currMB, int mode, byte luma_transform_size_8x8_flag)
    {
      VideoParameters *p_Vid = currMB->p_Vid;
      InputParameters *p_Inp = currMB->p_Inp;
      int is_inter = (mode != I4MB)&&(mode != I16MB) && (mode != I8MB);
      int luma_pos = AdaptRndPos[(is_inter<<1) + luma_transform_size_8x8_flag][p_Vid->type];
      int i,j;
      int qp = currMB->qp + p_Vid->bitdepth_luma_qp_scale;
      int cur_qp = p_Inp->AdaptRoundingFixed ? 0 : qp;
      int temp = 0;
      QuantParameters *p_Quant = p_Vid->p_Quant;
      int offsetRange = 1 << (OffsetBits - 1);
      int blk_mask = 0x03 + (luma_transform_size_8x8_flag<<2);
      int blk_shift = 2 + luma_transform_size_8x8_flag;  
      short **offsetList = luma_transform_size_8x8_flag ? p_Quant->OffsetList8x8[cur_qp] : p_Quant->OffsetList4x4[cur_qp];
      short *cur_offset_list = offsetList[luma_pos];
    
      int **fAdjust = luma_transform_size_8x8_flag ? p_Vid->ARCofAdj8x8[0][mode] : p_Vid->ARCofAdj4x4[0][mode];
      
      if (mode == IPCM) return;
    
      if( (p_Vid->active_sps->chroma_format_idc == YUV444) && (p_Inp->separate_colour_plane_flag != 0) )
      {
        if( luma_transform_size_8x8_flag )  // 8x8
          luma_pos += 5 * p_Vid->colour_plane_id;
        else  // 4x4
          luma_pos += p_Vid->colour_plane_id;
        cur_offset_list = offsetList[luma_pos];
      }
     
      for (j=0; j < MB_BLOCK_SIZE; j++)
      {
        int j_pos = ((j & blk_mask)<<blk_shift);
        for (i=0; i < MB_BLOCK_SIZE; i++)
        {
          temp = j_pos + (i & blk_mask);
          cur_offset_list[temp] = (short) iClip3(0, offsetRange, cur_offset_list[temp] + (short) fAdjust[j][i]);
        }
      }
    
      if(p_Vid->P444_joined)
      { 
        int **fAdjustCbCr;
        int uv;
    
        for(uv = 0; uv < 2; uv++)
        {
          luma_pos = AdaptRndPos[(is_inter<<1) + luma_transform_size_8x8_flag][p_Vid->type];
          fAdjustCbCr = luma_transform_size_8x8_flag ? p_Vid->ARCofAdj8x8[uv + 1][mode] : p_Vid->ARCofAdj4x4[uv + 1][mode];
          if(luma_transform_size_8x8_flag )  // 8x8
            luma_pos += 5 * (uv+1);
          else  // 4x4
            luma_pos += (uv+1);
          cur_offset_list = offsetList[luma_pos];
          for (j=0; j < MB_BLOCK_SIZE; j++)
          {
            int j_pos = ((j & blk_mask)<<blk_shift);
            for (i=0; i < MB_BLOCK_SIZE; i++)
            {
              temp = j_pos + (i & blk_mask);
              cur_offset_list[temp] = (short) iClip3(0, offsetRange, cur_offset_list[temp] + (short) fAdjustCbCr[j][i]);
            }
          }
        }
      }
    
      if ((p_Inp->AdaptRndChroma) && (p_Vid->yuv_format == YUV420 || p_Vid->yuv_format == YUV422 ))
      {  
        int u_pos = AdaptRndCrPos[is_inter][p_Vid->type];
        int v_pos = u_pos + 1;
        int k, jpos, uv = 1;
    
        for (k = u_pos; k <= v_pos; k++)
        {
          int **fAdjustChroma = (luma_transform_size_8x8_flag && mode == P8x8 )? p_Vid->ARCofAdj4x4[uv][4] : p_Vid->ARCofAdj4x4[uv][mode];
          uv++;
          cur_offset_list = p_Quant->OffsetList4x4[cur_qp][k];
    
          for (j = 0; j < p_Vid->mb_cr_size_y; j++)
          {
            jpos = ((j & 0x03)<<2);
            for (i = 0; i < p_Vid->mb_cr_size_x; i++)
            {
              temp = jpos + (i & 0x03);
              cur_offset_list[temp] = (short) iClip3(0, offsetRange, cur_offset_list[temp] + (short) fAdjustChroma[j][i]);
            }
          }
        }
      }
    }
    
    
    //Quant4x4_around.c
    //k = weight * ((coeff - level<<Qbits) >> Qbits+1)
    
    
    /*!
     ************************************************************************
     * rief 
     *   Quantization process for All coefficients for a 4x4 block
     *
     ************************************************************************
     */
    int quant_4x4_around(Macroblock *currMB, int **tblock, struct quant_methods *q_method)
    {
      VideoParameters *p_Vid = currMB->p_Vid;
      QuantParameters *p_Quant = p_Vid->p_Quant;
      Slice *currSlice = currMB->p_Slice;
      Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC);
    
      int AdaptRndWeight = p_Vid->AdaptRndWeight;
    
      int   block_x = q_method->block_x;
      int  qp = q_method->qp;
      int*  ACL = &q_method->ACLevel[0];
      int*  ACR = &q_method->ACRun[0];  
      LevelQuantParams **q_params_4x4 = q_method->q_params;
      const byte (*pos_scan)[2] = q_method->pos_scan;
      const byte *c_cost = q_method->c_cost;
      int *coeff_cost = q_method->coeff_cost;
    
      
      LevelQuantParams *q_params = NULL;
      int **fadjust4x4 = q_method->fadjust;
    
      int i,j, coeff_ctr;
    
      int *m7;
      int scaled_coeff;
    
      int   level, run = 0;
      int   nonzero = FALSE;
      int   qp_per = p_Quant->qp_per_matrix[qp];
      int   q_bits = Q_BITS + qp_per;
      const byte *p_scan = &pos_scan[0][0];
    
      int*  padjust4x4;
    
      // Quantization
      for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr)
      {
        i = *p_scan++;  // horizontal position
        j = *p_scan++;  // vertical position
    
        padjust4x4 = &fadjust4x4[j][block_x + i];
        m7 = &tblock[j][block_x + i];
    
        if (*m7 != 0)
        {
          q_params = &q_params_4x4[j][i];
          scaled_coeff = iabs (*m7) * q_params->ScaleComp;
          level = (scaled_coeff + q_params->OffsetComp) >> q_bits;
    
          if (level != 0)
          {
            if (is_cavlc)
              level = imin(level, CAVLC_LEVEL_LIMIT);
    
            *padjust4x4 = rshift_rnd_sf((AdaptRndWeight * (scaled_coeff - (level << q_bits))), q_bits + 1);
    
            *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run];
    
            level   = isignab(level, *m7);
            *m7     = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4);
            // inverse scale can be alternative performed as follows to ensure 16bit
            // arithmetic is satisfied.
            // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4);
            *ACL++  = level;
            *ACR++  = run; 
            // reset zero level counter
            run     = 0;
            nonzero = TRUE;        
          }
          else
          {
            *padjust4x4 = 0;
            *m7 = 0;
            ++run;
          } 
        }
        else
        {
          *padjust4x4 = 0;
          ++run;
        } 
      }
    
      *ACL = 0;
    
      return nonzero;
    }
    View Code

    trellis offset

    trellis offset其实用trellis quantization来描述更为准确,因为这种量化方式不会用到offset。Trellis就是采用Rdoq来得到最佳量化值,即取0、level还是level+1会达到最优的量化结果。由于不会用到offset,因此得到的level统一都是取下整,这样的话需要进行Rdo的候选level有三个:0、level、level+1。三个候选值还是稍微多了,可以采用以下方式进行筛选。

    Rdoq当中包含Rdo这三个字母,这意味它依赖编码后的码流长度以及残差来选择最优结果,不过由于Rdoq处于编码途中,因此无法得到确切的编码后码流长度以及残差,因此只能通过预测值来,即上述候选值来进行计算。计算码流长度涉及到熵编码,而熵编码是以8x8或4x4为单位进行的,但是由于当前像素进行预测时,其后面的像素还没有进行预测,所以进行Rdoq时,当前像素之前的像素点采用的是预测后的level,而当前像素点之后的像素点采用level[num-1]的像素点。

    Rdoq实际上就是对于当前像素点所在的block进行Rdo:在该block上,当前像素采用的是0、level还是level+1才能得到最优的结果。

    /*!
     ************************************************************************
     * rief
     *    Quantization process for All coefficients for a 4x4 block
     *
     ************************************************************************
     */
    int quant_4x4_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method)
    {
      int   block_x = q_method->block_x;
    
      int*  ACL = &q_method->ACLevel[0];
      int*  ACR = &q_method->ACRun[0];  
      Slice *currSlice = currMB->p_Slice;
      QuantParameters *p_Quant = currMB->p_Vid->p_Quant;
      int  qp = q_method->qp;
      LevelQuantParams **q_params_4x4 = q_method->q_params;
      const byte (*pos_scan)[2] = q_method->pos_scan;
      const byte *c_cost = q_method->c_cost;
      int *coeff_cost = q_method->coeff_cost;
    
      Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC);
    
      int i,j, coeff_ctr;
    
      int *m7;
    
      int   level, run = 0;
      int   nonzero = FALSE;
      int   qp_per = p_Quant->qp_per_matrix[qp];
      const byte *p_scan = &pos_scan[0][0];
    
      int levelTrellis[16];
      
     /*    rdoq_4x4
      *    To decide witch level to use
      *    0:0       1:level       2:level+1 (lowerint == 0)
      */
      currSlice->rdoq_4x4(currMB, tblock, q_method, levelTrellis);
    
      // Quantization
      for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr)
      {
        i = *p_scan++;  // horizontal position
        j = *p_scan++;  // vertical position
    
        m7 = &tblock[j][block_x + i];
    
        if (*m7 != 0)
        {    
          /*
          scaled_coeff = iabs (*m7) * q_params_4x4[j][i].ScaleComp;
          level = (scaled_coeff + q_params_4x4[j][i].OffsetComp) >> q_bits;
          */
          level = levelTrellis[coeff_ctr];
    
          if (level != 0)
          {
            if (is_cavlc)
              level = imin(level, CAVLC_LEVEL_LIMIT);
    
            *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run];
    
            level   = isignab(level, *m7);
            *m7     = rshift_rnd_sf(((level * q_params_4x4[j][i].InvScaleComp) << qp_per), 4);
            *ACL++  = level;
            *ACR++  = run; 
            // reset zero level counter
            run     = 0;
            nonzero = TRUE;        
          }
          else
          {
            *m7 = 0;
            ++run;
          } 
        }
        else
        {
          ++run;
        } 
      }
    
      *ACL = 0;
    
      return nonzero;
    }
    
    
    /*!
    ************************************************************************
    * rief
    *    Rate distortion optimized Quantization process for 
    *    all coefficients in a 4x4 block (CAVLC)
    *
    ************************************************************************
    */
    void rdoq_4x4_CAVLC(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[])
    {
      VideoParameters *p_Vid = currMB->p_Vid;
      int   block_x = q_method->block_x;
      int   block_y = q_method->block_y;
      LevelQuantParams **q_params_4x4 = q_method->q_params;
      const byte (*pos_scan)[2] = q_method->pos_scan;
      const byte *p_scan = &pos_scan[0][0];
      int  qp = q_method->qp;
      QuantParameters *p_Quant = currMB->p_Vid->p_Quant;
      int   qp_per = p_Quant->qp_per_matrix[qp];
      int   qp_rem = p_Quant->qp_rem_matrix[qp];
    
      levelDataStruct levelData[16];  
      double  lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; 
    
      int type = LUMA_4x4;
      int   pos_x   = block_x >> BLOCK_SHIFT;
      int   pos_y   = block_y >> BLOCK_SHIFT;
      int   b8      = 2*(pos_y >> 1) + (pos_x >> 1);
      int   b4      = 2*(pos_y & 0x01) + (pos_x & 0x01);
    
      init_trellis_data_4x4_CAVLC(currMB, tblock, block_x, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0], type);
      est_RunLevel_CAVLC(currMB, levelData, levelTrellis, LUMA, b8, b4, 16, lambda_md);
    }
    
    
    
    /*!
    ****************************************************************************
    * rief
    *    Initialize levelData 
    ****************************************************************************
    */
    void init_trellis_data_4x4_CAVLC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, LevelQuantParams **q_params,
                                     const byte *p_scan, levelDataStruct *dataLevel, int type)
    {
      Slice *currSlice = currMB->p_Slice;
      int i, j, coeff_ctr; 
      int *m7;
      int end_coeff_ctr = ( ( type == LUMA_4x4 ) ? 16 : 15 );
      int q_bits = Q_BITS + qp_per; 
      int q_offset = ( 1 << (q_bits - 1) );
      int scaled_coeff, level, lowerInt, k;
      double err, estErr;
    
    
      for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++)
      {
        i = *p_scan++;  // horizontal position
        j = *p_scan++;  // vertical position
    
        m7 = &tblock[j][block_x + i];
    
        if (*m7 == 0)
        {
          dataLevel->levelDouble = 0;
          dataLevel->level[0] = 0;
          dataLevel->noLevels = 1;
          err = 0.0;
          dataLevel->errLevel[0] = 0.0;
          dataLevel->pre_level = 0;
          dataLevel->sign = 0;
        }
        else
        {
          estErr = ((double) estErr4x4[qp_rem][j][i]) / currSlice->norm_factor_4x4;
    
          scaled_coeff = iabs(*m7) * q_params[j][i].ScaleComp;
          dataLevel->levelDouble = scaled_coeff;
          level = (scaled_coeff >> q_bits);
    
          lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0;
          
          dataLevel->level[0] = 0;
          if (level == 0 && lowerInt == 1)
          {
            dataLevel->noLevels = 1;
          }
          else if (level == 0 && lowerInt == 0)
          {
            dataLevel->level[1] = 1;
            dataLevel->noLevels = 2;
          }
          else if (level > 0 && lowerInt == 1)
          {
            dataLevel->level[1] = level;
            dataLevel->noLevels = 2;
          }
          else
          {
            dataLevel->level[1] = level;
            dataLevel->level[2] = level + 1;
            dataLevel->noLevels = 3;
          }
    
          for (k = 0; k < dataLevel->noLevels; k++)
          {
            err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff;
            dataLevel->errLevel[k] = (err * err * estErr); 
          }
    
          if(dataLevel->noLevels == 1)
            dataLevel->pre_level = 0;
          else
            dataLevel->pre_level = (iabs (*m7) * q_params[j][i].ScaleComp + q_params[j][i].OffsetComp) >> q_bits;
          dataLevel->sign = isign(*m7);
        }
        dataLevel++;
      }
    }
    
    
    
    
    /*!
    ****************************************************************************
    * rief
    *    estimate run and level for CAVLC 
    ****************************************************************************
    */
    void est_RunLevel_CAVLC(Macroblock *currMB, levelDataStruct *levelData, int *levelTrellis, int block_type, 
                            int b8, int b4, int coeff_num, double lambda)
    {
      int k, lastnonzero = -1, coeff_ctr;
      int level_to_enc[16] = {0}, sign_to_enc[16] = {0};
      int cstat, bestcstat = 0; 
      int nz_coeff=0;
      double lagr, lagrAcc = 0, minlagr = 0;
      VideoParameters *p_Vid = currMB->p_Vid;
    
      int subblock_x = ((b8 & 0x1) == 0) ? (((b4 & 0x1) == 0) ? 0 : 1) : (((b4 & 0x1) == 0) ? 2 : 3); 
      // horiz. position for coeff_count context  
      int subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) :((b4 < 2) ? 2 : 3); 
      // vert.  position for coeff_count context      
      int nnz; 
      levelDataStruct *dataLevel = &levelData[0];
    
      if (block_type != CHROMA_AC)
        nnz = predict_nnz(currMB, LUMA, subblock_x, subblock_y); 
      else
        nnz = predict_nnz_chroma(currMB, currMB->subblock_x >> 2, (currMB->subblock_y >> 2) + 4);
    
      for (coeff_ctr=0;coeff_ctr < coeff_num;coeff_ctr++)
      { 
        levelTrellis[coeff_ctr] = 0;
    
        for(k=0; k < dataLevel->noLevels; k++)
        {
          dataLevel->errLevel[k] /= 32768;
        }
    
        lagrAcc += dataLevel->errLevel[imax(0, dataLevel->noLevels - 1)];
    
        level_to_enc[coeff_ctr] = dataLevel->pre_level;
        sign_to_enc[coeff_ctr]  = dataLevel->sign;
    
        if(dataLevel->noLevels > 1)
        {
          dataLevel->coeff_ctr = coeff_ctr;
          lastnonzero = coeff_ctr;
        }
        else
          dataLevel->coeff_ctr = -1;
        dataLevel++;
      }
    
      if(lastnonzero != -1)
      {
        //sort the coefficients based on their absolute value
        qsort(levelData, lastnonzero + 1, sizeof(levelDataStruct), cmp);
        dataLevel = &levelData[lastnonzero];
    
        for(coeff_ctr = lastnonzero; coeff_ctr >= 0; coeff_ctr--) // go over all coeff
        {
          if(dataLevel->noLevels == 1)
          {
            dataLevel--;
            continue;
          }
    
          lagrAcc -= dataLevel->errLevel[dataLevel->noLevels-1];
          for(cstat=0; cstat<dataLevel->noLevels; cstat++) // go over all states of cur coeff k
          {
            level_to_enc[dataLevel->coeff_ctr] = dataLevel->level[cstat];
            lagr = lagrAcc + dataLevel->errLevel[cstat];
            lagr += lambda * est_CAVLC_bits( p_Vid, level_to_enc, sign_to_enc, nnz, block_type);
            if(cstat==0 || lagr<minlagr)
            {
              minlagr = lagr;
              bestcstat = cstat;
            }
          }
    
          lagrAcc += dataLevel->errLevel[bestcstat];
          level_to_enc[dataLevel->coeff_ctr] = dataLevel->level[bestcstat];
          dataLevel--;
        }
    
        for(coeff_ctr = 0; coeff_ctr <= lastnonzero; coeff_ctr++)
        {
          levelTrellis[coeff_ctr] = level_to_enc[coeff_ctr];
          if (level_to_enc[coeff_ctr] != 0)
            nz_coeff++;
        }
      }
    
      p_Vid->nz_coeff [p_Vid->current_mb_nr ][subblock_x][subblock_y] = nz_coeff;
    }
    
    
    /*!
    ************************************************************************
    * rief
    *    estimate CAVLC bits
    ************************************************************************
    */
    int est_CAVLC_bits (VideoParameters *p_Vid, int level_to_enc[16], int sign_to_enc[16], int nnz, int block_type)
    {
      int           no_bits    = 0;
      SyntaxElement se;
    
      int coeff_ctr, scan_pos = 0;
      int k, level = 1, run = -1, vlcnum;
      int numcoeff = 0, lastcoeff = 0, numtrailingones = 0; 
      int numones = 0, totzeros = 0, zerosleft, numcoef;
      int numcoeff_vlc;
      int level_two_or_higher;
      int max_coeff_num = 0, cdc = (block_type == CHROMA_DC ? 1 : 0);
      int yuv = p_Vid->yuv_format - 1;
      static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768};  // maximum vlc = 6
    
      int  pLevel[16] = {0};
      int  pRun[16] = {0};
    
      static const int Token_lentab[3][4][17] = 
      {
        {
          { 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},
          { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},
          { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},
          { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}
        },
        {                                                  
          { 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14},
          { 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14},
          { 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14},
          { 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14}
        },
        {                                                  
          { 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10},
          { 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10},
          { 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10},
          { 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10}
        }
      };
    
      static const int Totalzeros_lentab[TOTRUN_NUM][16] = 
      {
        { 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},  
        { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},  
        { 4,3,3,3,4,4,3,3,4,5,5,6,5,6},  
        { 5,3,4,4,3,3,3,4,3,4,5,5,5},  
        { 4,4,4,3,3,3,3,3,4,5,4,5},  
        { 6,5,3,3,3,3,3,3,4,3,6},  
        { 6,5,3,3,3,2,3,4,3,6},  
        { 6,4,5,3,2,2,3,3,6},  
        { 6,6,4,2,2,3,2,5},  
        { 5,5,3,2,2,2,4},  
        { 4,4,3,3,1,3},  
        { 4,4,2,1,3},  
        { 3,3,1,2},  
        { 2,2,1},  
        { 1,1},  
      };
      static const int Run_lentab[TOTRUN_NUM][16] = 
      {
        {1,1},
        {1,2,2},
        {2,2,2,2},
        {2,2,2,3,3},
        {2,2,3,3,3,3},
        {2,3,3,3,3,3,3},
        {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11},
      };
      static const int Token_lentab_cdc[3][4][17] =
      {
        //YUV420
       {{ 2, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 1, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 0, 3, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
        //YUV422
       {{ 1, 7, 7, 9, 9,10,11,12,13, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 2, 7, 7, 9,10,11,12,12, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 0, 3, 7, 7, 9,10,11,12, 0, 0, 0, 0, 0, 0, 0, 0},
        { 0, 0, 0, 5, 6, 7, 7,10,11, 0, 0, 0, 0, 0, 0, 0, 0}},
        //YUV444
       {{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},
        { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},
        { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},
        { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}}
      };
      static const int Totalzeros_lentab_cdc[3][TOTRUN_NUM][16] =
      {
        //YUV420
       {{ 1,2,3,3},
        { 1,2,2},
        { 1,1}},
        //YUV422
       {{ 1,3,3,4,4,4,5,5},
        { 3,2,3,3,3,3,3},
        { 3,3,2,2,3,3},
        { 3,2,2,2,3},
        { 2,2,2,2},
        { 2,2,1},
        { 1,1}},
        //YUV444
       {{ 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},
        { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},
        { 4,3,3,3,4,4,3,3,4,5,5,6,5,6},
        { 5,3,4,4,3,3,3,4,3,4,5,5,5},
        { 4,4,4,3,3,3,3,3,4,5,4,5},
        { 6,5,3,3,3,3,3,3,4,3,6},
        { 6,5,3,3,3,2,3,4,3,6},
        { 6,4,5,3,2,2,3,3,6},
        { 6,6,4,2,2,3,2,5},
        { 5,5,3,2,2,2,4},
        { 4,4,3,3,1,3},
        { 4,4,2,1,3},
        { 3,3,1,2},
        { 2,2,1},
        { 1,1}}
      };
    
      max_coeff_num = ( (block_type == CHROMA_DC) ? p_Vid->num_cdc_coeff : 
      ( (block_type == LUMA_INTRA16x16AC || block_type == CB_INTRA16x16AC || block_type == CR_INTRA16x16AC || block_type == CHROMA_AC) ? 15 : 16) );
    
      //convert zigzag scan to (run, level) pairs
      for (coeff_ctr = 0; coeff_ctr < max_coeff_num; coeff_ctr++)
      {
        run++;
        level = level_to_enc[coeff_ctr];
        if (level != 0)
        {
          pLevel[scan_pos] = isignab(level, sign_to_enc[coeff_ctr]);
          pRun  [scan_pos] = run;
          ++scan_pos;
          run = -1;                     // reset zero level counter
        }
      }
    
      level = 1;
      for(k = 0; (k < max_coeff_num) && level != 0; k++)    
      {
        level = pLevel[k]; // level
        run   = pRun[k];   // run
    
        if (level)
        {
          totzeros += run; // lets add run always (even if zero) to avoid conditional
          if (iabs(level) == 1)
          {
            numones ++;
            numtrailingones ++;
            numtrailingones = imin(numtrailingones, 3); // clip to 3
          }
          else
          {
            numtrailingones = 0;
          }
          numcoeff ++;
          lastcoeff = k;
        }
      }
    
      if (!cdc)
      {
        numcoeff_vlc = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3));
      }
      else
      {
        // chroma DC (has its own VLC)
        // numcoeff_vlc not relevant
        numcoeff_vlc = 0;
      }
    
      se.value1 = numcoeff;
      se.value2 = numtrailingones;
      se.len    = numcoeff_vlc; /* use len to pass vlcnum */
    
      if (!cdc)
      {
        if (se.len == 3)
          no_bits += 6;  // 4 + 2 bit FLC
        else
          no_bits += Token_lentab[se.len][se.value2][se.value1];
      }
      else
        no_bits += Token_lentab_cdc[yuv][se.value2][se.value1];  
    
      if (!numcoeff)
        return no_bits;
      else
      {
        if (numtrailingones)
          no_bits += numtrailingones;
    
        // encode levels
        level_two_or_higher = (numcoeff > 3 && numtrailingones == 3) ? 0 : 1;
    
        vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0;
    
        for (k = lastcoeff - numtrailingones; k >= 0; k--)
        {
          level = pLevel[k]; // level
    
          se.value1 = level;
    
          if (level_two_or_higher)
          {
            level_two_or_higher = 0;
            if (se.value1 > 0)
              se.value1 --;
            else
              se.value1 ++;
          }
    
          //    encode level
          if (vlcnum == 0)
            estSyntaxElement_Level_VLC1(&se);
          else
            estSyntaxElement_Level_VLCN(&se, vlcnum);
    
          // update VLC table
          if (iabs(level) > incVlc[vlcnum])
            vlcnum++;
    
          if ((k == lastcoeff - numtrailingones) && iabs(level) > 3)
            vlcnum = 2;
    
          no_bits  += se.len;
        }
    
        // encode total zeroes
        if (numcoeff < max_coeff_num)
        {
          se.value1 = totzeros;
    
          vlcnum = numcoeff-1;
    
          se.len = vlcnum;
    
          if (!cdc)
            no_bits += Totalzeros_lentab[se.len][se.value1];
          else
            no_bits += Totalzeros_lentab_cdc[yuv][se.len][se.value1];
        }
    
        // encode run before each coefficient
        zerosleft = totzeros;
        numcoef = numcoeff;
        for (k = lastcoeff; k >= 0; k--)
        {
          run = pRun[k]; // run
    
          se.value1 = run;
    
          // for last coeff, run is remaining totzeros
          // when zerosleft is zero, remaining coeffs have 0 run
          if ((!zerosleft) || (numcoeff <= 1 ))
            break;
    
          if (numcoef > 1 && zerosleft) 
          {
            vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1);
            se.len = vlcnum;
            no_bits += Run_lentab[se.len][se.value1];
            zerosleft -= run;
            numcoef --;
          }
        }
      }
    
      return no_bits;
    }
    View Code
  • 相关阅读:
    PTA A1005&A1006
    PTA A1003&A1004
    PTA A1001&A1002
    MOOC web前端开发笔记(二)
    MOOC web前端开发笔记(一)
    MOOC C++笔记(三):类和对象提高
    MOOC C++笔记(二):类和对象基础
    MOOC C++笔记(一):从C到C++
    linux command tee
    modbus数据格式(一)
  • 原文地址:https://www.cnblogs.com/TaigaCon/p/4395272.html
Copyright © 2011-2022 走看看