H.264 Quantization


H.264 Quantizer

一般的量化器,可用下面的公式來表示:

$Z=\pm \left \lfloor\frac{ \left | W \right | }{\bigtriangleup }\right \rfloor$

反量化可表示為:

$W' = \bigtriangleup \cdot Z$

量化步長$\bigtriangleup$決定了量化器的編碼壓縮率與圖像精度。如果$\bigtriangleup$比較大,相應的編碼長度較小,圖像細節損失較多;如果$\bigtriangleup$比較小,相應的編碼長度較大,圖像損失細節較少。編碼器需根據實際圖像來改變$\bigtriangleup$值。

 

Quantization Offset

可以看到,這種量化器是求下整,也就是會把區間$[0,\bigtriangleup)$的值量化成0。這種量化器顯然不是最優的,最優的量化器在某區間上的量化值應該為該區間的期望值。為此需要知道殘差變換系數的統計分布,這個分布是經過統計實驗得出來的,其中幀間比幀內分布得更為集中。

為了表明分布集中於區間的期望值,引入了參數——offset(量化偏移量)$f$。相應的量化公式變為:

$Z=\pm \left \lfloor\frac{ \left | W \right | + f }{\bigtriangleup }\right \rfloor$

反量化保持不變:

$W' =\pm (\bigtriangleup \cdot Z)$

H.264參考模型建議:當幀內預測時$f = \bigtriangleup/3$,幀間預測時$f = \bigtriangleup/6$。

 

另外參數$f$可以控制量化死區(量化后為0區域)大小。

當$f$變大時,量化死區減少;當$f$變小時,量化死區增加。死區大小可以直接影響到視頻圖像的主觀質量。變換后,圖像高頻部分的數值比較小,也就是說離0值比較接近。如果死區比較大,0值附近的值會被量化為0,則圖像會損失這些細節。這個特性在電影中特別有用:在電影膠片上會隨機分布着一些斑點,這些斑點是膠片化學物質的結晶體,由於這些斑點與視頻的內容在時間、空間上的不相關性,其值沒法在預測模塊中預測到。因此這些斑點表現為變換后的一些小的高頻系數。為了消除這些斑點,可取較小的$f$值,這樣量化死區就會較大。在字幕區域的細節比較多,可對字幕區域取比較大的$f$值。

從上方的例子可以看出,死區特征的應用是與應用直接相關的,最好能根據不同的應用相應加以調整。

我們注意到通過參數$f$可以控制量化區間的偏移,以及控制死區大小。兩者耦合在一起了。JVT-K026有個直接的解耦方法:加入一個新的參數$\Theta$來控制量化死區的大小,並將量化公式修改為:

$ Z=\pm \left \lfloor\frac{ \left | W \right | + \Theta + f }{\bigtriangleup }\right \rfloor $

$ W' = \pm (\bigtriangleup \cdot Z - \Theta) $

但是這種方法並沒有被標准采用。

 

Quantization Step

H.264標准共設計了52個不同的量化步長$Q_{step}$,如下表所示,其中QP是量化參數,也就是量化步長的序號。QP由小變大,意味着量化步長的增大,也就是由精細變粗糙。

QP

Qstep QP Qstep QP Qstep QP Qstep QP Qstep

0

0.625 12 2.5 24 10 36 40 48 160

1

0.6875 13 2.75 25 11 37 44 49 176

2

0.8125 14 3.25 26 13 38 52 50 208

3

0.875 15 3.5 27 14 39 56 51 224

4

1 16 4 28 16 40 64    

5

1.125 17 4.5 29 18 41 72    

6

1.25 18 5 30 20 42 80    

7

1.375 19 5.5 31 22 43 88    

8

1.625 20 6.5 32 26 44 104    

9

1.75 21 7 33 28 45 112    

10

2 22 8 34 32 46 128    

11

2.25 23 9 35 36 47 144    

 

$Q_{step}$變化有明顯的規律:QP每增加1,量化步長就增加12.25%(即$\sqrt[6]{2}-1$);QP每增加6,量化步長就增加一倍,即$Q_{step}(QP+6) = 2Q_{step}(QP)$。這樣做就可以顯著減少量化表與反量化表的大小,僅用0~5這6個QP的$Q_{step}$,通過右移就可以得到剩下所有的$Q_{step}$,即$Q_{step}(QP) = Q_{step}(QP\%6) \cdot 2^{QP/6}$。

