频道栏目
首页 > 程序开发 > 综合编程 > 组件/库 > 正文
HM编码器代码阅读(18)——变换以及量化(一)
2016-04-20 09:39:53      个评论    来源:NB_vol_1的专栏  
收藏   我要投稿

入口函数:encodeResAndCalcRdInterCU。

这个函数的作用是根据预测值,求出残差,然后进行TU的划分,然后进行变换、量化等操作以及RD代价的计算。

流程:

(1)如果是帧内预测,那么直接返回
(2)判断是否使用skip模式,如果使用了:
1)对所有的子分割设置skip标志
2)清理残差
3)把预测的CU直接设置为重建的CU
4)计算率失真
5)加载SBAC熵编码器,并重置比特数
6)如果使用了跳过变换量化的标志(TransquantBypassEnableFlag),那么就对它进行编码
7)对跳过标志进行编码
8)对merge模式的索引进行编码
9)统计比特数等信息
10)退出该函数
(3)接下来的都是没有使用skip模式的计算
(4)做一些前期准备工作,比如让TU的尺寸达到符合规定等等
(5)调用TComYuv::subtract,求取残差CU。
(6)对量化步长,从最小到最大依次遍历:
1)加载SBAC编码器
2)调用xEstimateResidualQT对残差进行量化变换等操作,并求出当前的代价
3)调用encodeQtRootCbfZero,进行Zero模式进行熵编码
4)调用calcRdCost,计算Zero模式的率失真代价
5)如果Zero模式的代价小于当前的代价,那么使用Zero模式,设置相应的信息
6)如果Zero模式并不比当前代价小,那么调用xSetResidualQTData(递归调用),保存最优的残差信息
7)加载熵编码器
8)调用xAddSymbolBitsInter,计算当前CU在熵编码的时候产生的比特数
9)计算率失真代价
10)如果代价更小,那么更新相关信息,调用xSetResidualQTData等保存最优的残差信息
(7)根据上面的步骤选择出最优的量化步长,如果最优的量化步长不是最小的量化步长也不是最大的量化步长,那么保存相关的一些信息

(8)计算最优的代价,记录相关信息

 

