【HEVC学习与研究】44、HEVC量化系数的解析——反量化过程

【同其他模块一样,HEVC标准文档中只实现了反量化过程,量化过程交由编码器实现。这样可使得编码器采用如自适应量化AQ、率失真优化量化RDOQ等更优的量化方法。这里首先简要记录标准文档的实现,然后再在参考代码中寻找对应的实现。具体可参见标准文档8.6.3】

1、输入与输出数据

反量化过程的输入数据主要有:
①(xTbY,yTbY):当前亮度TB的左上顶点相对于整帧左上顶点的相对位置坐标;
②nTbS:以边长表示当前TB的大小;
③cIdx:表示当前TB所属的颜色分量;
④qP:表示所选量化参数。
该过程的输出数据主要有:
反量化之后的变换系数矩阵d[x][y],大小为(nTbS)×(nTbS)。


2、数据推导过程

(1)变量bdShift

如果cIdx ==0 (为亮度分量),则bdShift = BitDepthY + log2(nTbS) - 5;

如果cIdx !=0 (为色度分量),则bdShift = BitDepthC + log2(nTbS) - 5;

(2)量化系数level列表levelScale

该列表指定为levelScale[i] = {40, 45, 51, 57, 64, 72}, i∈[0,5]。

(3)量化矩阵m[x][y]

①如果标志位scaling_list_enabled_flag为0,则m[x][y]=16;

②若scaling_list_enabled_flag为1,则m[x][y]=ScalingFactor[sizeId][matrixId][x][y];其中,sizeId表示TB大小的索引值,对于4×4、8×8、16×16、32×32分别为0、1、2、3;matrixId表示矩阵的索引,依据是sizeId、CuPredMode和cIdx(也就是块尺寸、预测模式和颜色分量)。

(4)量化系数d[x][y]

d[x][y] = Clip3( −32768, 32767, ( ( TransCoeffLevel[ xTbY ][ yTbY ][ cIdx ][ x ][ y ] * m[ x ][ y ] * levelScale[ qP%6 ] << (qP / 6 ) ) + ( 1 << ( bdShift − 1 ) ) ) >> bdShift )。
即变换系数由量化后的变换系数与变换矩阵、量化系数列表、qp和偏移值等数据计算得到,并且取值范围限制于[-32768,32767]之间。

实现方法:

Void TComTrQuant::xDeQuant(Int bitDepth, const TCoeff* pSrc, Int* pDes, Int iWidth, Int iHeight, Int scalingListType )
{  
  const TCoeff* piQCoef   = pSrc;
  Int*   piCoef    = pDes;
  
  if ( iWidth > (Int)m_uiMaxTrSize )
  {
    iWidth  = m_uiMaxTrSize;
    iHeight = m_uiMaxTrSize;
  }
  
  Int iShift,iAdd,iCoeffQ;
  UInt uiLog2TrSize = g_aucConvertToBit[ iWidth ] + 2;

  Int iTransformShift = MAX_TR_DYNAMIC_RANGE - bitDepth - uiLog2TrSize;

  iShift = QUANT_IQUANT_SHIFT - QUANT_SHIFT - iTransformShift;
  /*
  因此iShift的实际取值为
  iShift = bitDepth + uiLog2TrSize + (QUANT_IQUANT_SHIFT(20) - QUANT_SHIFT(14) -MAX_TR_DYNAMIC_RANGE(15))
		 = bitDepth + uiLog2TrSize - 9
		 = bdShift - 4;
  */

  TCoeff clipQCoef;

  if(getUseScalingList())//默认为false
  {
    //......    
  }
  else
  {
    iAdd = 1 << (iShift-1);
    Int scale = g_invQuantScales/*levelScale[]数组*/[m_cQP.m_iRem/*qp%6*/] << m_cQP.m_iPer/*qp/6*/;

    for( Int n = 0; n < iWidth*iHeight; n++ )
    {
      clipQCoef = Clip3( -32768, 32767, piQCoef[n] );
      iCoeffQ = ( clipQCoef * scale + iAdd ) >> iShift;
	  /*
	  实际取值iCoeffQ = ( clipQCoef * scale + 1 << (iShift-1) ) >> iShift;
					 = ( clipQCoef * g_invQuantScales[m_cQP.m_iRem] << m_cQP.m_iPer + 1 << (iShift-1) ) >> iShift;
					 = ( clipQCoef * g_invQuantScales[m_cQP.m_iRem] << m_cQP.m_iPer + 1 << (bdShift - 4 - 1) ) >> (bdShift - 4);
					 = ( clipQCoef * 2^4 *g_invQuantScales[m_cQP.m_iRem] << m_cQP.m_iPer + 1 << (bdShift - 1) ) >> bdShift;
	  由于scaling_list_enabled_flag默认为false,因此m[x][y]默认为16,即公式中的2^4。
	  */
      piCoef[n] = Clip3(-32768,32767,iCoeffQ);
    }
  }
}


上一篇:vue项目eslint配置 以及 解释


下一篇:上了学这么久,我才知道他们为什么可以这么爽(下)