在講述變換的時候說過,變換的$\bigotimes$運算矩陣$E_f$可以合並到量化表中。下面來看一下該運算矩陣

$ E_f[i][j] = \begin{bmatrix} a^2 & \frac{1}{2}ab & a^2 & \frac{1}{2}ab\\ \frac{1}{2}ab & \frac{1}{4}b^2 & \frac{1}{2}ab & \frac{1}{4}b^2\\ a^2 & \frac{1}{2}ab & a^2 & \frac{1}{2}ab\\ \frac{1}{2}ab & \frac{1}{4}b^2 & \frac{1}{2}ab & \frac{1}{4}b^2 \end{bmatrix}$

得到量化矩陣所進行的合並運算如下(歸一化為$2^{15}$)

$\begin{align*}Q(QP,i,j) &= \frac{E_f[i][j]}{Q_{step}(QP)}\times 2^{15+QP/6} \\ &= \frac{E_f[i][j]}{Q_{step}(QP\%6)\times 2^{QP/6}} \times 2^{15+QP/6} \\ &= \frac{E_f[i][j]}{Q_{step}(QP\%6)} \cdot 2^{15}\end{align*}$

上式表明$Q(QP,i,j) = Q(QP\%6,i,j)$

以$Q(0,0,0) $為例,

$\begin{align*}Q(0,0,0) &= \frac{a^2}{Q_{step}(QP)} \times 2^{15} \\ &= \frac{0.25}{0.625}\times 2^{15} \\ &= 13107 \end{align*}$

 

把0~5這6個QP的$Q_{step}$分別與$\bigotimes$運算矩陣$E_f$合並后,可以得到以下6個矩陣,即$Q(QP\%6,i,j)$

$Q(0,i,j) = \begin{bmatrix}13107 & 8066&13107& 8066\\ 8066& 5243& 8066& 5243\\13107& 8066&13107& 8066\\ 8066& 5243& 8066& 5243 \end{bmatrix}$

$Q(1,i,j) =\begin{bmatrix}11916& 7490&11916& 7490\\ 7490& 4660& 7490& 4660\\11916& 7490&11916& 7490\\ 7490& 4660& 7490& 4660\end{bmatrix}$

$Q(2,i,j)= \begin{bmatrix}10082& 6554&10082& 6554\\ 6554& 4194& 6554& 4194\\10082& 6554&10082& 6554\\ 6554& 4194& 6554& 4194\end{bmatrix}$ 

$Q(3,i,j) =\begin{bmatrix} 9362& 5825& 9362& 5825\\ 5825& 3647& 5825& 3647\\ 9362& 5825& 9362& 5825\\ 5825& 3647& 5825& 3647\end{bmatrix} $

$Q(4,i,j) =\begin{bmatrix} 8192& 5243& 8192& 5243\\ 5243& 3355& 5243& 3355\\ 8192& 5243& 8192& 5243\\ 5243& 3355& 5243& 3355\end{bmatrix} $

$Q(5,i,j) =\begin{bmatrix} 7282& 4559& 7282& 4559\\ 4559& 2893& 4559& 2893\\ 7282& 4559& 7282& 4559\\ 4559& 2893& 4559& 2893\end{bmatrix}$

 

在$E_f$矩陣中,可以看到里面有3個數值$a^2, ab, b^2$,合並到量化矩陣后,就有$3 \times 52 = 156$個參數。采用了上面的QP每增加6,量化步長增加一倍的方法后,參數就只有$3 \times 6 = 18$個參數:

$QuantMatrix[6][3] = \begin{bmatrix}13107 & 5243 & 8066 \\11916 & 4660 & 7490 \\10082 & 4194 & 6554 \\9362 & 3647 & 5825 \\8192 & 3355 & 5243 \\7282 & 2893 & 4559\end{bmatrix}$

 

 

采用量化矩陣的方式后,4x4整數DCT變換的量化公式為

 