Void TEncSearch::encodeResAndCalcRdInterCU( TComDataCU* pcCU, TComYuv* pcYuvOrg, TComYuv* pcYuvPred, TComYuv*& rpcYuvResi, TComYuv*& rpcYuvResiBest, TComYuv*& rpcYuvRec, Bool bSkipRes )
{
    // 如果它居然是进行帧内预测的,那么直接返回
	if ( pcCU->isIntra(0) )
	{
		return;
	}

	Bool      bHighPass    = pcCU->getSlice()->getDepth() ? true : false;
	UInt      uiBits       = 0, uiBitsBest = 0;
	UInt      uiDistortion = 0, uiDistortionBest = 0;

	UInt      uiWidth      = pcCU->getWidth ( 0 );
	UInt      uiHeight     = pcCU->getHeight( 0 );

	//  No residual coding : SKIP mode
    // 使用了skip模式
	if ( bSkipRes )
	{
		pcCU->setSkipFlagSubParts( true, 0, pcCU->getDepth(0) );

        // 清空残差
		rpcYuvResi->clear();

		pcYuvPred->copyToPartYuv( rpcYuvRec, 0 );

		uiDistortion = m_pcRdCost->getDistPart(g_bitDepthY, rpcYuvRec->getLumaAddr(), rpcYuvRec->getStride(),  pcYuvOrg->getLumaAddr(), pcYuvOrg->getStride(),  uiWidth,      uiHeight      )
			+ m_pcRdCost->getDistPart(g_bitDepthC, rpcYuvRec->getCbAddr(),   rpcYuvRec->getCStride(), pcYuvOrg->getCbAddr(),   pcYuvOrg->getCStride(), uiWidth >> 1, uiHeight >> 1, TEXT_CHROMA_U )
			+ m_pcRdCost->getDistPart(g_bitDepthC, rpcYuvRec->getCrAddr(),   rpcYuvRec->getCStride(), pcYuvOrg->getCrAddr(),   pcYuvOrg->getCStride(), uiWidth >> 1, uiHeight >> 1, TEXT_CHROMA_V );

		m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_CURR_BEST]);

		m_pcEntropyCoder->resetBits();

        // 使用了跳过变换量化的标志
		if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag())
		{
			m_pcEntropyCoder->encodeCUTransquantBypassFlag(pcCU, 0, true);
		}
        // 对跳过标志进行编码
		m_pcEntropyCoder->encodeSkipFlag(pcCU, 0, true);
        // 对merge索引进行编码
		m_pcEntropyCoder->encodeMergeIndex( pcCU, 0, true );

        // 得到已经写入的比特数
		uiBits = m_pcEntropyCoder->getNumberOfWrittenBits();
		pcCU->getTotalBits()       = uiBits;
		pcCU->getTotalDistortion() = uiDistortion;
		pcCU->getTotalCost()       = m_pcRdCost->calcRdCost( uiBits, uiDistortion );

		m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_TEMP_BEST]);

		pcCU->setCbfSubParts( 0, 0, 0, 0, pcCU->getDepth( 0 ) );
		pcCU->setTrIdxSubParts( 0, 0, pcCU->getDepth(0) );

		return;
	}

    // 没有使用skip模式,那么就要对残差进行编码(变换量化)
	//  Residual coding.
	Int    qp, qpBest = 0, qpMin, qpMax;
	Double  dCost, dCostBest = MAX_DOUBLE;

	UInt uiTrLevel = 0;
	if( (pcCU->getWidth(0) > pcCU->getSlice()->getSPS()->getMaxTrSize()) )
	{
		while( pcCU->getWidth(0) > (pcCU->getSlice()->getSPS()->getMaxTrSize()<>uiMaxTrMode) < (g_uiMaxCUWidth>>g_uiMaxCUDepth)) uiMaxTrMode--;

	qpMin =  bHighPass ? Clip3( -pcCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, pcCU->getQP(0) - m_iMaxDeltaQP ) : pcCU->getQP( 0 );
	qpMax =  bHighPass ? Clip3( -pcCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, pcCU->getQP(0) + m_iMaxDeltaQP ) : pcCU->getQP( 0 );

	rpcYuvResi->subtract( pcYuvOrg, pcYuvPred, 0, uiWidth );

	for ( qp = qpMin; qp <= qpMax; qp++ )
	{
		dCost = 0.;
		uiBits = 0;
		uiDistortion = 0;
		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_CURR_BEST ] );

		UInt uiZeroDistortion = 0;

        // 对残差进行计算
		xEstimateResidualQT( pcCU, 0, 0, 0, rpcYuvResi,  pcCU->getDepth(0), dCost, uiBits, uiDistortion, &uiZeroDistortion );

		m_pcEntropyCoder->resetBits();

        // 进行熵编码
		m_pcEntropyCoder->encodeQtRootCbfZero( pcCU );
		UInt zeroResiBits = m_pcEntropyCoder->getNumberOfWrittenBits();
        // 计算率失真代价
		Double dZeroCost = m_pcRdCost->calcRdCost( zeroResiBits, uiZeroDistortion );
		if(pcCU->isLosslessCoded( 0 ))
		{  
			dZeroCost = dCost + 1;
		}
		if ( dZeroCost < dCost )
		{
			dCost        = dZeroCost;
			uiBits       = 0;
			uiDistortion = uiZeroDistortion;

			const UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> (pcCU->getDepth(0) << 1);
			::memset( pcCU->getTransformIdx()      , 0, uiQPartNum * sizeof(UChar) );
			::memset( pcCU->getCbf( TEXT_LUMA )    , 0, uiQPartNum * sizeof(UChar) );
			::memset( pcCU->getCbf( TEXT_CHROMA_U ), 0, uiQPartNum * sizeof(UChar) );
			::memset( pcCU->getCbf( TEXT_CHROMA_V ), 0, uiQPartNum * sizeof(UChar) );
			::memset( pcCU->getCoeffY()            , 0, uiWidth * uiHeight * sizeof( TCoeff )      );
			::memset( pcCU->getCoeffCb()           , 0, uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
			::memset( pcCU->getCoeffCr()           , 0, uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
			pcCU->setTransformSkipSubParts ( 0, 0, 0, 0, pcCU->getDepth(0) );
		}
		else
		{
            // 设置残差四叉树的数据
			xSetResidualQTData( pcCU, 0, 0, 0, NULL, pcCU->getDepth(0), false );
		}

		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[pcCU->getDepth(0)][CI_CURR_BEST] );

		uiBits = 0;
		{
			TComYuv *pDummy = NULL;
			xAddSymbolBitsInter( pcCU, 0, 0, uiBits, pDummy, NULL, pDummy );
		}

        // 计算率失真代价
		Double dExactCost = m_pcRdCost->calcRdCost( uiBits, uiDistortion );
		dCost = dExactCost;

        // 更新最优值
		if ( dCost < dCostBest )
		{
			if ( !pcCU->getQtRootCbf( 0 ) )
			{
				rpcYuvResiBest->clear();
			}
			else
			{
				xSetResidualQTData( pcCU, 0, 0, 0, rpcYuvResiBest, pcCU->getDepth(0), true );
			}

			if( qpMin != qpMax && qp != qpMax )
			{
				const UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> (pcCU->getDepth(0) << 1);
				::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx(),        uiQPartNum * sizeof(UChar) );
				::memcpy( m_puhQTTempCbf[0], pcCU->getCbf( TEXT_LUMA ),     uiQPartNum * sizeof(UChar) );
				::memcpy( m_puhQTTempCbf[1], pcCU->getCbf( TEXT_CHROMA_U ), uiQPartNum * sizeof(UChar) );
				::memcpy( m_puhQTTempCbf[2], pcCU->getCbf( TEXT_CHROMA_V ), uiQPartNum * sizeof(UChar) );
				::memcpy( m_pcQTTempCoeffY,  pcCU->getCoeffY(),  uiWidth * uiHeight * sizeof( TCoeff )      );
				::memcpy( m_pcQTTempCoeffCb, pcCU->getCoeffCb(), uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
				::memcpy( m_pcQTTempCoeffCr, pcCU->getCoeffCr(), uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
#if ADAPTIVE_QP_SELECTION
				::memcpy( m_pcQTTempArlCoeffY,  pcCU->getArlCoeffY(),  uiWidth * uiHeight * sizeof( Int )      );
				::memcpy( m_pcQTTempArlCoeffCb, pcCU->getArlCoeffCb(), uiWidth * uiHeight * sizeof( Int ) >> 2 );
				::memcpy( m_pcQTTempArlCoeffCr, pcCU->getArlCoeffCr(), uiWidth * uiHeight * sizeof( Int ) >> 2 );
#endif
				::memcpy( m_puhQTTempTransformSkipFlag[0], pcCU->getTransformSkip(TEXT_LUMA),     uiQPartNum * sizeof( UChar ) );
				::memcpy( m_puhQTTempTransformSkipFlag[1], pcCU->getTransformSkip(TEXT_CHROMA_U), uiQPartNum * sizeof( UChar ) );
				::memcpy( m_puhQTTempTransformSkipFlag[2], pcCU->getTransformSkip(TEXT_CHROMA_V), uiQPartNum * sizeof( UChar ) );
			}
			uiBitsBest       = uiBits;
			uiDistortionBest = uiDistortion;
			dCostBest        = dCost;
			qpBest           = qp;
			m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_TEMP_BEST ] );
		}
	}

	assert ( dCostBest != MAX_DOUBLE );

	if( qpMin != qpMax && qpBest != qpMax )
	{
		assert( 0 ); // check
		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ pcCU->getDepth( 0 ) ][ CI_TEMP_BEST ] );

		// copy best cbf and trIdx to pcCU
		const UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> (pcCU->getDepth(0) << 1);
		::memcpy( pcCU->getTransformIdx(),       m_puhQTTempTrIdx,  uiQPartNum * sizeof(UChar) );
		::memcpy( pcCU->getCbf( TEXT_LUMA ),     m_puhQTTempCbf[0], uiQPartNum * sizeof(UChar) );
		::memcpy( pcCU->getCbf( TEXT_CHROMA_U ), m_puhQTTempCbf[1], uiQPartNum * sizeof(UChar) );
		::memcpy( pcCU->getCbf( TEXT_CHROMA_V ), m_puhQTTempCbf[2], uiQPartNum * sizeof(UChar) );
		::memcpy( pcCU->getCoeffY(),  m_pcQTTempCoeffY,  uiWidth * uiHeight * sizeof( TCoeff )      );
		::memcpy( pcCU->getCoeffCb(), m_pcQTTempCoeffCb, uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
		::memcpy( pcCU->getCoeffCr(), m_pcQTTempCoeffCr, uiWidth * uiHeight * sizeof( TCoeff ) >> 2 );
#if ADAPTIVE_QP_SELECTION
		::memcpy( pcCU->getArlCoeffY(),  m_pcQTTempArlCoeffY,  uiWidth * uiHeight * sizeof( Int )      );
		::memcpy( pcCU->getArlCoeffCb(), m_pcQTTempArlCoeffCb, uiWidth * uiHeight * sizeof( Int ) >> 2 );
		::memcpy( pcCU->getArlCoeffCr(), m_pcQTTempArlCoeffCr, uiWidth * uiHeight * sizeof( Int ) >> 2 );
#endif
		::memcpy( pcCU->getTransformSkip(TEXT_LUMA),     m_puhQTTempTransformSkipFlag[0], uiQPartNum * sizeof( UChar ) );
		::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_U), m_puhQTTempTransformSkipFlag[1], uiQPartNum * sizeof( UChar ) );
		::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_V), m_puhQTTempTransformSkipFlag[2], uiQPartNum * sizeof( UChar ) );
	}
	rpcYuvRec->addClip ( pcYuvPred, rpcYuvResiBest, 0, uiWidth );

	// update with clipped distortion and cost (qp estimation loop uses unclipped values)
	uiDistortionBest = m_pcRdCost->getDistPart(g_bitDepthY, rpcYuvRec->getLumaAddr(), rpcYuvRec->getStride(),  pcYuvOrg->getLumaAddr(), pcYuvOrg->getStride(),  uiWidth,      uiHeight      )
		+ m_pcRdCost->getDistPart(g_bitDepthC, rpcYuvRec->getCbAddr(),   rpcYuvRec->getCStride(), pcYuvOrg->getCbAddr(),   pcYuvOrg->getCStride(), uiWidth >> 1, uiHeight >> 1, TEXT_CHROMA_U )
		+ m_pcRdCost->getDistPart(g_bitDepthC, rpcYuvRec->getCrAddr(),   rpcYuvRec->getCStride(), pcYuvOrg->getCrAddr(),   pcYuvOrg->getCStride(), uiWidth >> 1, uiHeight >> 1, TEXT_CHROMA_V );
	dCostBest = m_pcRdCost->calcRdCost( uiBitsBest, uiDistortionBest );

	pcCU->getTotalBits()       = uiBitsBest;
	pcCU->getTotalDistortion() = uiDistortionBest;
	pcCU->getTotalCost()       = dCostBest;

	if ( pcCU->isSkipped(0) )
	{
		pcCU->setCbfSubParts( 0, 0, 0, 0, pcCU->getDepth( 0 ) );
	}

	pcCU->setQPSubParts( qpBest, 0, pcCU->getDepth(0) );
}
根据预测帧和原始帧计算残差:

 

 

