最近刚接触X265,由于需要在265的量化部分进行一定的研究,因此最近把HM的量化部分代码仔细看了一遍,现在对HM中的量化部分有了一定的理解,将自己的理解写在了注释中,贴出来献丑一下。其中很多都是比较小白的注释,大神请忽略。另外由于刚接触不久,注释中肯定会有很多理解不对的地方,希望有大牛看了能随时批评与指正~~~~
HM中的变换量化函数是transformNxN(),其中先是调用xTransformSkip()或xT()进行变换,之后调用xQuant()进行量化:
Void TComTrQuant::xQuant( TComDataCU* pcCU,
Int* pSrc,
TCoeff* pDes,
#if ADAPTIVE_QP_SELECTION
Int*& pArlDes,
#endif
Int iWidth,
Int iHeight,
UInt& uiAcSum,
TextType eTType,
UInt uiAbsPartIdx )
{
Int* piCoef = pSrc;
TCoeff* piQCoef = pDes;
#if ADAPTIVE_QP_SELECTION
Int* piArlCCoef = pArlDes;
#endif
Int iAdd = 0;
Bool useRDOQ = pcCU->getTransformSkip(uiAbsPartIdx,eTType) ? m_useRDOQTS:m_useRDOQ;
if ( useRDOQ && (eTType == TEXT_LUMA || RDOQ_CHROMA))
{
#if ADAPTIVE_QP_SELECTION
xRateDistOptQuant( pcCU, piCoef, pDes, pArlDes, iWidth, iHeight, uiAcSum, eTType, uiAbsPartIdx );
#else
xRateDistOptQuant( pcCU, piCoef, pDes, iWidth, iHeight, uiAcSum, eTType, uiAbsPartIdx );
#endif
}
else//标准量化???
{
const UInt log2BlockSize = g_aucConvertToBit[ iWidth ] + 2;//log2 N
UInt scanIdx = pcCU->getCoefScanIdx(uiAbsPartIdx, iWidth, eTType==TEXT_LUMA, pcCU->isIntra(uiAbsPartIdx));//扫描索引
const UInt *scan = g_auiSigLastScan[ scanIdx ][ log2BlockSize - 1 ];//光栅扫描与zig-zag扫描的位置对应表
Int deltaU[32*32] ;
#if ADAPTIVE_QP_SELECTION
QpParam cQpBase;
Int iQpBase = pcCU->getSlice()->getSliceQpBase();//slice层的QP值 用来对实际QP值进行预测
Int qpScaled;
Int qpBDOffset = (eTType == TEXT_LUMA)? pcCU->getSlice()->getSPS()->getQpBDOffsetY() : pcCU->getSlice()->getSPS()->getQpBDOffsetC();
if(eTType == TEXT_LUMA)//亮度分量的情况
{
qpScaled = iQpBase + qpBDOffset;//预测得出亮度块的QP
}
else//色度分量Cb Cr的情况
{
Int chromaQPOffset;
if(eTType == TEXT_CHROMA_U)//U分量
{
chromaQPOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();//得出色度块Cr的pps和slice层的偏移之和 pps_offset + slice_offset
}
else//V分量
{
chromaQPOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();//得出色度块Cb的pps和slice层的偏移之和 pps_offset + slice_offset
}
iQpBase = iQpBase + chromaQPOffset;//QP(pred) + pps_offset + slice_offset
qpScaled = Clip3( -qpBDOffset, 57, iQpBase);//使得 qpBDOffset <= iQpBase <= 57
if(qpScaled < 0)
{
qpScaled = qpScaled + qpBDOffset;//预测得到色度的QP: QP(pred) + pps_offset + slice_offset + QP(delta)
}
else
{
qpScaled = g_aucChromaScale[ qpScaled ] + qpBDOffset;//预测得到色度的QP: QP(pred) + pps_offset + slice_offset + QP(delta)
}
}
cQpBase.setQpParam(qpScaled);//设置m_iQP m_iPer m_iRem的值
#endif
UInt uiLog2TrSize = g_aucConvertToBit[ iWidth ] + 2;//log2 N
Int scalingListType = (pcCU->isIntra(uiAbsPartIdx) ? 0 : 3) + g_eTTable[(Int)eTType];//扫描方式
assert(scalingListType < SCALING_LIST_NUM);
Int *piQuantCoeff = 0;
piQuantCoeff = getQuantCoeff(scalingListType,m_cQP.m_iRem,uiLog2TrSize-2);//获取量化矩阵中的系数
UInt uiBitDepth = eTType == TEXT_LUMA ? g_bitDepthY : g_bitDepthC;
Int iTransformShift = MAX_TR_DYNAMIC_RANGE - uiBitDepth - uiLog2TrSize; //之前的变换中的缩放比例 Represents scaling through forward transform
#if ADAPTIVE_QP_SELECTION
Int iQBits = QUANT_SHIFT + cQpBase.m_iPer + iTransformShift;//非RDO量化器的右偏移量
iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9);//用于计算f = 1/3(I) 或1/6(B/P)
Int iQBitsC = QUANT_SHIFT + cQpBase.m_iPer + iTransformShift - ARL_C_PRECISION;
Int iAddC = 1 << (iQBitsC-1);//用于计算f = 0.5
#else
Int iQBits = QUANT_SHIFT + m_cQP.m_iPer + iTransformShift; //非RDO量化器的右偏移量 Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits
iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9);
#endif
Int qBits8 = iQBits-8;
for( Int n = 0; n < iWidth*iHeight; n++ )
{
Int iLevel;
Int iSign;
UInt uiBlockPos = n;
iLevel = piCoef[uiBlockPos];//变换后的系数
iSign = (iLevel < 0 ? -1: 1); //变换后的系数的符号
#if ADAPTIVE_QP_SELECTION
Int64 tmpLevel = (Int64)abs(iLevel) * piQuantCoeff[uiBlockPos];//QM:比例缩放
if( m_bUseAdaptQpSelect )
{
piArlCCoef[uiBlockPos] = (Int)((tmpLevel + iAddC ) >> iQBitsC);
}
iLevel = (Int)((tmpLevel + iAdd ) >> iQBits);//计算量化后的系数 f = 1/3(I) 或1/6(B/P)
deltaU[uiBlockPos] = (Int)((tmpLevel - (iLevel<<iQBits) )>> qBits8);//= -iAdd >> qBits8
#else
iLevel = ((Int64)abs(iLevel) * piQuantCoeff[uiBlockPos] + iAdd ) >> iQBits;
deltaU[uiBlockPos] = (Int)( ((Int64)abs(piCoef[uiBlockPos]) * piQuantCoeff[uiBlockPos] - (iLevel<<iQBits) )>> qBits8 );
#endif
uiAcSum += iLevel;//变换量化系数的绝对和 absolute sum of quantized transform coefficient
iLevel *= iSign;
piQCoef[ui