在H.266中,做完主变换后,还要进行二次变换,然后才进行量化;
Void TComTrQuant::transformNxN( TComTU & rTu,
const ComponentID compID,
Pel * pcResidual,//残差;
const UInt uiStride,
TCoeff * rpcCoeff,//残差经变换量化后的系数;
#if ADAPTIVE_QP_SELECTION
TCoeff * pcArlCoeff,
#endif
TCoeff & uiAbsSum,
const QpParam & cQP
#if VCEG_AZ08_KLT_COMMON
, Bool useKLT
#endif
)
{
const TComRectangle &rect = rTu.getRect(compID);
const UInt uiWidth = rect.width;
const UInt uiHeight = rect.height;
TComDataCU* pcCU = rTu.getCU();
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
const UInt uiOrgTrDepth = rTu.GetTransformDepthRel();
uiAbsSum=0;//存放残差系数绝对值的和;
RDPCMMode rdpcmMode = RDPCM_OFF;//默认是关闭rdpcm的;
rdpcmNxN( rTu, compID, pcResidual, uiStride, cQP, rpcCoeff, uiAbsSum, rdpcmMode );
if (rdpcmMode == RDPCM_OFF)
{
uiAbsSum = 0;
//transform and quantise
if(pcCU->getCUTransquantBypass(uiAbsPartIdx))//旁路掉变换和量化,即直接把残差系数赋值给rpcCoeff;
{
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);
const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1;
for (UInt y = 0, coefficientIndex = 0; y<uiHeight; y++)
{
for (UInt x = 0; x<uiWidth; x++, coefficientIndex++)
{
const Pel currentSample = pcResidual[(y * uiStride) + x];
rpcCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = currentSample;
uiAbsSum += TCoeff(abs(currentSample));
}
}
}
else//不旁路变换量化
{
#if DEBUG_TRANSFORM_AND_QUANTISE
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at input to transform\n";
printBlock(pcResidual, uiWidth, uiHeight, uiStride);
#endif
#if JVET_C0024_QTBT
assert( (pcCU->getSlice()->getSPS()->getCTUSize() >= uiWidth) );
#else
assert( (pcCU->getSlice()->getSPS()->getMaxTrSize() >= uiWidth) );
#endif
if(pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0)//如果跳过变换,将残差系数经过伸缩和移位后赋值给m_plTempCoeff;
{
xTransformSkip( pcResidual, uiStride, m_plTempCoeff, rTu, compID );
}
else//不跳过变换
{
const Int channelBitDepth=pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));//10;
xT( channelBitDepth, rTu.useDST(compID), pcResidual, uiStride, m_plTempCoeff, uiWidth, uiHeight, pcCU->getSlice()->getSPS()->getMaxLog2TrDynamicRange(toChannelType(compID))
#if COM16_C806_EMT
, getEmtMode ( rTu, compID )
, getEmtTrIdx( rTu, compID )
#endif
#if VCEG_AZ08_KLT_COMMON
, useKLT && (compID == 0)
#endif
);//执行变换的主函数,也是第一次变换
}
#if DEBUG_TRANSFORM_AND_QUANTISE
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between transform and quantiser\n";
printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth);
#endif
#if VCEG_AZ05_ROT_TR
#if JVET_C0024_QTBT
Char ucROTIdx = pcCU->getROTIdx(toChannelType(compID), uiAbsPartIdx) ;
if (ucROTIdx && uiWidth>=4 && uiHeight>=4)
#else
if (pcCU->getROTIdx(uiAbsPartIdx) )
#endif
{
static Int ROT_MATRIX[16];
Int iSubGroupXMax = Clip3 (1,16,(Int)( (uiWidth>>2)));
Int iSubGroupYMax = Clip3 (1,16,(Int)( (uiHeight>>2)));
Int iOffSetX = 0;
Int iOffSetY = 0;
Int y = 0;
Int* piCoeffTemp = m_plTempCoeff;
Int* piROTTemp = ROT_MATRIX;
Int iString2CopySize = 4*sizeof(Int);
for (Int iSubGroupX = 0; iSubGroupX<iSubGroupXMax; iSubGroupX++)
for (Int iSubGroupY = 0; iSubGroupY<iSubGroupYMax; iSubGroupY++)
{
iOffSetX = 4*iSubGroupX;
iOffSetY = 4*iSubGroupY*uiWidth;
piROTTemp = ROT_MATRIX;
piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
for( y = 0; y < 4; y++ )
{
::memcpy(piROTTemp, piCoeffTemp, iString2CopySize);
piROTTemp +=4;
piCoeffTemp +=uiWidth;
}
#if JVET_C0024_QTBT
RotTransform4I( ROT_MATRIX, ucROTIdx-1 );
#else
RotTransform4I( ROT_MATRIX, pcCU->getROTIdx(uiAbsPartIdx)-1 );
#endif
piROTTemp = ROT_MATRIX;
piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
for( y = 0; y < 4; y++ )
{
::memcpy(piCoeffTemp,piROTTemp, iString2CopySize);
piROTTemp +=4;
piCoeffTemp +=uiWidth;
}
}
}
#elif COM16_C1044_NSST
#if JVET_C0024_QTBT
Char ucNsstIdx = pcCU->getROTIdx(toChannelType(compID), uiAbsPartIdx) ;//二次变换的索引
if (ucNsstIdx && uiWidth>=4 && uiHeight>=4
#if JVET_C0045_C0053_NO_NSST_FOR_TS
&& !pcCU->getTransformSkip(uiAbsPartIdx, compID)
#endif
)//ucNsstIdx在不等于0且宽和高都大于等于4且不是TS的前提下才做二次变换;
#else
if (pcCU->getROTIdx(uiAbsPartIdx)
#if JVET_C0045_C0053_NO_NSST_FOR_TS
&& !pcCU->getTransformSkip(uiAbsPartIdx, compID)
#endif
)
#endif
{
#if JVET_D0120_NSST_IMPROV
static Int NSST_MATRIX[64];
const Int iLog2SbSize = (uiWidth > 4 && uiHeight > 4) ? 3 : 2;//宽和高都大于4,则等于3,否则等于2
const Int iSbSize = (uiWidth > 4 && uiHeight > 4) ? 8 : 4;//宽和高都大于4,则等于8,否则等于4
const Int iSubGroupXMax = Clip3(1, 8, (Int)uiWidth ) >> iLog2SbSize;
const Int iSubGroupYMax = Clip3(1, 8, (Int)uiHeight) >> iLog2SbSize;
#else
static Int NSST_MATRIX[16];
Int iSubGroupXMax = Clip3 (1,16,(Int)( (uiWidth>>2)));
Int iSubGroupYMax = Clip3 (1,16,(Int)( (uiHeight>>2)));
#endif
Int iOffSetX = 0;
Int iOffSetY = 0;
Int y = 0;
Int* piCoeffTemp = m_plTempCoeff;
Int* piNsstTemp = NSST_MATRIX;
#if JVET_D0120_NSST_IMPROV
Int iString2CopySize = iSbSize*sizeof(Int);
#else
Int iString2CopySize = 4*sizeof(Int);
#endif
#if VCEG_AZ07_CTX_RESIDUALCODING
#if !JVET_C0024_QTBT
const UInt uiLog2BlockSize = g_aucConvertToBit[ uiWidth ] + 2;
#endif
#endif
const UInt uiScanIdx = pcCU->getCoefScanIdx(uiAbsPartIdx, uiWidth, uiHeight, compID);//系数扫描索引
#if JVET_C0024_QTBT
const UInt log2BlockWidth = g_aucConvertToBit[uiWidth] + MIN_CU_LOG2;
const UInt log2BlockHeight = g_aucConvertToBit[uiHeight] + MIN_CU_LOG2;
#else
const UInt log2BlockWidth = g_aucConvertToBit[uiWidth] + 2;
const UInt log2BlockHeight = g_aucConvertToBit[uiHeight] + 2;
#endif
#if VCEG_AZ07_CTX_RESIDUALCODING
#if JVET_D0120_NSST_IMPROV
#if JVET_C0024_QTBT
const UInt *scan = (log2BlockWidth>=3 && log2BlockHeight>=3) ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-3] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#else
const UInt *scan = uiLog2BlockSize>3 ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-4] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#endif
#else
#if JVET_C0024_QTBT
const UInt *scan = (log2BlockWidth==3 && log2BlockHeight==3) ? g_auiCoefScanFirstCG8x8[uiScanIdx] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#else
const UInt *scan = uiLog2BlockSize==3 ? g_auiCoefScanFirstCG8x8[uiScanIdx] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#endif
#endif
#else
#if JVET_D0120_NSST_IMPROV
#if JVET_C0024_QTBT
const UInt *scan = (log2BlockWidth>=3 && log2BlockHeight>=3) ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-3] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#else
const UInt *scan = uiLog2BlockSize>3 ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-4] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#endif
#else
const UInt *scan = g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth ][ log2BlockHeight ];
#endif
#endif
UInt uiIntraMode = pcCU->getIntraDir( toChannelType(compID), uiAbsPartIdx);//得到帧内预测模式;
if( compID != COMPONENT_Y )
{
#if JVET_E0062_MULTI_DMS && COM16_C806_LMCHROMA
if( uiIntraMode == LM_CHROMA_IDX )
{
uiIntraMode = PLANAR_IDX;
}
#if JVET_E0077_ENHANCED_LM
if (IsLMMode(uiIntraMode))
{
uiIntraMode = PLANAR_IDX;
}
#endif
#else
if( uiIntraMode == DM_CHROMA_IDX )
{
#if JVET_C0024_QTBT
if( pcCU->getSlice()->isIntra() )
{
uiIntraMode = pcCU->getPic()->getCtu(pcCU->getCtuRsAddr())->getIntraDir(CHANNEL_TYPE_LUMA, pcCU->getZorderIdxInCtu()+uiAbsPartIdx);
}
else
{
#endif
uiIntraMode = pcCU->getIntraDir( CHANNEL_TYPE_LUMA, uiAbsPartIdx );
#if JVET_C0024_QTBT
}
#endif
}
#if COM16_C806_LMCHROMA
else if( uiIntraMode == LM_CHROMA_IDX )
{
uiIntraMode = PLANAR_IDX;
}
#endif
#if JVET_E0077_ENHANCED_LM
if (IsLMMode(uiIntraMode))
{
uiIntraMode = PLANAR_IDX;
}
#endif
#endif
}
assert( uiIntraMode<NUM_INTRA_MODE-1 );
const Int iNsstCandNum = ( uiIntraMode<=DC_IDX ) ? 3 : 4;//二次变换候选数量,DC和planar和CCLM模式的候选数量为3,其他为4;
#if JVET_C0024_QTBT
if( iNsstCandNum > ucNsstIdx )
#else
if( iNsstCandNum > pcCU->getROTIdx(uiAbsPartIdx) )
#endif
{
#if JVET_D0120_NSST_IMPROV
#if JVET_C0024_QTBT
const Int * permut = iSbSize>4 ? g_nsstHyGTPermut8x8[g_NsstLut[uiIntraMode]][ucNsstIdx - 1] : g_nsstHyGTPermut4x4[g_NsstLut[uiIntraMode]][ucNsstIdx - 1];
#else
const Int * permut = iSbSize>4 ? g_nsstHyGTPermut8x8[g_NsstLut[uiIntraMode]][pcCU->getROTIdx(uiAbsPartIdx) - 1] : g_nsstHyGTPermut4x4[g_NsstLut[uiIntraMode]][pcCU->getROTIdx(uiAbsPartIdx) - 1];
#endif
#endif
for (Int iSubGroupX = 0; iSubGroupX<iSubGroupXMax; iSubGroupX++)
{
for (Int iSubGroupY = 0; iSubGroupY<iSubGroupYMax; iSubGroupY++)
{
#if JVET_D0120_NSST_IMPROV
iOffSetX = iSbSize*iSubGroupX;
iOffSetY = iSbSize*iSubGroupY*uiWidth;
#else
iOffSetX = 4*iSubGroupX;
iOffSetY = 4*iSubGroupY*uiWidth;
#endif
piNsstTemp = NSST_MATRIX;
piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
#if JVET_D0120_NSST_IMPROV
for( y = 0; y < iSbSize; y++ )//遍历每一行
#else
for( y = 0; y < 4; y++ )
#endif
{
if( uiIntraMode>DIA_IDX )//垂直方向,即将CoeffTemp转置后复制给NsstTemp;
{
#if JVET_D0120_NSST_IMPROV
if( iSbSize==4 )
{//[0][1][2][3]是第一行,[0][4][8][12]是第一列
piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 4] = piCoeffTemp[1];
piNsstTemp[ 8] = piCoeffTemp[2]; piNsstTemp[12] = piCoeffTemp[3];
}
else if( iSbSize==8 )
{
piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 8] = piCoeffTemp[1];
piNsstTemp[16] = piCoeffTemp[2]; piNsstTemp[24] = piCoeffTemp[3];
piNsstTemp[32] = piCoeffTemp[4]; piNsstTemp[40] = piCoeffTemp[5];
piNsstTemp[48] = piCoeffTemp[6]; piNsstTemp[56] = piCoeffTemp[7];
}
#else
piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 4] = piCoeffTemp[1];
piNsstTemp[ 8] = piCoeffTemp[2]; piNsstTemp[12] = piCoeffTemp[3];
#endif
piNsstTemp ++;
}
else//uiIntraMode<=DIA_IDX
{
::memcpy(piNsstTemp, piCoeffTemp, iString2CopySize); //水平方向直接复制;
#if JVET_D0120_NSST_IMPROV
piNsstTemp += iSbSize;
#else
piNsstTemp +=4;
#endif
}
piCoeffTemp +=uiWidth;
}
#if JVET_C0024_QTBT
#if JVET_D0120_NSST_IMPROV//NSST是JEM中新加的技术,有两种
if ( iSbSize>4 )
{
FwdNsst8x8( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );//大于等于8x8的TU,使用8x8的NSST
}
else
{
FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );//4x4的TU,使用4x4的NSST
}
#else
FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );
#endif
#else
#if JVET_D0120_NSST_IMPROV
if ( iSbSize>4 )
{
FwdNsst8x8( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
}
else
{
FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
}
#else
FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
#endif
#endif
piNsstTemp = NSST_MATRIX;
piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
#if JVET_D0120_NSST_IMPROV
for( y = 0; y < iSbSize*iSbSize; y++ )
#else
for( y = 0; y < 16; y++ )
#endif
{
#if JVET_D0120_NSST_IMPROV
piCoeffTemp[scan[y]] = piNsstTemp[permut[y]];
#else
piCoeffTemp[scan[y]] = piNsstTemp[y];
#endif
}
}
}
}
}
#endif
#if VCEG_AZ08_KLT_COMMON
if (useKLT && (compID == 0))//如果是亮度分量且使用KLT
{
TUEntropyCodingParameters codingParameters;
getTUEntropyCodingParameters(codingParameters, rTu, compID);
const UInt *scan = codingParameters.scan;
reOrderCoeff(m_plTempCoeff, scan, uiWidth, uiHeight);//对系数进行重排序
}
#endif
xQuant( rTu, m_plTempCoeff, rpcCoeff,
#if ADAPTIVE_QP_SELECTION
pcArlCoeff,
#endif
uiAbsSum, compID, cQP
);//进行量化的主函数
#if DEBUG_TRANSFORM_AND_QUANTISE
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of quantiser\n";
printBlock(rpcCoeff, uiWidth, uiHeight, uiWidth);
#endif
}
}
//set the CBF
#if JVET_C0024_QTBT
assert(uiOrgTrDepth==0);
pcCU->setCbfPartRange((uiAbsSum > 0) ? 1 : 0, compID, uiAbsPartIdx, 0);//设置cbf,如果uiAbsSum大于0,则为1,否则为0
#else
pcCU->setCbfPartRange((((uiAbsSum > 0) ? 1 : 0) << uiOrgTrDepth), compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID));
#endif
}
Void TComTrQuant::xT( const Int channelBitDepth, Bool useDST, Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, Int iWidth, Int iHeight, const Int maxLog2TrDynamicRange
#if COM16_C806_EMT
, UChar ucMode
, UChar ucTrIdx
#endif
#if VCEG_AZ08_KLT_COMMON
, Bool useKLT
#endif
)
{
#if MATRIX_MULT
if( iWidth == iHeight)
{
#if COM16_C806_EMT
if( ucTrIdx!=DCT2_HEVC )
{
xTr_EMT(channelBitDepth, piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange, ucMode, ucTrIdx );
}
else
#endif
xTr(channelBitDepth, piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange);
return;
}
#endif
TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ];
TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ];
for (Int y = 0; y < iHeight; y++)
{
for (Int x = 0; x < iWidth; x++)
{
block[(y * iWidth) + x] = piBlkResi[(y * uiStride) + x];//先把残差数据赋值给临时数组block
}
}
#if COM16_C806_EMT
#if VCEG_AZ08_KLT_COMMON
if( ucTrIdx!=DCT2_HEVC && useKLT == false)//不是DCT2_HEVC且不使用KLT时进行EMT
#else
if( ucTrIdx!=DCT2_HEVC )
#endif
{
xTrMxN_EMT(channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange, ucMode, ucTrIdx );
}
else// ucTrIdx==DCT2_HEVC || useKLT==true
#endif
#if VCEG_AZ08_KLT_COMMON
xTrMxN( channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange, useKLT);
#else
xTrMxN( channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange );
#endif
memcpy(psCoeff, coeff, (iWidth * iHeight * sizeof(TCoeff)));//把变换后的系数赋值给psCoeff
}
Void TComTrQuant::xQuant( TComTU &rTu,
TCoeff * pSrc,
TCoeff * pDes,
#if ADAPTIVE_QP_SELECTION
TCoeff *pArlDes,
#endif
TCoeff &uiAbsSum,
const ComponentID compID,
const QpParam &cQP
)
{
const TComRectangle &rect = rTu.getRect(compID);
const UInt uiWidth = rect.width;
const UInt uiHeight = rect.height;
TComDataCU* pcCU = rTu.getCU();
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
const Int channelBitDepth = pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));
TCoeff* piCoef = pSrc;
TCoeff* piQCoef = pDes;
#if ADAPTIVE_QP_SELECTION
TCoeff* piArlCCoef = pArlDes;
#endif
const Bool useTransformSkip = pcCU->getTransformSkip(uiAbsPartIdx, compID);
const Int maxLog2TrDynamicRange = pcCU->getSlice()->getSPS()->getMaxLog2TrDynamicRange(toChannelType(compID));
Bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ;//使用率失真优化量化
#if JVET_C0024_QTBT
if (uiWidth<4 || uiHeight<4)//宽或高小于4,则不使用率失真优化量化
{
useRDOQ = false;
}
#endif
if ( useRDOQ && (isLuma(compID) || RDOQ_CHROMA) )
{
#if T0196_SELECTIVE_RDOQ
if ( !m_useSelectiveRDOQ || xNeedRDOQ( rTu, piCoef, compID, cQP ) )
{
#endif
#if ADAPTIVE_QP_SELECTION
xRateDistOptQuant( rTu, piCoef, pDes, pArlDes, uiAbsSum, compID, cQP );//率失真优化量化;
#else
xRateDistOptQuant( rTu, piCoef, pDes, uiAbsSum, compID, cQP );
#endif
#if T0196_SELECTIVE_RDOQ
}
else//否则直接将量化后系数设置为0
{
memset( pDes, 0, sizeof( TCoeff ) * uiWidth *uiHeight );
uiAbsSum = 0;
}
#endif
}
else//不使用RDOQ或者不是亮度分量
{
TUEntropyCodingParameters codingParameters;
getTUEntropyCodingParameters(codingParameters, rTu, compID);
const TCoeff entropyCodingMinimum = -(1 << maxLog2TrDynamicRange);//熵编码的最小值,-2^15
const TCoeff entropyCodingMaximum = (1 << maxLog2TrDynamicRange) - 1;//熵编码的最大值,2^15
TCoeff deltaU[MAX_TU_SIZE * MAX_TU_SIZE];
const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);
Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
assert(scalingListType < SCALING_LIST_NUM);
#if JVET_C0024_QTBT
const UInt uiLog2TrWidth = g_aucConvertToBit[uiWidth] + MIN_CU_LOG2;
const UInt uiLog2TrHeight = g_aucConvertToBit[uiHeight] + MIN_CU_LOG2;
Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrWidth-1, uiLog2TrHeight-1);
#else
Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrSize-2);
#endif
//指示是否使用加权量化矩阵
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0));
const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem];
/* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
* implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
* uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller)
* Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
*/
// Represents scaling through forward transform
Int iTransformShift = getTransformShift(channelBitDepth, uiLog2TrSize, maxLog2TrDynamicRange);
if (useTransformSkip && pcCU->getSlice()->getSPS()->getSpsRangeExtension().getExtendedPrecisionProcessingFlag())
{
iTransformShift = std::max<Int>(0, iTransformShift);
}
#if JVET_C0024_QTBT
Int iWHScale = 1;
if ((g_aucConvertToBit[ uiWidth ] + g_aucConvertToBit[ uiHeight ] + (MIN_CU_LOG2<<1))%2 !=0)
{
iTransformShift += 7;
iWHScale = 181;
}
#endif
const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
// QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
#if ADAPTIVE_QP_SELECTION
Int iQBitsC = MAX_INT;
Int iAddC = MAX_INT;
if (m_bUseAdaptQpSelect)
{
iQBitsC = iQBits - ARL_C_PRECISION;
iAddC = 1 << (iQBitsC-1);
}
#endif
const Int64 iAdd = (Int64)(pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << ((Int64)iQBits-9);
const Int qBits8 = iQBits - 8;
for( Int uiBlockPos = 0; uiBlockPos < uiWidth*uiHeight; uiBlockPos++ )//遍历该CU的每个变换后系数
{
const TCoeff iLevel = piCoef[uiBlockPos];//系数值
const TCoeff iSign = (iLevel < 0 ? -1: 1);//该系数的符号
//量化,enableScalingLists等于true则使用加权量化矩阵,否则使用默认的量化系数
const Int64 tmpLevel = (Int64)abs(iLevel) * (enableScalingLists ? piQuantCoeff[uiBlockPos] : defaultQuantisationCoefficient);
#if ADAPTIVE_QP_SELECTION
if( m_bUseAdaptQpSelect )
{
#if JVET_C0024_QTBT
piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel * iWHScale + iAddC ) >> iQBitsC);
#else
piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel + iAddC ) >> iQBitsC);
#endif
}
#endif
#if JVET_C0024_QTBT
const TCoeff quantisedMagnitude = TCoeff((tmpLevel * iWHScale + iAdd ) >> iQBits);//量化后的幅值
deltaU[uiBlockPos] = (TCoeff)((tmpLevel * iWHScale - ((Int64)quantisedMagnitude<<iQBits) )>> qBits8);
#else
const TCoeff quantisedMagnitude = TCoeff((tmpLevel + iAdd ) >> iQBits);
deltaU[uiBlockPos] = (TCoeff)((tmpLevel - (quantisedMagnitude<<iQBits) )>> qBits8);
#endif
uiAbsSum += quantisedMagnitude;
const TCoeff quantisedCoefficient = quantisedMagnitude * iSign;//量化系数等于量化幅值乘以符号
piQCoef[uiBlockPos] = Clip3<TCoeff>( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient );
} // for n
#if JVET_C0024_QTBT
if( pcCU->getSlice()->getPPS()->getSignHideFlag() && uiWidth>=4 && uiHeight>=4)//如果宽和高大于等于4且可以使用符号比特隐藏技术
#else
if( pcCU->getSlice()->getPPS()->getSignHideFlag() )
#endif
{
if(uiAbsSum >= 2) //this prevents TUs with only one coefficient of value 1 from being tested
{
signBitHidingHDQ( piQCoef, piCoef, deltaU, codingParameters, maxLog2TrDynamicRange ) ;
}
}
} //if RDOQ
//return;
}