Void TComYuv::subtract( TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, UInt uiTrUnitIdx, UInt uiPartSize )
{
	subtractLuma  ( pcYuvSrc0, pcYuvSrc1,  uiTrUnitIdx, uiPartSize    );
	subtractChroma( pcYuvSrc0, pcYuvSrc1,  uiTrUnitIdx, uiPartSize>>1 );
}
TEncSearch::xEstimateResidualQT函数详解:
函数的主要功能是对残差进行变换以及量化
(1)首先对当前TU的三个分量(Y、U、V)进行变换量化以及反变换反量化,根据率失真代价等参数选出最优模式,对变换量化之后的系数进行编码
(2)如果当前TU会被分割成四个子TU,那么
①对当前TU的四个子TU递归调用xEstimateResidualQT
②对当前TU的亮度对应的四叉树调用xEncodeResidualQT、以及对子TU的YUV三个分量对应的四叉树调用xEncodeResidualQT进行编码
③计算率失真代价

 

 

Void TEncSearch::xEstimateResidualQT( TComDataCU* pcCU, UInt uiQuadrant, UInt uiAbsPartIdx, UInt absTUPartIdx, TComYuv* pcResi, const UInt uiDepth, Double &rdCost, UInt &ruiBits, UInt &ruiDist, UInt *puiZeroDist )
{
	// 四叉树的分割模式
	const UInt uiTrMode = uiDepth - pcCU->getDepth( 0 );

	assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) );

	// 计算尺寸
	const UInt uiLog2TrSize = g_aucConvertToBit[pcCU->getSlice()->getSPS()->getMaxCUWidth() >> uiDepth]+2;

	// split标志
	UInt SplitFlag = ((pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) && pcCU->getPredictionMode(uiAbsPartIdx) == MODE_INTER && ( pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N ));
	
	// 完整检查的标志
	Bool bCheckFull;
	if ( SplitFlag && uiDepth == pcCU->getDepth(uiAbsPartIdx) && ( uiLog2TrSize >  pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) )
	{
		bCheckFull = false;
	}
	else
	{
		bCheckFull =  ( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() );
	}

	// 是否检查split标志
	const Bool bCheckSplit  = ( uiLog2TrSize >  pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) );

	assert( bCheckFull || bCheckSplit );

	// 是否对色度分量进行编码
	Bool  bCodeChroma   = true;
	// 色度分量的模式
	UInt  uiTrModeC     = uiTrMode;
	// 色度分量的尺寸
	UInt  uiLog2TrSizeC = uiLog2TrSize-1;

	// 对大小是4x4的TU进行特殊处理
	if( uiLog2TrSize == 2 )
	{
		uiLog2TrSizeC++;
		uiTrModeC    --;
		UInt  uiQPDiv = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth( 0 ) + uiTrModeC ) << 1 );
		bCodeChroma   = ( ( uiAbsPartIdx % uiQPDiv ) == 0 );
	}

	// 设置CBF(编码块标志)
	const UInt uiSetCbf = 1 << uiTrMode;
	// code full block
	// 单独一整块的代价
	Double dSingleCost = MAX_DOUBLE;
	// 单独一整块的比特数
	UInt uiSingleBits = 0;
	// 歹毒一整块的失真
	UInt uiSingleDist = 0;
	UInt uiAbsSumY = 0, uiAbsSumU = 0, uiAbsSumV = 0;
	// 最优的变换模式
	UInt uiBestTransformMode[3] = {0};

	m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );

	// 完整检查模式
	if( bCheckFull )
	{
		const UInt uiNumCoeffPerAbsPartIdxIncrement = pcCU->getSlice()->getSPS()->getMaxCUWidth() * pcCU->getSlice()->getSPS()->getMaxCUHeight() >> ( pcCU->getSlice()->getSPS()->getMaxCUDepth() << 1 );
		const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;

		// 取得Y、U、V三个部分的残差系数
		TCoeff *pcCoeffCurrY = m_ppcQTTempCoeffY [uiQTTempAccessLayer] +  uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx;
		TCoeff *pcCoeffCurrU = m_ppcQTTempCoeffCb[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);
		TCoeff *pcCoeffCurrV = m_ppcQTTempCoeffCr[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);
#if ADAPTIVE_QP_SELECTION    
		Int *pcArlCoeffCurrY = m_ppcQTTempArlCoeffY [uiQTTempAccessLayer] +  uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx;
		Int *pcArlCoeffCurrU = m_ppcQTTempArlCoeffCb[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);
		Int *pcArlCoeffCurrV = m_ppcQTTempArlCoeffCr[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);   
#endif

		Int trWidth = 0, trHeight = 0, trWidthC = 0, trHeightC = 0;
		UInt absTUPartIdxC = uiAbsPartIdx;

		// TU的宽度
		trWidth  = trHeight  = 1 << uiLog2TrSize;
		trWidthC = trHeightC = 1 <setTrIdxSubParts( uiDepth - pcCU->getDepth( 0 ), uiAbsPartIdx, uiDepth );

		// 三个分量的编码代价
		Double minCostY = MAX_DOUBLE;
		Double minCostU = MAX_DOUBLE;
		Double minCostV = MAX_DOUBLE;

		// 是否跳过Y、U、V
		Bool checkTransformSkipY  = pcCU->getSlice()->getPPS()->getUseTransformSkip() && trWidth == 4 && trHeight == 4;
		Bool checkTransformSkipUV = pcCU->getSlice()->getPPS()->getUseTransformSkip() && trWidthC == 4 && trHeightC == 4;

		checkTransformSkipY         &= (!pcCU->isLosslessCoded(0));
		checkTransformSkipUV        &= (!pcCU->isLosslessCoded(0));

		pcCU->setTransformSkipSubParts ( 0, TEXT_LUMA, uiAbsPartIdx, uiDepth ); 
		if( bCodeChroma )
		{
			pcCU->setTransformSkipSubParts ( 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 
			pcCU->setTransformSkipSubParts ( 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 
		}

		// 是否使用了率失真优化的量化
		if (m_pcEncCfg->getUseRDOQ())
		{
			// 估算比特数
			m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, trWidth, trHeight, TEXT_LUMA );        
		}

		m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_LUMA, pcCU->getSlice()->getSPS()->getQpBDOffsetY(), 0 );

#if RDOQ_CHROMA_LAMBDA 
		m_pcTrQuant->selectLambda(TEXT_LUMA);  
#endif
        // DCT变换和量化(Y分量),非常重要的函数
		m_pcTrQuant->transformNxN( pcCU, pcResi->getLumaAddr( absTUPartIdx ), pcResi->getStride (), pcCoeffCurrY, 
#if ADAPTIVE_QP_SELECTION
			pcArlCoeffCurrY, 
#endif      
			trWidth,   trHeight,    uiAbsSumY, TEXT_LUMA,     uiAbsPartIdx );

		pcCU->setCbfSubParts( uiAbsSumY ? uiSetCbf : 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );

		// 对色度部分信息编码
		if( bCodeChroma )
		{
			if (m_pcEncCfg->getUseRDOQ())
			{
				m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, trWidthC, trHeightC, TEXT_CHROMA );          
			}

			Int curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();
			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

#if RDOQ_CHROMA_LAMBDA 
			m_pcTrQuant->selectLambda(TEXT_CHROMA_U);
#endif
			// 变换和量化(U分量)
			m_pcTrQuant->transformNxN( pcCU, pcResi->getCbAddr(absTUPartIdxC), pcResi->getCStride(), pcCoeffCurrU, 
#if ADAPTIVE_QP_SELECTION
				pcArlCoeffCurrU, 
#endif        
				trWidthC, trHeightC, uiAbsSumU, TEXT_CHROMA_U, uiAbsPartIdx );

			curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();
			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

#if RDOQ_CHROMA_LAMBDA
			m_pcTrQuant->selectLambda(TEXT_CHROMA_V);
#endif
			// 变换和量化(V分量)
			m_pcTrQuant->transformNxN( pcCU, pcResi->getCrAddr(absTUPartIdxC), pcResi->getCStride(), pcCoeffCurrV,
#if ADAPTIVE_QP_SELECTION
				pcArlCoeffCurrV, 
#endif        
				trWidthC, trHeightC, uiAbsSumV, TEXT_CHROMA_V, uiAbsPartIdx );

			pcCU->setCbfSubParts( uiAbsSumU ? uiSetCbf : 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
			pcCU->setCbfSubParts( uiAbsSumV ? uiSetCbf : 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
		}

		m_pcEntropyCoder->resetBits();

        // 对CBF进行编码(Y分量)
		m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_LUMA,     uiTrMode );

        // 对残差系数进行编码(Y分量)
		m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrY, uiAbsPartIdx,  trWidth,  trHeight,    uiDepth, TEXT_LUMA );
		const UInt uiSingleBitsY = m_pcEntropyCoder->getNumberOfWrittenBits();

		UInt uiSingleBitsU = 0;
		UInt uiSingleBitsV = 0;

		// 对色度部分进行编码
		if( bCodeChroma )
		{
			m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
			m_pcEntropyCoder->resetBits();

			// 对CBF进行编码(U分量)
			m_pcEntropyCoder->encodeQtCbf   ( pcCU, uiAbsPartIdx, TEXT_CHROMA_U, uiTrMode );
			// 对系数进行编码(U分量)
			m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrU, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_U );
			uiSingleBitsU = m_pcEntropyCoder->getNumberOfWrittenBits();

			m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
			m_pcEntropyCoder->resetBits();

			// 对CBF进行编码(V分量)
			m_pcEntropyCoder->encodeQtCbf   ( pcCU, uiAbsPartIdx, TEXT_CHROMA_V, uiTrMode );
			// 对系数进行编码(V分量)
			m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrV, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_V );
			uiSingleBitsV = m_pcEntropyCoder->getNumberOfWrittenBits();
		}

		const UInt uiNumSamplesLuma = 1 << (uiLog2TrSize<<1);
		const UInt uiNumSamplesChro = 1 << (uiLog2TrSizeC<<1);

		::memset( m_pTempPel, 0, sizeof( Pel ) * uiNumSamplesLuma ); // not necessary needed for inside of recursion (only at the beginning)

		UInt uiDistY = m_pcRdCost->getDistPart(g_bitDepthY, m_pTempPel, trWidth, pcResi->getLumaAddr( absTUPartIdx ), pcResi->getStride(), trWidth, trHeight ); // initialized with zero residual destortion

		if ( puiZeroDist )
		{
			*puiZeroDist += uiDistY;
		}

		// 如果Y分量绝对系数和?(不是知道是不是这个意思,反正就是如果变换量化有效果就执行下面的步骤)大于0
		// 开始执行反量化、反变换
		if( uiAbsSumY )
		{
			Pel *pcResiCurrY = m_pcQTTempTComYuv[ uiQTTempAccessLayer ].getLumaAddr( absTUPartIdx );

			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_LUMA, pcCU->getSlice()->getSPS()->getQpBDOffsetY(), 0 );

			Int scalingListType = 3 + g_eTTable[(Int)TEXT_LUMA];
			assert(scalingListType < SCALING_LIST_NUM);
            // 反变换、反量化(Y分量)
			m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_LUMA,REG_DCT, pcResiCurrY, m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(),  pcCoeffCurrY, trWidth, trHeight, scalingListType );//this is for inter mode only

			const UInt uiNonzeroDistY = m_pcRdCost->getDistPart(g_bitDepthY, m_pcQTTempTComYuv[uiQTTempAccessLayer].getLumaAddr( absTUPartIdx ), m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(),
				pcResi->getLumaAddr( absTUPartIdx ), pcResi->getStride(), trWidth,trHeight );
			if (pcCU->isLosslessCoded(0)) 
			{
				uiDistY = uiNonzeroDistY;
			}
			else
			{
				const Double singleCostY = m_pcRdCost->calcRdCost( uiSingleBitsY, uiNonzeroDistY );
				m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
				m_pcEntropyCoder->resetBits();
				m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_LUMA,     uiTrMode );
				const UInt uiNullBitsY   = m_pcEntropyCoder->getNumberOfWrittenBits();
				const Double nullCostY   = m_pcRdCost->calcRdCost( uiNullBitsY, uiDistY );
				if( nullCostY < singleCostY )  
				{    
					uiAbsSumY = 0;
					::memset( pcCoeffCurrY, 0, sizeof( TCoeff ) * uiNumSamplesLuma );
					if( checkTransformSkipY )
					{
						minCostY = nullCostY;
					}
				}
				else
				{
					uiDistY = uiNonzeroDistY;
					if( checkTransformSkipY )
					{
						minCostY = singleCostY;
					}
				}
			}
		}
		// 否则(没有进行变换量化或者变换量化了没有效果?),如果是跳过Y分量
		else if( checkTransformSkipY )
		{
			m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
			m_pcEntropyCoder->resetBits();
			// 编码Y分量的CBF的0系数
			m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_LUMA, uiTrMode );
			const UInt uiNullBitsY = m_pcEntropyCoder->getNumberOfWrittenBits();
			// 计算率失真
			minCostY = m_pcRdCost->calcRdCost( uiNullBitsY, uiDistY );
		}

		if( !uiAbsSumY )
		{
			Pel *pcPtr =  m_pcQTTempTComYuv[uiQTTempAccessLayer].getLumaAddr( absTUPartIdx );
			const UInt uiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride();
			for( UInt uiY = 0; uiY < trHeight; ++uiY )
			{
				::memset( pcPtr, 0, sizeof( Pel ) * trWidth );
				pcPtr += uiStride;
			} 
		}

		UInt uiDistU = 0;
		UInt uiDistV = 0;

		// 如果对色度部分进行了变换量化,那么需要对色度部分进行反变换反量化
		if( bCodeChroma )
		{
			uiDistU = m_pcRdCost->getDistPart(g_bitDepthC, m_pTempPel, trWidthC, pcResi->getCbAddr( absTUPartIdxC ), pcResi->getCStride(), trWidthC, trHeightC
				, TEXT_CHROMA_U
				); // initialized with zero residual destortion
			if ( puiZeroDist )
			{
				*puiZeroDist += uiDistU;
			}

			// 如果对U分量进行了变换量化
			if( uiAbsSumU )
			{
				Pel *pcResiCurrU = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCbAddr( absTUPartIdxC );

				Int curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();
				m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

				Int scalingListType = 3 + g_eTTable[(Int)TEXT_CHROMA_U];
				assert(scalingListType < SCALING_LIST_NUM);

				// 反变换、反量化(U分量)
				m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_CHROMA,REG_DCT, pcResiCurrU, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(), pcCoeffCurrU, trWidthC, trHeightC, scalingListType  );

				const UInt uiNonzeroDistU = m_pcRdCost->getDistPart(g_bitDepthC, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCbAddr( absTUPartIdxC), m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(),
					pcResi->getCbAddr( absTUPartIdxC), pcResi->getCStride(), trWidthC, trHeightC
					, TEXT_CHROMA_U
					);

				if(pcCU->isLosslessCoded(0))  
				{
					uiDistU = uiNonzeroDistU;
				}
				else
				{
					const Double dSingleCostU = m_pcRdCost->calcRdCost( uiSingleBitsU, uiNonzeroDistU );
					m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
					m_pcEntropyCoder->resetBits();
					m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_CHROMA_U,     uiTrMode );
					const UInt uiNullBitsU    = m_pcEntropyCoder->getNumberOfWrittenBits();
					const Double dNullCostU   = m_pcRdCost->calcRdCost( uiNullBitsU, uiDistU );
					if( dNullCostU < dSingleCostU )
					{
						uiAbsSumU = 0;
						::memset( pcCoeffCurrU, 0, sizeof( TCoeff ) * uiNumSamplesChro );
						if( checkTransformSkipUV )
						{
							minCostU = dNullCostU;
						}
					}
					else
					{
						uiDistU = uiNonzeroDistU;
						if( checkTransformSkipUV )
						{
							minCostU = dSingleCostU;
						}
					}
				}
			}
			// 否则(即变换量化没有效果或者不够优?)
			else if( checkTransformSkipUV )
			{
				m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
				m_pcEntropyCoder->resetBits();
				// 编码CBF的0系数
				m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_CHROMA_U, uiTrMode );
				const UInt uiNullBitsU = m_pcEntropyCoder->getNumberOfWrittenBits();
				minCostU = m_pcRdCost->calcRdCost( uiNullBitsU, uiDistU );
			}
			if( !uiAbsSumU )
			{
				Pel *pcPtr =  m_pcQTTempTComYuv[uiQTTempAccessLayer].getCbAddr( absTUPartIdxC );
				const UInt uiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride();
				for( UInt uiY = 0; uiY < trHeightC; ++uiY )
				{
					::memset( pcPtr, 0, sizeof(Pel) * trWidthC );
					pcPtr += uiStride;
				}
			}

			uiDistV = m_pcRdCost->getDistPart(g_bitDepthC, m_pTempPel, trWidthC, pcResi->getCrAddr( absTUPartIdxC), pcResi->getCStride(), trWidthC, trHeightC
				, TEXT_CHROMA_V
				); // initialized with zero residual destortion
			if ( puiZeroDist )
			{
				*puiZeroDist += uiDistV;
			}

			// 对V分量进行处理(过程同U分量)
			if( uiAbsSumV )
			{
				Pel *pcResiCurrV = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCrAddr( absTUPartIdxC );
				Int curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();
				m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

				Int scalingListType = 3 + g_eTTable[(Int)TEXT_CHROMA_V];
				assert(scalingListType < SCALING_LIST_NUM);

				// 反变换反量化(V分量)
				m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_CHROMA,REG_DCT, pcResiCurrV, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(), pcCoeffCurrV, trWidthC, trHeightC, scalingListType );

				const UInt uiNonzeroDistV = m_pcRdCost->getDistPart(g_bitDepthC, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCrAddr( absTUPartIdxC ), m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(),
					pcResi->getCrAddr( absTUPartIdxC ), pcResi->getCStride(), trWidthC, trHeightC
					, TEXT_CHROMA_V
					);
				if (pcCU->isLosslessCoded(0)) 
				{
					uiDistV = uiNonzeroDistV;
				}
				else
				{
					const Double dSingleCostV = m_pcRdCost->calcRdCost( uiSingleBitsV, uiNonzeroDistV );
					m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
					m_pcEntropyCoder->resetBits();
					// 对CBF的0系数进行编码
					m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_CHROMA_V,     uiTrMode );
					const UInt uiNullBitsV    = m_pcEntropyCoder->getNumberOfWrittenBits();
					const Double dNullCostV   = m_pcRdCost->calcRdCost( uiNullBitsV, uiDistV );
					if( dNullCostV < dSingleCostV )
					{
						uiAbsSumV = 0;
						::memset( pcCoeffCurrV, 0, sizeof( TCoeff ) * uiNumSamplesChro );
						if( checkTransformSkipUV )
						{
							minCostV = dNullCostV;
						}
					}
					else
					{
						uiDistV = uiNonzeroDistV;
						if( checkTransformSkipUV )
						{
							minCostV = dSingleCostV;
						}
					}
				}
			}
			// 如果跳过了UV分量
			else if( checkTransformSkipUV )
			{
				m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
				m_pcEntropyCoder->resetBits();
				// 对CBF的0系数进行编码
				m_pcEntropyCoder->encodeQtCbfZero( pcCU, TEXT_CHROMA_V, uiTrMode );
				const UInt uiNullBitsV = m_pcEntropyCoder->getNumberOfWrittenBits();
				// 计算率失真代价
				minCostV = m_pcRdCost->calcRdCost( uiNullBitsV, uiDistV );
			}
			if( !uiAbsSumV )
			{
				Pel *pcPtr =  m_pcQTTempTComYuv[uiQTTempAccessLayer].getCrAddr( absTUPartIdxC );
				const UInt uiStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride();
				for( UInt uiY = 0; uiY < trHeightC; ++uiY )
				{   
					::memset( pcPtr, 0, sizeof(Pel) * trWidthC );
					pcPtr += uiStride;
				}
			}
		}
		pcCU->setCbfSubParts( uiAbsSumY ? uiSetCbf : 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );
		if( bCodeChroma )
		{
			pcCU->setCbfSubParts( uiAbsSumU ? uiSetCbf : 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
			pcCU->setCbfSubParts( uiAbsSumV ? uiSetCbf : 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
		}

		// 如果跳过了Y分量
		if( checkTransformSkipY )
		{
			UInt uiNonzeroDistY, uiAbsSumTransformSkipY;
			Double dSingleCostY;

			Pel *pcResiCurrY = m_pcQTTempTComYuv[ uiQTTempAccessLayer ].getLumaAddr( absTUPartIdx );
			UInt resiYStride = m_pcQTTempTComYuv[ uiQTTempAccessLayer ].getStride();

			TCoeff bestCoeffY[32*32];
			memcpy( bestCoeffY, pcCoeffCurrY, sizeof(TCoeff) * uiNumSamplesLuma );

#if ADAPTIVE_QP_SELECTION
			TCoeff bestArlCoeffY[32*32];
			memcpy( bestArlCoeffY, pcArlCoeffCurrY, sizeof(TCoeff) * uiNumSamplesLuma );
#endif

			Pel bestResiY[32*32];
			for ( Int i = 0; i < trHeight; ++i )
			{
				memcpy( &bestResiY[i*trWidth], pcResiCurrY+i*resiYStride, sizeof(Pel) * trWidth );
			}

			m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );

			pcCU->setTransformSkipSubParts ( 1, TEXT_LUMA, uiAbsPartIdx, uiDepth );

			if (m_pcEncCfg->getUseRDOQTS())
			{
				// 估算比特数
				m_pcEntropyCoder->estimateBit( m_pcTrQuant->m_pcEstBitsSbac, trWidth, trHeight, TEXT_LUMA );        
			}

			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_LUMA, pcCU->getSlice()->getSPS()->getQpBDOffsetY(), 0 );

#if RDOQ_CHROMA_LAMBDA 
			m_pcTrQuant->selectLambda(TEXT_LUMA);
#endif
			// 变换和量化
			m_pcTrQuant->transformNxN( pcCU, pcResi->getLumaAddr( absTUPartIdx ), pcResi->getStride (), pcCoeffCurrY, 
#if ADAPTIVE_QP_SELECTION
				pcArlCoeffCurrY, 
#endif      
				trWidth,   trHeight,    uiAbsSumTransformSkipY, TEXT_LUMA, uiAbsPartIdx, true );
			pcCU->setCbfSubParts( uiAbsSumTransformSkipY ? uiSetCbf : 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );

			if( uiAbsSumTransformSkipY != 0 )
			{
				m_pcEntropyCoder->resetBits();
				// 对CBF的0系数进行编码
				m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_LUMA, uiTrMode );
				// 对残差系数进行编码
				m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrY, uiAbsPartIdx, trWidth, trHeight, uiDepth, TEXT_LUMA );
				const UInt uiTsSingleBitsY = m_pcEntropyCoder->getNumberOfWrittenBits();

				m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_LUMA, pcCU->getSlice()->getSPS()->getQpBDOffsetY(), 0 );

				Int scalingListType = 3 + g_eTTable[(Int)TEXT_LUMA];
				assert(scalingListType < SCALING_LIST_NUM);

				// 反变换、反量化
				m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_LUMA,REG_DCT, pcResiCurrY, m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(),  pcCoeffCurrY, trWidth, trHeight, scalingListType, true );

				uiNonzeroDistY = m_pcRdCost->getDistPart(g_bitDepthY, m_pcQTTempTComYuv[uiQTTempAccessLayer].getLumaAddr( absTUPartIdx ), m_pcQTTempTComYuv[uiQTTempAccessLayer].getStride(),
					pcResi->getLumaAddr( absTUPartIdx ), pcResi->getStride(), trWidth, trHeight );

				// 计算率失真
				dSingleCostY = m_pcRdCost->calcRdCost( uiTsSingleBitsY, uiNonzeroDistY );
			}

			if( !uiAbsSumTransformSkipY || minCostY < dSingleCostY )
			{
				pcCU->setTransformSkipSubParts ( 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );
				memcpy( pcCoeffCurrY, bestCoeffY, sizeof(TCoeff) * uiNumSamplesLuma );
#if ADAPTIVE_QP_SELECTION
				memcpy( pcArlCoeffCurrY, bestArlCoeffY, sizeof(TCoeff) * uiNumSamplesLuma );
#endif
				for( Int i = 0; i < trHeight; ++i )
				{
					memcpy( pcResiCurrY+i*resiYStride, &bestResiY[i*trWidth], sizeof(Pel) * trWidth );
				}
			}
			else
			{
				uiDistY = uiNonzeroDistY;
				uiAbsSumY = uiAbsSumTransformSkipY;
				uiBestTransformMode[0] = 1;
			}

			pcCU->setCbfSubParts( uiAbsSumY ? uiSetCbf : 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );
		}

		// 如果对色度部分进行编码,但是跳过了UV分量(这是什么情况?)
		if( bCodeChroma && checkTransformSkipUV  )
		{
			UInt uiNonzeroDistU, uiNonzeroDistV, uiAbsSumTransformSkipU, uiAbsSumTransformSkipV;
			Double dSingleCostU, dSingleCostV;

			Pel *pcResiCurrU = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCbAddr( absTUPartIdxC );
			Pel *pcResiCurrV = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCrAddr( absTUPartIdxC );
			UInt resiCStride = m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride();

			TCoeff bestCoeffU[32*32], bestCoeffV[32*32];
			memcpy( bestCoeffU, pcCoeffCurrU, sizeof(TCoeff) * uiNumSamplesChro );
			memcpy( bestCoeffV, pcCoeffCurrV, sizeof(TCoeff) * uiNumSamplesChro );

#if ADAPTIVE_QP_SELECTION
			TCoeff bestArlCoeffU[32*32], bestArlCoeffV[32*32];
			memcpy( bestArlCoeffU, pcArlCoeffCurrU, sizeof(TCoeff) * uiNumSamplesChro );
			memcpy( bestArlCoeffV, pcArlCoeffCurrV, sizeof(TCoeff) * uiNumSamplesChro );
#endif

			Pel bestResiU[32*32], bestResiV[32*32];
			for (Int i = 0; i < trHeightC; ++i )
			{
				memcpy( &bestResiU[i*trWidthC], pcResiCurrU+i*resiCStride, sizeof(Pel) * trWidthC );
				memcpy( &bestResiV[i*trWidthC], pcResiCurrV+i*resiCStride, sizeof(Pel) * trWidthC );
			}

			m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );

			pcCU->setTransformSkipSubParts ( 1, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 
			pcCU->setTransformSkipSubParts ( 1, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );

			if (m_pcEncCfg->getUseRDOQTS())
			{
				// 比特数估算
				m_pcEntropyCoder->estimateBit(m_pcTrQuant->m_pcEstBitsSbac, trWidthC, trHeightC, TEXT_CHROMA );          
			}

			Int curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();
			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

#if RDOQ_CHROMA_LAMBDA 
			m_pcTrQuant->selectLambda(TEXT_CHROMA_U);
#endif
			// 变换量化(U分量)
			m_pcTrQuant->transformNxN( pcCU, pcResi->getCbAddr(absTUPartIdxC), pcResi->getCStride(), pcCoeffCurrU, 
#if ADAPTIVE_QP_SELECTION
				pcArlCoeffCurrU, 
#endif        
				trWidthC, trHeightC, uiAbsSumTransformSkipU, TEXT_CHROMA_U, uiAbsPartIdx, true );
			curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();
			m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );
#if RDOQ_CHROMA_LAMBDA
			m_pcTrQuant->selectLambda(TEXT_CHROMA_V);
#endif
			// 变换量化(V分量)
			m_pcTrQuant->transformNxN( pcCU, pcResi->getCrAddr(absTUPartIdxC), pcResi->getCStride(), pcCoeffCurrV,
#if ADAPTIVE_QP_SELECTION
				pcArlCoeffCurrV, 
#endif        
				trWidthC, trHeightC, uiAbsSumTransformSkipV, TEXT_CHROMA_V, uiAbsPartIdx, true );

			pcCU->setCbfSubParts( uiAbsSumTransformSkipU ? uiSetCbf : 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
			pcCU->setCbfSubParts( uiAbsSumTransformSkipV ? uiSetCbf : 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );

			uiSingleBitsU = 0;
			uiSingleBitsV = 0;

			// 如果跳过了U分量
			if( uiAbsSumTransformSkipU )
			{
				m_pcEntropyCoder->resetBits();
				// 对系数进行编码
				m_pcEntropyCoder->encodeQtCbf   ( pcCU, uiAbsPartIdx, TEXT_CHROMA_U, uiTrMode );
				m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrU, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_U );
				uiSingleBitsU = m_pcEntropyCoder->getNumberOfWrittenBits();    

				curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();
				m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

				Int scalingListType = 3 + g_eTTable[(Int)TEXT_CHROMA_U];
				assert(scalingListType < SCALING_LIST_NUM);

				// 反变换反量化
				m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_CHROMA,REG_DCT, pcResiCurrU, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(), pcCoeffCurrU, trWidthC, trHeightC, scalingListType, true  );

				uiNonzeroDistU = m_pcRdCost->getDistPart(g_bitDepthC, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCbAddr( absTUPartIdxC), m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(),
					pcResi->getCbAddr( absTUPartIdxC), pcResi->getCStride(), trWidthC, trHeightC
					, TEXT_CHROMA_U
					);

				dSingleCostU = m_pcRdCost->calcRdCost( uiSingleBitsU, uiNonzeroDistU );
			}

			if( !uiAbsSumTransformSkipU || minCostU < dSingleCostU )
			{
				pcCU->setTransformSkipSubParts ( 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 

				memcpy( pcCoeffCurrU, bestCoeffU, sizeof (TCoeff) * uiNumSamplesChro );
#if ADAPTIVE_QP_SELECTION
				memcpy( pcArlCoeffCurrU, bestArlCoeffU, sizeof (TCoeff) * uiNumSamplesChro );
#endif
				for( Int i = 0; i < trHeightC; ++i )
				{
					memcpy( pcResiCurrU+i*resiCStride, &bestResiU[i*trWidthC], sizeof(Pel) * trWidthC );
				}
			}
			else
			{
				uiDistU = uiNonzeroDistU;
				uiAbsSumU = uiAbsSumTransformSkipU;
				uiBestTransformMode[1] = 1;
			}

			// 如果跳过了V分量
			if( uiAbsSumTransformSkipV )
			{
				m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
				m_pcEntropyCoder->resetBits();
				// 对系数进行编码
				m_pcEntropyCoder->encodeQtCbf   ( pcCU, uiAbsPartIdx, TEXT_CHROMA_V, uiTrMode );
				m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrV, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_V );
				uiSingleBitsV = m_pcEntropyCoder->getNumberOfWrittenBits();

				curChromaQpOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();
				m_pcTrQuant->setQPforQuant( pcCU->getQP( 0 ), TEXT_CHROMA, pcCU->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset );

				Int scalingListType = 3 + g_eTTable[(Int)TEXT_CHROMA_V];
				assert(scalingListType < SCALING_LIST_NUM);

				// 反变换反量化
				m_pcTrQuant->invtransformNxN( pcCU->getCUTransquantBypass(uiAbsPartIdx), TEXT_CHROMA,REG_DCT, pcResiCurrV, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(), pcCoeffCurrV, trWidthC, trHeightC, scalingListType, true );

				uiNonzeroDistV = m_pcRdCost->getDistPart(g_bitDepthC, m_pcQTTempTComYuv[uiQTTempAccessLayer].getCrAddr( absTUPartIdxC ), m_pcQTTempTComYuv[uiQTTempAccessLayer].getCStride(),
					pcResi->getCrAddr( absTUPartIdxC ), pcResi->getCStride(), trWidthC, trHeightC
					, TEXT_CHROMA_V
					);

				dSingleCostV = m_pcRdCost->calcRdCost( uiSingleBitsV, uiNonzeroDistV );
			}

			if( !uiAbsSumTransformSkipV || minCostV < dSingleCostV )
			{
				pcCU->setTransformSkipSubParts ( 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 

				memcpy( pcCoeffCurrV, bestCoeffV, sizeof(TCoeff) * uiNumSamplesChro );
#if ADAPTIVE_QP_SELECTION
				memcpy( pcArlCoeffCurrV, bestArlCoeffV, sizeof(TCoeff) * uiNumSamplesChro );
#endif
				for( Int i = 0; i < trHeightC; ++i )
				{
					memcpy( pcResiCurrV+i*resiCStride, &bestResiV[i*trWidthC], sizeof(Pel) * trWidthC );
				}
			}
			else
			{
				uiDistV = uiNonzeroDistV;
				uiAbsSumV = uiAbsSumTransformSkipV;
				uiBestTransformMode[2] = 1;
			}

			pcCU->setCbfSubParts( uiAbsSumU ? uiSetCbf : 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
			pcCU->setCbfSubParts( uiAbsSumV ? uiSetCbf : 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
		}

		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
		m_pcEntropyCoder->resetBits();

		if( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) )
		{
			// 编码分割标志?
			m_pcEntropyCoder->encodeTransformSubpFlag( 0, 5 - uiLog2TrSize );
		}

		// 前面的是为了选出最优模式,下面对系数进行编码

		// 对色度部分CBF进行编码
		if( bCodeChroma )
		{
			m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_CHROMA_U, uiTrMode );
			m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_CHROMA_V, uiTrMode );
		}

		// 对亮度的CBF进行编码
		m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_LUMA,     uiTrMode );

		// 编码亮度部分的系数
		m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrY, uiAbsPartIdx, trWidth, trHeight,    uiDepth, TEXT_LUMA );

		// 对色度部分的系数进行编码
		if( bCodeChroma )
		{
			m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrU, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_U );
			m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrV, uiAbsPartIdx, trWidthC, trHeightC, uiDepth, TEXT_CHROMA_V );
		}

		uiSingleBits = m_pcEntropyCoder->getNumberOfWrittenBits();

		uiSingleDist = uiDistY + uiDistU + uiDistV;
		// 计算率失真代价
		dSingleCost = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDist );
	}  

	// code sub-blocks
	// 对TU的四个子TU进行计算(使用递归的方式)
	if( bCheckSplit )
	{
		if( bCheckFull )
		{
			m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] );
			m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
		}
		UInt uiSubpDist = 0;
		UInt uiSubpBits = 0;
		Double dSubpCost = 0.0;

		const UInt uiQPartNumSubp = pcCU->getPic()->getNumPartInCU() >> ((uiDepth + 1 ) << 1);
		for( UInt ui = 0; ui < 4; ++ui )
		{
			UInt nsAddr = uiAbsPartIdx + ui * uiQPartNumSubp;
			// 递归调用
			xEstimateResidualQT( pcCU, ui, uiAbsPartIdx + ui * uiQPartNumSubp, nsAddr, pcResi, uiDepth + 1, dSubpCost, uiSubpBits, uiSubpDist, bCheckFull ? NULL : puiZeroDist );
		}

		UInt uiYCbf = 0;
		UInt uiUCbf = 0;
		UInt uiVCbf = 0;
		for( UInt ui = 0; ui < 4; ++ui )
		{
			uiYCbf |= pcCU->getCbf( uiAbsPartIdx + ui * uiQPartNumSubp, TEXT_LUMA,     uiTrMode + 1 );
			uiUCbf |= pcCU->getCbf( uiAbsPartIdx + ui * uiQPartNumSubp, TEXT_CHROMA_U, uiTrMode + 1 );
			uiVCbf |= pcCU->getCbf( uiAbsPartIdx + ui * uiQPartNumSubp, TEXT_CHROMA_V, uiTrMode + 1 );
		}
		for( UInt ui = 0; ui < 4 * uiQPartNumSubp; ++ui )
		{
			pcCU->getCbf( TEXT_LUMA     )[uiAbsPartIdx + ui] |= uiYCbf << uiTrMode;
			pcCU->getCbf( TEXT_CHROMA_U )[uiAbsPartIdx + ui] |= uiUCbf << uiTrMode;
			pcCU->getCbf( TEXT_CHROMA_V )[uiAbsPartIdx + ui] |= uiVCbf << uiTrMode;
		}

		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_ROOT ] );
		m_pcEntropyCoder->resetBits();

		// 对残差四叉树进行编码(目前不知道这样调用的目的是什么)
		xEncodeResidualQT( pcCU, uiAbsPartIdx, uiDepth, true,  TEXT_LUMA );
		xEncodeResidualQT( pcCU, uiAbsPartIdx, uiDepth, false, TEXT_LUMA );
		xEncodeResidualQT( pcCU, uiAbsPartIdx, uiDepth, false, TEXT_CHROMA_U );
		xEncodeResidualQT( pcCU, uiAbsPartIdx, uiDepth, false, TEXT_CHROMA_V );

		uiSubpBits = m_pcEntropyCoder->getNumberOfWrittenBits();

		// 计算率失真代价
		dSubpCost  = m_pcRdCost->calcRdCost( uiSubpBits, uiSubpDist );

		if( uiYCbf || uiUCbf || uiVCbf || !bCheckFull )
		{
			if( dSubpCost < dSingleCost )
			{
				rdCost += dSubpCost;
				ruiBits += uiSubpBits;
				ruiDist += uiSubpDist;
				return;
			}
		}
		pcCU->setTransformSkipSubParts ( uiBestTransformMode[0], TEXT_LUMA, uiAbsPartIdx, uiDepth ); 
		if(bCodeChroma)
		{
			pcCU->setTransformSkipSubParts ( uiBestTransformMode[1], TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 
			pcCU->setTransformSkipSubParts ( uiBestTransformMode[2], TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC ); 
		}
		assert( bCheckFull );

		m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiDepth ][ CI_QT_TRAFO_TEST ] );
	}
	rdCost += dSingleCost;
	ruiBits += uiSingleBits;
	ruiDist += uiSingleDist;

	pcCU->setTrIdxSubParts( uiTrMode, uiAbsPartIdx, uiDepth );

	pcCU->setCbfSubParts( uiAbsSumY ? uiSetCbf : 0, TEXT_LUMA, uiAbsPartIdx, uiDepth );
	if( bCodeChroma )
	{
		pcCU->setCbfSubParts( uiAbsSumU ? uiSetCbf : 0, TEXT_CHROMA_U, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
		pcCU->setCbfSubParts( uiAbsSumV ? uiSetCbf : 0, TEXT_CHROMA_V, uiAbsPartIdx, pcCU->getDepth(0)+uiTrModeC );
	}
}
对残差四叉树进行编码:

 

 

Void TEncSearch::xEncodeResidualQT( TComDataCU* pcCU, UInt uiAbsPartIdx, const UInt uiDepth, Bool bSubpAndCbf, TextType eType )
{
	assert( pcCU->getDepth( 0 ) == pcCU->getDepth( uiAbsPartIdx ) );

	// 模式
	const UInt uiCurrTrMode = uiDepth - pcCU->getDepth( 0 );
	const UInt uiTrMode = pcCU->getTransformIdx( uiAbsPartIdx );

	// 对当前TU是否会继续向下分割
	const Bool bSubp = uiCurrTrMode != uiTrMode;

	const UInt uiLog2TrSize = g_aucConvertToBit[pcCU->getSlice()->getSPS()->getMaxCUWidth() >> uiDepth]+2;

	if( bSubpAndCbf && uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() && uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) )
	{
		// 编码向下分割的标志
		m_pcEntropyCoder->encodeTransformSubpFlag( bSubp, 5 - uiLog2TrSize );
	}

	assert( pcCU->getPredictionMode(uiAbsPartIdx) != MODE_INTRA );

	// 
	if( bSubpAndCbf )
	{
		const Bool bFirstCbfOfCU = uiCurrTrMode == 0;
		// 编码UV分量的CBF(Y分量已经在调用这个函数之前处理完了)
		if( bFirstCbfOfCU || uiLog2TrSize > 2 )
		{
			if( bFirstCbfOfCU || pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_U, uiCurrTrMode - 1 ) )
			{
				m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_CHROMA_U, uiCurrTrMode );
			}
			if( bFirstCbfOfCU || pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_V, uiCurrTrMode - 1 ) )
			{
				m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_CHROMA_V, uiCurrTrMode );
			}
		}
		else if( uiLog2TrSize == 2 )
		{
			assert( pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_U, uiCurrTrMode ) == pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_U, uiCurrTrMode - 1 ) );
			assert( pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_V, uiCurrTrMode ) == pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_V, uiCurrTrMode - 1 ) );
		}
	}

	// 如果不在继续向下分割,那么直接编码YUV三个分量的系数,否则需要对子TU递归调用
	if( !bSubp )
	{
		const UInt uiNumCoeffPerAbsPartIdxIncrement = pcCU->getSlice()->getSPS()->getMaxCUWidth() * pcCU->getSlice()->getSPS()->getMaxCUHeight() >> ( pcCU->getSlice()->getSPS()->getMaxCUDepth() << 1 );
		//assert( 16 == uiNumCoeffPerAbsPartIdxIncrement ); // check
		const UInt uiQTTempAccessLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;
		TCoeff *pcCoeffCurrY = m_ppcQTTempCoeffY [uiQTTempAccessLayer] +  uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx;
		TCoeff *pcCoeffCurrU = m_ppcQTTempCoeffCb[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);
		TCoeff *pcCoeffCurrV = m_ppcQTTempCoeffCr[uiQTTempAccessLayer] + (uiNumCoeffPerAbsPartIdxIncrement * uiAbsPartIdx>>2);

		Bool  bCodeChroma   = true;
		UInt  uiTrModeC     = uiTrMode;
		UInt  uiLog2TrSizeC = uiLog2TrSize-1;
		if( uiLog2TrSize == 2 )
		{
			uiLog2TrSizeC++;
			uiTrModeC    --;
			UInt  uiQPDiv = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth( 0 ) + uiTrModeC ) << 1 );
			bCodeChroma   = ( ( uiAbsPartIdx % uiQPDiv ) == 0 );
		}

		if( bSubpAndCbf )
		{
			m_pcEntropyCoder->encodeQtCbf( pcCU, uiAbsPartIdx, TEXT_LUMA,     uiTrMode );
		}
		else
		{
			if( eType == TEXT_LUMA     && pcCU->getCbf( uiAbsPartIdx, TEXT_LUMA,     uiTrMode ) )
			{
				Int trWidth  = 1 << uiLog2TrSize;
				Int trHeight = 1 << uiLog2TrSize;
				// 对Y分量的系数进行编码
				m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrY, uiAbsPartIdx, trWidth, trHeight,    uiDepth, TEXT_LUMA );
			}
			if( bCodeChroma )
			{
				Int trWidth  = 1 << uiLog2TrSizeC;
				Int trHeight = 1 << uiLog2TrSizeC;
				// 对U分量的系数进行编码
				if( eType == TEXT_CHROMA_U && pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_U, uiTrMode ) )
				{
					m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrU, uiAbsPartIdx, trWidth, trHeight, uiDepth, TEXT_CHROMA_U );
				}
				// 对V分量的系数进行编码
				if( eType == TEXT_CHROMA_V && pcCU->getCbf( uiAbsPartIdx, TEXT_CHROMA_V, uiTrMode ) )
				{
					m_pcEntropyCoder->encodeCoeffNxN( pcCU, pcCoeffCurrV, uiAbsPartIdx, trWidth, trHeight, uiDepth, TEXT_CHROMA_V );
				}
			}
		}
	}
	else
	{
		if( bSubpAndCbf || pcCU->getCbf( uiAbsPartIdx, eType, uiCurrTrMode ) )
		{
			const UInt uiQPartNumSubp = pcCU->getPic()->getNumPartInCU() >> ((uiDepth + 1 ) << 1);
			// 对子TU递归调用该函数
			for( UInt ui = 0; ui < 4; ++ui )
			{
				xEncodeResidualQT( pcCU, uiAbsPartIdx + ui * uiQPartNumSubp, uiDepth + 1, bSubpAndCbf, eType );
			}
		}
	}
}


点击复制链接 与好友分享!回本站首页
相关TAG标签 编码器 代码
上一篇:LUA脚本语言
下一篇:快速掌握Lua 5.3 —— 编写提供给Lua使用的C库函数的技巧 (2)
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站