$\begin{align*}Z_{ij} &= \frac{Y_{ij}\bigotimes E_f[i][j] + f'}{Q_{step}(QP)} \\ &= \frac{Y_{ij}\bigotimes E_f[i][j] + f}{Q_{step}(QP\%6)} \div 2^{QP/6} \\ &= Y_{ij}\bigotimes Q(QP\%6,i,j) \div 2^{15+QP/6}\end{align*}$

 

同樣道理,逆量化矩陣為(歸一化為$2^{10}$):

$\begin{align*}R(QP,i,j) &= E^R_f[i][j] \times Q_{step}(QP) \times 2^{10-QP/6} \\ &= E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{QP/6} \times 2^{10-QP/6} \\ &= E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{10}\end{align*}$

上式表明$R(QP,i,j) = R(QP\%6,i,j)$

逆量化公式為:

$\begin{align*}Y'_{ij} &= Z_{ij}\bigotimes E^R_f[i][j] \times Q_{step} \\&= Z_{ij} \bigotimes R(QP\%6,i,j) \div {2^{10-QP/6}}\end{align*}$

逆量化矩陣為

$dequantMat[6][3]= \begin{bmatrix} 160 & 256 & 208\\ 176 & 288 & 224\\ 208 & 320 & 256\\224 & 368 & 288\\ 256 & 400 & 320\\ 288 & 464 & 368\end{bmatrix}$

 

Nonuniformity Quantization

非一致性量化就是4x4或8x8矩陣上各個位置的量化權重不同,通過這種方法可以在進行量化之前調整量化步長,得到更適合人類視覺系統,更真實的圖像。

加入權重矩陣$W_{ij}$后,量化矩陣與逆量化矩陣分別為:

$Q(QP,i,j) = \frac{1}{W_{ij}}\cdot \frac{E_f[i][j]}{Q_{step}(QP\%6)}\times 2^{15+QP/6}$

$ R(QP,i,j) = W_{ij} \cdot E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{10-QP/6}$

其中$W_{ij}$會被歸一為16,即$2<<4$

 

JM18.6參考代碼如下

量化矩陣:

/*!
 ************************************************************************
 * \brief
 *    For calculating the quantisation values at frame level
 *
 * \par Input:
 *    none
 *
 * \par Output:
 *    none
 ************************************************************************
 */
void CalculateQuant4x4Param(VideoParameters *p_Vid)
{
  QuantParameters *p_Quant  = p_Vid->p_Quant;
  ScaleParameters *p_QScale = p_Vid->p_QScale;

  pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps;
  seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps;

  int i, j, k, temp;
  int k_mod;
  int present[6];
  int no_q_matrix=FALSE;//FALSE means donot use default quant ,use weight qp on config files (quantMat << 4 / weight)

  int max_bitdepth = imax(p_Vid->bitdepth_luma, p_Vid->bitdepth_chroma);
  int max_qp = (3 + 6*(max_bitdepth));


  if(!active_sps->seq_scaling_matrix_present_flag && !active_pps->pic_scaling_matrix_present_flag) //set to no q-matrix
    no_q_matrix=TRUE;
  else
  {
    memset(present, 0, 6 * sizeof(int));

    if(active_sps->seq_scaling_matrix_present_flag)
      for(i=0; i<6; i++)
        present[i] = active_sps->seq_scaling_list_present_flag[i];

    if(active_pps->pic_scaling_matrix_present_flag)
      for(i=0; i<6; i++)
      {
        if((i==0) || (i==3))
          present[i] |= active_pps->pic_scaling_list_present_flag[i];
        else
          present[i] = active_pps->pic_scaling_list_present_flag[i];
      }
  }

  if(no_q_matrix==TRUE)//normal quant
  {
    for(k_mod = 0; k_mod <= max_qp; k_mod++)
    {
      k = k_mod % 6;
      set_default_quant4x4(p_Quant->q_params_4x4[0][0][k_mod],  quant_coef[k], dequant_coef[k]);
      set_default_quant4x4(p_Quant->q_params_4x4[0][1][k_mod],  quant_coef[k], dequant_coef[k]);
      set_default_quant4x4(p_Quant->q_params_4x4[1][0][k_mod],  quant_coef[k], dequant_coef[k]);
      set_default_quant4x4(p_Quant->q_params_4x4[1][1][k_mod],  quant_coef[k], dequant_coef[k]);
      set_default_quant4x4(p_Quant->q_params_4x4[2][0][k_mod],  quant_coef[k], dequant_coef[k]);
      set_default_quant4x4(p_Quant->q_params_4x4[2][1][k_mod],  quant_coef[k], dequant_coef[k]);
    }
  }
  else //weight quant
  {
    for(k_mod = 0; k_mod <= max_qp; k_mod++)
    {
      k = k_mod % 6;
      for(j=0; j<4; j++)
      {
        for(i=0; i<4; i++)
        {
          temp = (j<<2)+i;
          //present means we use the weight quant on the file q_matrix.cfg 
          if((!present[0]) || p_QScale->UseDefaultScalingMatrix4x4Flag[0])
          {
            p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/Quant_intra_default[temp];
            p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*Quant_intra_default[temp];
          }
          else
          {
            p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/p_QScale->ScalingList4x4[0][temp];
            p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[0][temp];
          }

          if(!present[1])
          {
            p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp    = p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp;
            p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp;
          }
          else
          {
            p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[1] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[1][temp]);
            p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[1] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[1][temp]);
          }

          if(!present[2])
          {
            p_Quant->q_params_4x4[2][1][k_mod][j][i].ScaleComp    = p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp;
            p_Quant->q_params_4x4[2][1][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp;
          }
          else
          {
            p_Quant->q_params_4x4[2][1][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[2] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[2][temp]);
            p_Quant->q_params_4x4[2][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[2] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[2][temp]);
          }

          if((!present[3]) || p_QScale->UseDefaultScalingMatrix4x4Flag[3])
          {
            p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp         = (quant_coef[k][j][i]<<4)/Quant_inter_default[temp];
            p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp      = dequant_coef[k][j][i]*Quant_inter_default[temp];
          }
          else
          {
            p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp         = (quant_coef[k][j][i]<<4)/p_QScale->ScalingList4x4[3][temp];
            p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp      = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[3][temp];
          }

          if(!present[4])
          {
            p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp    = p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp;
            p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp;
          }
          else
          {
            p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[4] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[4][temp]);
            p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[4] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[4][temp]);
          }

          if(!present[5])
          {
            p_Quant->q_params_4x4[2][0][k_mod][j][i].ScaleComp    = p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp;
            p_Quant->q_params_4x4[2][0][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp;
          }
          else
          {
            p_Quant->q_params_4x4[2][0][k_mod][j][i].ScaleComp    = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[5] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[5][temp]);
            p_Quant->q_params_4x4[2][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[5] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[5][temp]);
          }
        }
      }
    }
  }
}
View Code

 

