这个函数主要包括TU单元的变化量化,反变换反量化,熵编码
其中
transformNxN函数为变化量化主函数
其中invtransformNxN函数为反变换反量化主函数
/*
** 估计残差的编码代价
** 主要是进行变换量化以及熵编码,然后选出最优的模式
*/
Void TEncSearch::xEstimateInterResidualQT(TComYuv *pcResi,
Double &rdCost,
UInt &ruiBits,
Distortion &ruiDist,
Distortion *puiZeroDist,
TComTU &rTu
DEBUG_STRING_FN_DECLARE(sDebug))
{
TComDataCU *pcCU = rTu.getCU();
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
const UInt uiDepth = rTu.GetTransformDepthTotal();//变换块的总深度,可直接得出块的尺寸
const UInt uiTrMode = rTu.GetTransformDepthRel();//TU相对CU的深度(TrIdx)
const UInt subTUDepth = uiTrMode + 1;
const UInt numValidComp = pcCU->getPic()->getNumberValidComponents();//有效分量
DEBUG_STRING_NEW(sSingleStringComp[MAX_NUM_COMPONENT])
assert(pcCU->getDepth(0) == pcCU->getDepth(uiAbsPartIdx));
const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize();//块尺寸
UInt SplitFlag = ((pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) && pcCU->isInter(uiAbsPartIdx) && (pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N));
#if DEBUG_STRING
const Int debugPredModeMask = DebugStringGetPredModeMask(pcCU->getPredictionMode(uiAbsPartIdx));
#endif
Bool bCheckFull;//TU大小从32x32开始
if (SplitFlag && uiDepth == pcCU->getDepth(uiAbsPartIdx) && (uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx)))
{//若划分,且当前总深度与CU深度相等(即TU还未进行划分),且当前TU尺寸较大;认为当前TU需要划分,则无需check当前层的TU而直接划分
bCheckFull = false;//无需check当前层TU
}
else
{//否则,若当前TU尺寸小于最大TU尺寸,则可check当前层TU
bCheckFull = (uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize());
}
const Bool bCheckSplit = (uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx));
//QuadtreeTULog2MinSizeInCU:不同尺寸的CU有不同的最小TU尺寸(64x64的CU最小TU为16x16;32x32的CU最小TU为8x8;16x16的CU最小TU为4x4)
//所以64x64的CU中TU深度(TrIdx)为1,2(也存在为0的情况,当ZeroCost<nonZeroCost时);32x32和16x16的CU中TU深度为0,1,2;
assert(bCheckFull || bCheckSplit);//检查当前层或划分至少有一项
Double dSingleCost = MAX_DOUBLE;
UInt uiSingleBits = 0;
Distortion uiSingleDistComp [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {
{0,0},{0,0},{0,0}};
Distortion uiSingleDist = 0;
TCoeff uiAbsSum [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {
{0,0},{0,0},{0,0}};
UInt uiBestTransformMode [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {
{0,0},{0,0},{0,0}};
// Stores the best explicit RDPCM mode for a TU encoded without split
UInt bestExplicitRdpcmModeUnSplit[MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {
{3,3}, {3,3}, {3,3}};
SChar bestCrossCPredictionAlpha [MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/] = {
{0,0},{0,0},{0,0}};
#if RQTET_ATTRIBUTE
Int uinonZeroCoeff [MAX_NUM_COMPONENT][2];
#endif
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
if( bCheckFull )
{
Double minCost[MAX_NUM_COMPONENT][2/*0 = top (or whole TU for non-4:2:2) sub-TU, 1 = bottom sub-TU*/];
Bool checkTransformSkip[MAX_NUM_COMPONENT];
pcCU->setTrIdxSubParts( uiTrMode, uiAbsPartIdx, uiDepth );
m_pcEntropyCoder->resetBits();//重置熵编码比特数
memset( m_pTempPel, 0, sizeof( Pel ) * rTu.getRect(COMPONENT_Y).width * rTu.getRect(COMPONENT_Y).height ); // not necessary needed for inside of recursion (only at the beginning)
const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;
TCoeff *pcCoeffCurr[MAX_NUM_COMPONENT];//YUV分量的系数
#if ADAPTIVE_QP_SELECTION
TCoeff *pcArlCoeffCurr[MAX_NUM_COMPONENT];
#endif
for(UInt i=0; i<numValidComp; i++)
{
minCost[i][0] = MAX_DOUBLE;//初始化最小cost
minCost[i][1] = MAX_DOUBLE;
}
Pel crossCPredictedResidualBuffer[ MAX_TU_SIZE * MAX_TU_SIZE ];
for(UInt i=0; i<numValidComp; i++)//有效分量循环
{
checkTransformSkip[i]=false;//初始化transformSkip为false
const ComponentID compID=ComponentID(i);
const Int channelBitDepth=pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));
pcCoeffCurr[compID] = m_ppcQTTempCoeff[compID][uiQTTempAccessLayer] + rTu.getCoefficientOffset(compID);//当前分量系数存储数组
#if ADAPTIVE_QP_SELECTION
pcArlCoeffCurr[compID] = m_ppcQTTempArlCoeff[compID ][uiQTTempAccessLayer] + rTu.getCoefficientOffset(compID);
#endif
if(rTu.ProcessComponentSection(compID))//当前分量是否存在(Width是否大于0)
{
const QpParam cQP(*pcCU, compID);
checkTransformSkip[compID] = pcCU->getSlice()->getPPS()->getUseTransformSkip() &&
TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(compID), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize()) &&
(!pcCU->isLosslessCoded(0));//获取TransformSkip标志位(使用TrSkip、且Rect可以TrSkip、且不使用无损编码的情况下,进行TrSkip模式)
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;//若当前TU为矩形,则分为两部分
TComTURecurse TUIterator(rTu, false, (splitIntoSubTUs ? TComTU::VERTICAL_SPLIT : TComTU::DONT_SPLIT), true, compID);//创建矩形TU分割的子TU
const UInt partIdxesPerSubTU = TUIterator.GetAbsPartIdxNumParts(compID);
do//矩形TU分割得到的子TU循环编码
{//初始化矩形分割得到的子TU的信息
const UInt subTUIndex = TUIterator.GetSectionNumber();
const UInt subTUAbsPartIdx = TUIterator.GetAbsPartIdxTU(compID);
const TComRectangle &tuCompRect = TUIterator.getRect(compID);
const UInt subTUBufferOffset = tuCompRect.width * tuCompRect.height * subTUIndex;//子TU的offset
TCoeff *currentCoefficients = pcCoeffCurr[compID] + subTUBufferOffset;//获取当前分量的子TU系数
#if ADAPTIVE_QP_SELECTION
TCoeff *currentARLCoefficients = pcArlCoeffCurr[compID] + subTUBufferOffset;
#endif
const Bool isCrossCPredictionAvailable = isChroma(compID)
&& pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag()
&& (pcCU->getCbf(subTUAbsPartIdx, COMPONENT_Y, uiTrMode) != 0);//是否使用交叉预测编码?色度编码可利用亮度编码的信息
//若当前分量为色度,且使用CrossCPred,且Y亮度分量的残差系数绝对值和大于0(cbf不为0)
SChar preCalcAlpha = 0;
const Pel *pLumaResi = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( COMPONENT_Y, rTu.getRect( COMPONENT_Y ).x0, rTu.getRect( COMPONENT_Y ).y0 );//亮度残差
if (isCrossCPredictionAvailable)
{
const Bool bUseReconstructedResidualForEstimate = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
const Pel *const lumaResidualForEstimate = bUseReconstructedResidualForEstimate ? pLumaResi : pcResi->getAddrPix(COMPONENT_Y, tuCompRect.x0, tuCompRect.y0);
const UInt lumaResidualStrideForEstimate = bUseReconst