这个函数主要包括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 = bUseReconstructedResidualForEstimate ? m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y) : pcResi->getStride(COMPONENT_Y);
preCalcAlpha = xCalcCrossComponentPredictionAlpha(TUIterator,
compID,
lumaResidualForEstimate,
pcResi->getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
tuCompRect.width,
tuCompRect.height,
lumaResidualStrideForEstimate,
pcResi->getStride(compID));
}
const Int transformSkipModesToTest = checkTransformSkip[compID] ? 2 : 1;//是否检查TrSkip模式,若是,则有TrSkip和nonTrSkip模式两种,否则只有nonTrSkip一种
//是否检查CrossC模式
const Int crossCPredictionModesToTest = (preCalcAlpha != 0) ? 2 : 1; // preCalcAlpha cannot be anything other than 0 if isCrossCPredictionAvailable is false
const Bool isOneMode = (crossCPredictionModesToTest == 1) && (transformSkipModesToTest == 1);//若不检查TrSkip和CrossC,则下述循环只有一种模式
for (Int transformSkipModeId = 0; transformSkipModeId < transformSkipModesToTest; transformSkipModeId++)
{
pcCU->setTransformSkipPartRange(transformSkipModeId, compID, subTUAbsPartIdx, partIdxesPerSubTU);//为子TU设置标志位
for (Int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++)//此双层循环最多有4种模式
{
const Bool isFirstMode = (transformSkipModeId == 0) && (crossCPredictionModeId == 0);//是否是第一种模式
const Bool bUseCrossCPrediction = crossCPredictionModeId != 0;//当前是否为CrossC模式
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );//加载熵编码器
m_pcEntropyCoder->resetBits();//重置比特数为0
pcCU->setTransformSkipPartRange(transformSkipModeId, compID, subTUAbsPartIdx, partIdxesPerSubTU);//为子TU设置TrSkip标志位
pcCU->setCrossComponentPredictionAlphaPartRange((bUseCrossCPrediction ? preCalcAlpha : 0), compID, subTUAbsPartIdx, partIdxesPerSubTU );//为子TU设置CrossC标志位
if ((compID != COMPONENT_Cr) && ((transformSkipModeId == 1) ? m_pcEncCfg->getUseRDOQTS() : m_pcEncCfg->getUseRDOQ()))// 是否使用了率失真优化的量化
{
COEFF_SCAN_TYPE scanType = COEFF_SCAN_TYPE(pcCU->getCoefScanIdx(uiAbsPartIdx, tuCompRect.width, tuCompRect.height, compID));
m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, tuCompRect.width, tuCompRect.height, toChannelType(compID), scanType);// 估算比特数??
}
#if RDOQ_CHROMA_LAMBDA
m_pcTrQuant->selectLambda(compID);
#endif
Pel *pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0);//当前层变换单元的首地址
UInt resiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID);//当前变换单元Stride
TCoeff bestCoeffComp [MAX_TU_SIZE*MAX_TU_SIZE];
Pel bestResiComp [MAX_TU_SIZE*MAX_TU_SIZE];
#if ADAPTIVE_QP_SELECTION
TCoeff bestArlCoeffComp[MAX_TU_SIZE*MAX_TU_SIZE];
#endif
TCoeff currAbsSum = 0;
UInt currCompBits = 0;//当前比特数
Distortion currCompDist = 0;
Double currCompCost = 0;
UInt nonCoeffBits = 0;//无残差情况下的比特数
Distortion nonCoeffDist = 0;
Double nonCoeffCost = 0;
if(!isOneMode && !isFirstMode)//第二、三、四种模式,将当前系数、残差copy到最佳中
{
memcpy(bestCoeffComp, currentCoefficients, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height));
#if ADAPTIVE_QP_SELECTION
memcpy(bestArlCoeffComp, currentARLCoefficients, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height));
#endif
for(Int y = 0; y < tuCompRect.height; y++)
{
memcpy(&bestResiComp[y * tuCompRect.width], (pcResiCurrComp + (y * resiStride)), (sizeof(Pel) * tuCompRect.width));
}
}
if (bUseCrossCPrediction)//根据是否使用CrossC模式选择相应的Transform
{
TComTrQuant::crossComponentPrediction(TUIterator,
compID,
pLumaResi,
pcResi->getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
crossCPredictedResidualBuffer,
tuCompRect.width,
tuCompRect.height,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y),
pcResi->getStride(compID),
tuCompRect.width,
false);
m_pcTrQuant->transformNxN(TUIterator, compID, crossCPredictedResidualBuffer, tuCompRect.width, currentCoefficients,
#if ADAPTIVE_QP_SELECTION
currentARLCoefficients,
#endif
currAbsSum, cQP);
}
else
{
m_pcTrQuant->transformNxN(TUIterator, compID, pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ), pcResi->getStride(compID), currentCoefficients,
#if ADAPTIVE_QP_SELECTION
currentARLCoefficients,
#endif
currAbsSum, cQP);
}
if(isFirstMode || (currAbsSum == 0))//为第一种模式,或AbsSum为0(尝试无残差编码)
{
if (bUseCrossCPrediction)//获取无残差编码的失真
{
TComTrQuant::crossComponentPrediction(TUIterator,
compID,
pLumaResi,
m_pTempPel,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
tuCompRect.width,
tuCompRect.height,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y),
tuCompRect.width,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID),
true);
nonCoeffDist = m_pcRdCost->getDistPart( channelBitDepth, m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ),
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride( compID ), pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ),
pcResi->getStride(compID), tuCompRect.width, tuCompRect.height, compID); // initialized with zero residual distortion
}
else
{
nonCoeffDist = m_pcRdCost->getDistPart( channelBitDepth, m_pTempPel, tuCompRect.width, pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ),
pcResi->getStride(compID), tuCompRect.width, tuCompRect.height, compID); // initialized with zero residual distortion
}
m_pcEntropyCoder->encodeQtCbfZero( TUIterator, toChannelType(compID) );//对cbf进行熵编码
if ( isCrossCPredictionAvailable )//若允许使用CrossC模式,则对CrossC标志位进行熵编码
{
m_pcEntropyCoder->encodeCrossComponentPrediction( TUIterator, compID );
}
nonCoeffBits = m_pcEntropyCoder->getNumberOfWrittenBits();
nonCoeffCost = m_pcRdCost->calcRdCost( nonCoeffBits, nonCoeffDist );//计算无残差编码的RDcost
}
if((puiZeroDist != NULL) && isFirstMode)
{
*puiZeroDist += nonCoeffDist; // initialized with zero residual distortion
}
DEBUG_STRING_NEW(sSingleStringTest)
if( currAbsSum > 0 ) //if non-zero coefficients are present, a residual needs to be derived for further prediction
{
if (isFirstMode)
{
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );//加载熵编码器
m_pcEntropyCoder->resetBits();
}
m_pcEntropyCoder->encodeQtCbf( TUIterator, compID, true );//对cbf进行熵编码
if (isCrossCPredictionAvailable)
{
m_pcEntropyCoder->encodeCrossComponentPrediction( TUIterator, compID );//对CrossC模式的标志位进行熵编码
}
m_pcEntropyCoder->encodeCoeffNxN( TUIterator, currentCoefficients, compID );//对系数进行熵编码
currCompBits = m_pcEntropyCoder->getNumberOfWrittenBits();
pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 );
m_pcTrQuant->invTransformNxN( TUIterator, compID, pcResiCurrComp, m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID), currentCoefficients, cQP DEBUG_STRING_PASS_INTO_OPTIONAL(&sSingleStringTest, (DebugOptionList::DebugString_InvTran.getInt()&debugPredModeMask)) );
if (bUseCrossCPrediction)//结合nonCoeffCost获取最终cur_Rdcost
{
TComTrQuant::crossComponentPrediction(TUIterator,
compID,
pLumaResi,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
tuCompRect.width,
tuCompRect.height,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y),
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID ),
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID ),
true);
}
currCompDist = m_pcRdCost->getDistPart( channelBitDepth, m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ),
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID),
pcResi->getAddrPix( compID, tuCompRect.x0, tuCompRect.y0 ),
pcResi->getStride(compID),
tuCompRect.width, tuCompRect.height, compID);//获取有残差编码的Rdcost
currCompCost = m_pcRdCost->calcRdCost(currCompBits, currCompDist);
if (pcCU->isLosslessCoded(0))//若是无损编码,则不使用无残差编码,即将其Rdcost设为最大值
{
nonCoeffCost = MAX_DOUBLE;
}
}
else if ((transformSkipModeId == 1) && !bUseCrossCPrediction)//AbsSum=0,若当前为TrSkip、nonCrossC模式,则当前Rdcost设为最大值
{
currCompCost = MAX_DOUBLE;
}
else//AbsSum=0,nonTrSkip或CrossC模式,当前Rdcost即为无残差编码的Rdcost(AbsSum=0)
{
currCompBits = nonCoeffBits;
currCompDist = nonCoeffDist;
currCompCost = nonCoeffCost;
}
// evaluate,若cur_Rdcost小于初始值,或当前为TrSkip模式且cur_Rdcost为最大值,即使用nonCoeff编码
if ((currCompCost < minCost[compID][subTUIndex]) || ((transformSkipModeId == 1) && (currCompCost == minCost[compID][subTUIndex])))
{
bestExplicitRdpcmModeUnSplit[compID][subTUIndex] = pcCU->getExplicitRdpcmMode(compID, subTUAbsPartIdx);
if(isFirstMode) //check for forced null
{
if((nonCoeffCost < currCompCost) || (currAbsSum == 0))//若nonCoeffCost最小
{
memset(currentCoefficients, 0, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height));//清除残差系数
currAbsSum = 0;//赋值AbsSum、Bits、Dist、Cost
currCompBits = nonCoeffBits;
currCompDist = nonCoeffDist;
currCompCost = nonCoeffCost;
}
}
#if DEBUG_STRING
if (currAbsSum > 0)
{
DEBUG_STRING_SWAP(sSingleStringComp[compID], sSingleStringTest)
}
else
{
sSingleStringComp[compID].clear();
}
#endif
//确定了最终AbsSum、Dist、Cost、TrSkip标志位、CrossC标志位,将其写入数组中
uiAbsSum [compID][subTUIndex] = currAbsSum;
uiSingleDistComp [compID][subTUIndex] = currCompDist;
minCost [compID][subTUIndex] = currCompCost;
uiBestTransformMode [compID][subTUIndex] = transformSkipModeId;
bestCrossCPredictionAlpha[compID][subTUIndex] = (crossCPredictionModeId == 1) ? pcCU->getCrossComponentPredictionAlpha(subTUAbsPartIdx, compID) : 0;
#if RQTET_ATTRIBUTE
if (uiAbsSum[compID][subTUIndex] == 0)
uinonZeroCoeff[compID][subTUIndex] = 0;
else
{
uinonZeroCoeff[compID][subTUIndex] = CountnonZeroCoeff(currentCoefficients, tuCompRect);
}
#endif
if (uiAbsSum[compID][subTUIndex] == 0)
{
if (bUseCrossCPrediction)
{
TComTrQuant::crossComponentPrediction(TUIterator,
compID,
pLumaResi,
m_pTempPel,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0),
tuCompRect.width,
tuCompRect.height,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(COMPONENT_Y),
tuCompRect.width,
m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID),
true);
}
else
{
pcResiCurrComp = m_pcQTTempTComYuv[uiQTTempAccessLayer].getAddrPix(compID, tuCompRect.x0, tuCompRect.y0);
const UInt uiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(compID);
for(UInt uiY = 0; uiY < tuCompRect.height; uiY++)
{
memset(pcResiCurrComp, 0, (sizeof(Pel) * tuCompRect.width));
pcResiCurrComp += uiStride;
}
}
}
}
else
{
// reset
memcpy(currentCoefficients, bestCoeffComp, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height));
#if ADAPTIVE_QP_SELECTION
memcpy(currentARLCoefficients, bestArlCoeffComp, (sizeof(TCoeff) * tuCompRect.width * tuCompRect.height));
#endif
for (Int y = 0; y < tuCompRect.height; y++)
{
memcpy((pcResiCurrComp + (y * resiStride)), &bestResiComp[y * tuCompRect.width], (sizeof(Pel) * tuCompRect.width));
}
}
}//CrossCMode循环
}//TrSkipMode循环
pcCU->setExplicitRdpcmModePartRange ( bestExplicitRdpcmModeUnSplit[compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU);
pcCU->setTransformSkipPartRange ( uiBestTransformMode [compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU );
pcCU->setCbfPartRange ((((uiAbsSum [compID][subTUIndex] > 0) ? 1 : 0) << uiTrMode), compID, subTUAbsPartIdx, partIdxesPerSubTU );
pcCU->setCrossComponentPredictionAlphaPartRange( bestCrossCPredictionAlpha [compID][subTUIndex], compID, subTUAbsPartIdx, partIdxesPerSubTU );
} while (TUIterator.nextSection(rTu)); //end of sub-TU loop
} // processing section
} // component loop
for(UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID = ComponentID(ch);
if (rTu.ProcessComponentSection(compID) && (rTu.getRect(compID).width != rTu.getRect(compID).height))//将矩形TU的cbf值传入子TU??
{
offsetSubTUCBFs(rTu, compID); //the CBFs up to now have been defined for two sub-TUs - shift them down a level and replace with the parent level CBF
}
}
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );//加载熵编码器
m_pcEntropyCoder->resetBits();
if( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) )//若当前TU尺寸较大
{
m_pcEntropyCoder->encodeTransformSubdivFlag( 0, 5 - uiLog2TrSize );//对划分标志位进行熵编码
}
for(UInt ch = 0; ch < numValidComp; ch++)
{
const UInt chOrderChange = ((ch + 1) == numValidComp) ? 0 : (ch + 1);
const ComponentID compID=ComponentID(chOrderChange);
if( rTu.ProcessComponentSection(compID) )
{
m_pcEntropyCoder->encodeQtCbf( rTu, compID, true );//对cbf进行熵编码
}
}
for(UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID=ComponentID(ch);
if (rTu.ProcessComponentSection(compID))
{
if(isChroma(compID) && (uiAbsSum[COMPONENT_Y][0] != 0))
{
m_pcEntropyCoder->encodeCrossComponentPrediction( rTu, compID );//对CrossC进行熵编码
}
m_pcEntropyCoder->encodeCoeffNxN( rTu, pcCoeffCurr[compID], compID );//对残差系数进行熵编码
for (UInt subTUIndex = 0; subTUIndex < 2; subTUIndex++)
{
uiSingleDist += uiSingleDistComp[compID][subTUIndex];//将矩形分割的子TU的Dist相加,获取当前层的失真
}
}
}
uiSingleBits = m_pcEntropyCoder->getNumberOfWrittenBits();//获取当前层编码比特数
dSingleCost = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDist );//计算当前层的Rdcost
#if RQTET_ATTRIBUTE
TComDataCU* RootCtu = pcCU->getPic()->getCtu(pcCU->getCtuRsAddr());
const UChar CuDepth = pcCU->getDepth(0);//0,1,2
UInt m_uiNumPartitions = RootCtu->getPic()->getNumPartitionsInCtu() >> (CuDepth << 1);
Double TrSize = pow(2, uiLog2TrSize);
if (pcCU->getSlice()->getSliceType() != I_SLICE && CuDepth <= 2 && pcCU->getPartitionSize(0) == SIZE_2Nx2N && !pcCU->getMergeFlag(0))
{
switch (CuDepth)
{
case 0:
if (TrSize == 32)
{
UInt m_sectionX = (rTu.GetRelPartIdxTU() / 64) % 2;
UInt m_sectionY = (rTu.GetRelPartIdxTU() / 64) / 2;
//for (size_t j = rTu.getCoefficientOffset(COMPONENT_Y) / 16; j < ((rTu.getCoefficientOffset(COMPONENT_Y) / 16) + (m_uiNumPartitions / 4)); j++)
for (size_t i = 0; i < 8; i++)
{
for (size_t k = 0; k < 8; k++)
{
size_t j = (i+8*m_sectionY) * 16 + (m_sectionX*8+k);
RootCtu->getrtet(ARRAY_32x32, j)->SingleCost = dSingleCost;
for (UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID = ComponentID(ch);
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;
RootCtu->getrtet(ARRAY_32x32, j)->AbsSum[compID] = splitIntoSubTUs ? (uiAbsSum[compID][0] + uiAbsSum[compID][1]) : uiAbsSum[compID][0];
RootCtu->getrtet(ARRAY_32x32, j)->nonZeroCoeff[compID] = splitIntoSubTUs ? (uinonZeroCoeff[compID][0] + uinonZeroCoeff[compID][1]) : uinonZeroCoeff[compID][0];
}
}
}
}
break;
case 1:
if (TrSize == 32)
{
for (size_t j = 0; j < m_uiNumPartitions; j++)
{
RootCtu->getrtet(ARRAY_32x32, j)->SingleCost = dSingleCost;
for (UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID = ComponentID(ch);
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;
RootCtu->getrtet(ARRAY_32x32, j)->AbsSum[compID] = splitIntoSubTUs ? (uiAbsSum[compID][0] + uiAbsSum[compID][1]) : uiAbsSum[compID][0];
RootCtu->getrtet(ARRAY_32x32, j)->nonZeroCoeff[compID] = splitIntoSubTUs ? (uinonZeroCoeff[compID][0] + uinonZeroCoeff[compID][1]) : uinonZeroCoeff[compID][0];
}
}
}
else if (TrSize == 16)
{
UInt m_sectionX = (rTu.GetRelPartIdxTU() / 16) % 2;
UInt m_sectionY = (rTu.GetRelPartIdxTU() / 16) / 2;
//for (size_t j = rTu.getCoefficientOffset(COMPONENT_Y) / 16; j < ((rTu.getCoefficientOffset(COMPONENT_Y) / 16) + (m_uiNumPartitions / 4)); j++)
for (size_t i = 0; i < 4; i++)
{
for (size_t k = 0; k < 4; k++)
{
UInt j = (i + 4 * m_sectionY) * 8 + (m_sectionX * 4 + k);
RootCtu->getrtet(ARRAY_16x16, j)->SingleCost = dSingleCost;
for (UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID = ComponentID(ch);
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;
RootCtu->getrtet(ARRAY_16x16, j)->AbsSum[compID] = splitIntoSubTUs ? (uiAbsSum[compID][0] + uiAbsSum[compID][1]) : uiAbsSum[compID][0];
RootCtu->getrtet(ARRAY_16x16, j)->nonZeroCoeff[compID] = splitIntoSubTUs ? (uinonZeroCoeff[compID][0] + uinonZeroCoeff[compID][1]) : uinonZeroCoeff[compID][0];
}
}
}
}
break;
case 2:
if (TrSize == 16)
{
for (size_t j = 0; j < m_uiNumPartitions; j++)
{
RootCtu->getrtet(ARRAY_16x16, j)->SingleCost = dSingleCost;
for (UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID = ComponentID(ch);
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;
RootCtu->getrtet(ARRAY_16x16, j)->AbsSum[compID] = splitIntoSubTUs ? (uiAbsSum[compID][0] + uiAbsSum[compID][1]) : uiAbsSum[compID][0];
RootCtu->getrtet(ARRAY_16x16, j)->nonZeroCoeff[compID] = splitIntoSubTUs ? (uinonZeroCoeff[compID][0] + uinonZeroCoeff[compID][1]) : uinonZeroCoeff[compID][0];
}
}
}
break;
default:
break;
}
}
#endif
} // check full
// code sub-blocks
if( bCheckSplit )
{
if( bCheckFull )//若对本层进行了check,则存储当前层基于RDO的熵编码信息
{
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] );
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
}
Distortion uiSubdivDist = 0;//初始化子TU失真
UInt uiSubdivBits = 0;//初始化子TU比特数
Double dSubdivCost = 0.0;//初始化子TU的Rdcost
//save the non-split CBFs in case we need to restore them later
UInt bestCBF [MAX_NUM_COMPONENT];//存储当前层的最佳CBF值
UInt bestsubTUCBF[MAX_NUM_COMPONENT][2];//若矩形TU需要分割,还需存储分割之后的CBF最佳值
for(UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID=ComponentID(ch);
if (rTu.ProcessComponentSection(compID))
{
bestCBF[compID] = pcCU->getCbf(uiAbsPartIdx, compID, uiTrMode);//存储当前层的最佳CBF值
const TComRectangle &tuCompRect = rTu.getRect(compID);
if (tuCompRect.width != tuCompRect.height)//若为矩形,则分割
{
const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> 1;
for (UInt subTU = 0; subTU < 2; subTU++)
{
bestsubTUCBF[compID][subTU] = pcCU->getCbf ((uiAbsPartIdx + (subTU * partIdxesPerSubTU)), compID, subTUDepth);//存储矩形TU分割的子TU的cbf
}
}
}
}
TComTURecurse tuRecurseChild(rTu, false);//获取并设置划分的子TU
const UInt uiQPartNumSubdiv = tuRecurseChild.GetAbsPartIdxNumParts();
DEBUG_STRING_NEW(sSplitString[MAX_NUM_COMPONENT])
do//递归调用进行划分
{
DEBUG_STRING_NEW(childString)
xEstimateInterResidualQT( pcResi, dSubdivCost, uiSubdivBits, uiSubdivDist, bCheckFull ? NULL : puiZeroDist, tuRecurseChild DEBUG_STRING_PASS_INTO(childString));
#if DEBUG_STRING
// split the string by component and append to the relevant output (because decoder decodes in channel order, whereas this search searches by TU-order)
std::size_t lastPos=0;
const std::size_t endStrng=childString.find(debug_reorder_data_inter_token[MAX_NUM_COMPONENT], lastPos);
for(UInt ch = 0; ch < numValidComp; ch++)
{
if (lastPos!=std::string::npos && childString.find(debug_reorder_data_inter_token[ch], lastPos)==lastPos)
{
lastPos+=strlen(debug_reorder_data_inter_token[ch]); // skip leading string
}
std::size_t pos=childString.find(debug_reorder_data_inter_token[ch+1], lastPos);
if (pos!=std::string::npos && pos>endStrng)
{
lastPos=endStrng;
}
sSplitString[ch]+=childString.substr(lastPos, (pos==std::string::npos)? std::string::npos : (pos-lastPos) );
lastPos=pos;
}
#endif
} while ( tuRecurseChild.nextSection(rTu) ) ;
UInt uiCbfAny=0;
for(UInt ch = 0; ch < numValidComp; ch++)
{
UInt uiYUVCbf = 0;
for( UInt ui = 0; ui < 4; ++ui )
{
uiYUVCbf |= pcCU->getCbf( uiAbsPartIdx + ui * uiQPartNumSubdiv, ComponentID(ch), uiTrMode + 1 );
}
UChar *pBase=pcCU->getCbf( ComponentID(ch) );
const UInt flags=uiYUVCbf << uiTrMode;
for( UInt ui = 0; ui < 4 * uiQPartNumSubdiv; ++ui )
{
pBase[uiAbsPartIdx + ui] |= flags;
}
uiCbfAny|=uiYUVCbf;
}
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
m_pcEntropyCoder->resetBits();
// when compID isn't a channel, code Cbfs:
xEncodeInterResidualQT( MAX_NUM_COMPONENT, rTu );//递归调用自己进行熵编码
for(UInt ch = 0; ch < numValidComp; ch++)
{
xEncodeInterResidualQT( ComponentID(ch), rTu );
}
uiSubdivBits = m_pcEntropyCoder->getNumberOfWrittenBits();
dSubdivCost = m_pcRdCost->calcRdCost( uiSubdivBits, uiSubdivDist );
if (!bCheckFull || (uiCbfAny && (dSubdivCost < dSingleCost)))
{
rdCost += dSubdivCost;
ruiBits += uiSubdivBits;
ruiDist += uiSubdivDist;
#if DEBUG_STRING
for(UInt ch = 0; ch < numValidComp; ch++)
{
DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[ch])
DEBUG_STRING_APPEND(sDebug, sSplitString[ch])
}
#endif
}
else
{
rdCost += dSingleCost;
ruiBits += uiSingleBits;
ruiDist += uiSingleDist;
//restore state to unsplit
pcCU->setTrIdxSubParts( uiTrMode, uiAbsPartIdx, uiDepth );
for(UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID=ComponentID(ch);
DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[ch])
if (rTu.ProcessComponentSection(compID))
{
DEBUG_STRING_APPEND(sDebug, sSingleStringComp[compID])
const Bool splitIntoSubTUs = rTu.getRect(compID).width != rTu.getRect(compID).height;
const UInt numberOfSections = splitIntoSubTUs ? 2 : 1;
const UInt partIdxesPerSubTU = rTu.GetAbsPartIdxNumParts(compID) >> (splitIntoSubTUs ? 1 : 0);
for (UInt subTUIndex = 0; subTUIndex < numberOfSections; subTUIndex++)
{
const UInt uisubTUPartIdx = uiAbsPartIdx + (subTUIndex * partIdxesPerSubTU);
if (splitIntoSubTUs)
{
const UChar combinedCBF = (bestsubTUCBF[compID][subTUIndex] << subTUDepth) | (bestCBF[compID] << uiTrMode);
pcCU->setCbfPartRange(combinedCBF, compID, uisubTUPartIdx, partIdxesPerSubTU);
}
else
{
pcCU->setCbfPartRange((bestCBF[compID] << uiTrMode), compID, uisubTUPartIdx, partIdxesPerSubTU);
}
pcCU->setCrossComponentPredictionAlphaPartRange(bestCrossCPredictionAlpha[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU);
pcCU->setTransformSkipPartRange(uiBestTransformMode[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU);
pcCU->setExplicitRdpcmModePartRange(bestExplicitRdpcmModeUnSplit[compID][subTUIndex], compID, uisubTUPartIdx, partIdxesPerSubTU);
}
}
}
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] );
}
}
else//若不划分了,则计算Cost和
{
rdCost += dSingleCost;
ruiBits += uiSingleBits;
ruiDist += uiSingleDist;
#if DEBUG_STRING
for(UInt ch = 0; ch < numValidComp; ch++)
{
const ComponentID compID=ComponentID(ch);
DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[compID])
if (rTu.ProcessComponentSection(compID))
{
DEBUG_STRING_APPEND(sDebug, sSingleStringComp[compID])
}
}
#endif
}
DEBUG_STRING_APPEND(sDebug, debug_reorder_data_inter_token[MAX_NUM_COMPONENT])
}
Void TEncSearch::xEncodeInterResidualQT( const ComponentID compID, TComTU &rTu )
{
TComDataCU* pcCU=rTu.getCU();
const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU();
const UInt uiCurrTrMode = rTu.GetTransformDepthRel();
assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) );
const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx );
const Bool bSubdiv = uiCurrTrMode != uiTrMode;
const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize();
if (compID==MAX_NUM_COMPONENT) // we are not processing a channel, instead we always recurse and code the CBFs
{
if( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() && uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) )
{
if((pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) && (pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N))
{
assert(bSubdiv); // Inferred splitting rule - see derivation and use of interSplitFlag in the specification.
}
else
{
m_pcEntropyCoder->encodeTransformSubdivFlag( bSubdiv, 5 - uiLog2TrSize );
}
}
assert( !pcCU->isIntra(uiAbsPartIdx) );
const Bool bFirstCbfOfCU = uiCurrTrMode == 0;
for (UInt ch=COMPONENT_Cb; ch<pcCU->getPic()->getNumberValidComponents(); ch++)
{
const ComponentID compIdInner=ComponentID(ch);
if( bFirstCbfOfCU || rTu.ProcessingAllQuadrants(compIdInner) )
{
if( bFirstCbfOfCU || pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode - 1 ) )
{
m_pcEntropyCoder->encodeQtCbf( rTu, compIdInner, !bSubdiv );
}
}
else
{
assert( pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode ) == pcCU->getCbf( uiAbsPartIdx, compIdInner, uiCurrTrMode - 1 ) );
}
}
if (!bSubdiv)
{
m_pcEntropyCoder->encodeQtCbf( rTu, COMPONENT_Y, true );
}
}
if( !bSubdiv )
{
if (compID != MAX_NUM_COMPONENT) // we have already coded the CBFs, so now we code coefficients
{
if (rTu.ProcessComponentSection(compID))
{
if (isChroma(compID) && (pcCU->getCbf(uiAbsPartIdx, COMPONENT_Y, uiTrMode) != 0))
{
m_pcEntropyCoder->encodeCrossComponentPrediction(rTu, compID);
}
if (pcCU->getCbf(uiAbsPartIdx, compID, uiTrMode) != 0)
{
const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;
TCoeff *pcCoeffCurr = m_ppcQTTempCoeff[compID][uiQTTempAccessLayer] + rTu.getCoefficientOffset(compID);
m_pcEntropyCoder->encodeCoeffNxN( rTu, pcCoeffCurr, compID );
}
}
}
}
else
{
if( compID==MAX_NUM_COMPONENT || pcCU->getCbf( uiAbsPartIdx, compID, uiCurrTrMode ) )
{
TComTURecurse tuRecurseChild(rTu, false);
do
{
xEncodeInterResidualQT( compID, tuRecurseChild );
} while (tuRecurseChild.nextSection(rTu));
}
}
}