量化偏移矩陣

/*!
 ************************************************************************
 * \brief
 *    Init quantization offset parameters
 *
 * \par Input:
 *    none
 *
 * \par Output:
 *    none
 ************************************************************************
 */

void InitOffsetParam (QuantParameters *p_Quant, InputParameters *p_Inp)
{
  int i, k;
  int max_qp_luma = (4 + 6*(p_Inp->output.bit_depth[0]));
  int max_qp_cr   = (4 + 6*(p_Inp->output.bit_depth[1]));

  for (i = 0; i < (p_Inp->AdaptRoundingFixed ? 1 : imax(max_qp_luma, max_qp_cr)); i++)
  {
    if (p_Inp->OffsetMatrixPresentFlag)
    {
      memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(p_Quant->OffsetList4x4input[0][0]), 400 * sizeof(short)); // 25 * 16
      memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(p_Quant->OffsetList8x8input[0][0]), 960 * sizeof(short)); // 15 * 64
    }
    else
    {
      if (p_Inp->OffsetMatrixFlat == 1)
      {
        // 0 (INTRA4X4_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(Offset_intra_flat_intra[0]), 16 * sizeof(short));
        for (k = 1; k < 3; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_flat_chroma[0]),  16 * sizeof(short));
        for (k = 3; k < 9; k++) // 3,4,5,6,7,8 (INTRA4X4_LUMA/CHROMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_flat_inter[0]),  16 * sizeof(short));
        for (k = 9; k < 25; k++) // 9,10,11,12,13,14 (INTER4X4)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_inter_flat[0]),  16 * sizeof(short));
  
        // 0 (INTRA8X8_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(Offset8_intra_flat_intra[0]), 64 * sizeof(short));
        for (k = 1; k < 3; k++)  // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_flat_inter[0]),  64 * sizeof(short));
        for (k = 3; k < 5; k++)  // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_flat[0]),  64 * sizeof(short));
  
        // 5 (INTRA8X8_CHROMAU_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][5][0]),&(Offset8_intra_flat_chroma[0]), 64 * sizeof(short));
        for (k = 6; k < 8; k++)  // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_flat_inter[0]),  64 * sizeof(short));
        for (k = 8; k < 10; k++)  // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_flat[0]),  64 * sizeof(short));

        // 10 (INTRA8X8_CHROMAV_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][10][0]),&(Offset8_intra_flat_chroma[0]), 64 * sizeof(short));
        for (k = 11; k < 13; k++)  // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_flat_inter[0]),  64 * sizeof(short));
        for (k = 13; k < 15; k++)  // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_flat[0]),  64 * sizeof(short));
      }
      else if (p_Inp->OffsetMatrixFlat == 2)
      {
        // 0 (INTRA4X4_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(Offset_intra_default_intra[0]), 16 * sizeof(short));
        for (k = 1; k < 3; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_flat_chroma[0]),  16 * sizeof(short));
        memcpy(&(p_Quant->OffsetList4x4[i][3][0]),&(Offset_intra_default_inter[0]),  16 * sizeof(short));
        for (k = 4; k < 6; k++) // 4,5 (INTRA4X4_CHROMA_INTERP)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_flat_inter[0]),  16 * sizeof(short));
        memcpy(&(p_Quant->OffsetList4x4[i][6][0]),&(Offset_intra_default_inter[0]),  16 * sizeof(short));
        for (k = 7; k < 9; k++) // 7,8 (INTRA4X4_CHROMA_INTERB)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_flat_inter[0]),  16 * sizeof(short));
        for (k = 9; k < 25; k++) // 9,10,11,12,13,14 (INTER4X4)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_inter_default[0]),  16 * sizeof(short));
  
        // 0 (INTRA8X8_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(Offset8_intra_default_intra[0]), 64 * sizeof(short));
        for (k = 1; k < 3; k++)  // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]),  64 * sizeof(short));
        for (k = 3; k < 5; k++)  // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));
  
        // 5 (INTRA8X8_CHROMAU_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][5][0]),&(Offset8_intra_flat_chroma[0]), 64 * sizeof(short));
        for (k = 6; k < 8; k++)  // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_flat_inter[0]),  64 * sizeof(short));
        for (k = 8; k < 10; k++)  // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));

        // 10 (INTRA8X8_CHROMAV_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][10][0]),&(Offset8_intra_flat_chroma[0]), 64 * sizeof(short));
        for (k = 11; k < 13; k++)  // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_flat_inter[0]),  64 * sizeof(short));
        for (k = 13; k < 15; k++)  // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));
      }
      else
      {
        // 0 (INTRA4X4_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(Offset_intra_default_intra[0]), 16 * sizeof(short));
        for (k = 1; k < 3; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_default_chroma[0]),  16 * sizeof(short));
        for (k = 3; k < 9; k++) // 3,4,5,6,7,8 (INTRA4X4_LUMA/CHROMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_default_inter[0]),  16 * sizeof(short));
        for (k = 9; k < 25; k++) // 9,10,11,12,13,14 (INTER4X4)
          memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_inter_default[0]),  16 * sizeof(short));
  
        // 0 (INTRA8X8_LUMA_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(Offset8_intra_default_intra[0]), 64 * sizeof(short));
        for (k = 1; k < 3; k++)  // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]),  64 * sizeof(short));
        for (k = 3; k < 5; k++)  // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));
  
        // 5 (INTRA8X8_CHROMAU_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][5][0]),&(Offset8_intra_default_chroma[0]), 64 * sizeof(short));
        for (k = 6; k < 8; k++)  // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]),  64 * sizeof(short));
        for (k = 8; k < 10; k++)  // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));

        // 10 (INTRA8X8_CHROMAV_INTRA)
        memcpy(&(p_Quant->OffsetList8x8[i][10][0]),&(Offset8_intra_default_chroma[0]), 64 * sizeof(short));
        for (k = 11; k < 13; k++)  // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]),  64 * sizeof(short));
        for (k = 13; k < 15; k++)  // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
          memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]),  64 * sizeof(short));
      }
    }
  }  
}


/*!
 ************************************************************************
 * \brief
 *    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);
    }
  }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM