HM调用函数的简要过程1

CompressGOP->CompressSlice->EncodeSlice

Void TEncGOP::compressGOP( Int iPOCLast, Int iNumPicRcvd, TComList<TComPic*>& rcListPic,
                           TComList<TComPicYuv*>& rcListPicYuvRecOut, std::list<AccessUnit>& accessUnitsInGOP,
                           Bool isField, Bool isTff, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE )
{
.
.
.
 for(UInt nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; )
      {
        m_pcSliceEncoder->precompressSlice( pcPic );
        m_pcSliceEncoder->compressSlice   ( pcPic, false, false);
.		
.
.
}

Void TEncSlice::compressSlice( TComPic* pcPic, const Bool bCompressEntireSlice, const Bool bFastDeltaQP )//每个slice都会调用compressslice来对其进行预测变换量化选出最优参数
{
.
.
.
}

Void TEncSlice::encodeSlice   ( TComPic* pcPic, TComOutputBitstream* pcSubstreams, UInt &numBinsCoded )//slice通过最后调用encodeslice对其进行熵编码
{
.
.
.
}

CompressSlice->CompressCtu->xCompressCU->xCheckRDCostInter->predInterSearch->xMotionEstimation->xPatternSearch

Void TEncSlice::compressSlice( TComPic* pcPic, const Bool bCompressEntireSlice, const Bool bFastDeltaQP )//每个slice都会调用compressslice来对其进行预测变换量化选出最优参数
{
.
.
.
 // run CTU trial encoder
    m_pcCuEncoder->compressCtu( pCtu );//就是一个CTU的编码,包括CU的划分,PU模式的决定,TU的划分
.
.
.
}

Void TEncCu::compressCtu(TComDataCU* pCtu)
{
.
.
.

		//这里进入xCompressCU函数,这里的第三个参数是 CU的分割深度。64x64的深度为0,以此类推,最小的CU为8x8深度为3。
		//把一个slice内部的图像划分为K个LCU,同时这K个LCU是以raster的顺序来进行扫描的。LCU的尺寸默认为64x64,可以通过配置文件中的MaxCUWidth,MaxCUHeight来进行设置。
		//而每个LCU会调用如下的compressCU函数去决定编码的参数。 而LCU是采用四叉树的表示结构,每个LCU会被递归的划分为4个子CU,
		//并根据RD代价来确定是否进行划分,而每个LCU相当于树的第1层,所以他会调用xCompressCU。且在xCompressCU中会对每个子CU递归的调用xCompressCU,
		//然而在每次xCompressCU时,会对当前CU进行intra模式的测试,如果是B或Pslice,还对其进行merge和inter模式的测试。下面分别介绍intra,inter和merge相关的代码
	
	xCompressCU(m_ppcBestCU[0], m_ppcTempCU[0], 0 DEBUG_STRING_PASS_INTO(sDebug))
.
.
.
}

Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth )
#endif//总结,其实xCompressCU的作用就是从LCU开始深度遍历,计算每一个depth上最优的模式,再综合比较各个depth上最优的模式,选出最优的模式
{
.
.
.
//*****************************************帧间模式选择***************************//

// do inter modes, SKIP and 2Nx2N // do inter modes, SKIP and 2Nx2N  
	  /*
	  ** 在处理所有的其他模式之前,先处理帧间skip和2Nx2N的模式
	  ** 特别是对于2Nx2N的划分,要分两次处理:
	  ** 1、尝试merge模式——xCheckRDCostMerge2Nx2N
	  ** 2、尝试普通的帧间预测(即AMVP)——xCheckRDCostInter
	  */
        if(m_pcEncCfg->getUseEarlySkipDetection())//使用earlyDetectionSkipMode优化算法

         //  更新为Merge模式的代价
        xCheckRDCostMerge2Nx2N( rpcBestCU, rpcTempCU DEBUG_STRING_PASS_INTO(sDebug), &earlyDetectionSkipMode );//by Merge for inter_2Nx2N
       
        if(!m_pcEncCfg->getUseEarlySkipDetection())//不使用earlyDetectionSkipMode优化算法

// do inter modes, NxN, 2NxN, and Nx2N  
		/*
		** 普通的帧间预测(普通的帧间预测就是AMVP)开始:
		** 注意:这里不再处理merge模式和普通帧间的2Nx2N划分模式,
		** 这是因为前面已经处理过2Nx2N的划分模式了,merge模式只对于2Nx2N的划分才有效
		** 因此下面的处理是没有merge模式和2Nx2N的划分模式的
		*/
        if( rpcBestCU->getSlice()->getSliceType() != I_SLICE )//非I帧
        {
          //  NxN 划分为4个PU

          if(!( (rpcBestCU->getWidth(0)==8) && (rpcBestCU->getHeight(0)==8) ))//块尺寸不能为8x8
          {
            if( uiDepth == sps.getLog2DiffMaxMinCodingBlockSize() && doNotBlockPu)
            {
				//计算NxN模式代价并比较
              xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug)   );
              rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
            }
          }

            //计算Nx2N

            if(doNotBlockPu)
               {
		      	  //计算Nx2N代价并比较 划分为2个PU
                  xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_Nx2N 
                     DEBUG_STRING_PASS_INTO(sDebug)  );
                  rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                 if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == 
                      SIZE_Nx2N )
                  {
                    doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                 }
                 }

		  //计算2NxN代价并比较
		  if(doNotBlockPu)
          { 
            xCheckRDCostInter      ( rpcBestCU, rpcTempCU, SIZE_2NxN DEBUG_STRING_PASS_INTO(sDebug)  );
            rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
            if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxN)
            {
              doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
            }
          }

		  //尝试非对称尺寸
          //! Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N)
		  // 接下来是2NxnU、2NxnD、nLx2N、nRx2N的划分模式的处理  
		  /*
		  ** 接下来的处理有点讲究:
		  ** 1、首先测试AMP_ENC_SPEEDUP宏(表示是否加快编码速度)是否开启
		  ** 2、如果AMP_ENC_SPEEDUP宏开启
		  **      (1)默认情况下,如果TestAMP_Hor、TestAMP_Ver为真,那么可以处理2NxnU、2NxnD、nLx2N、nRx2N这四种模式
		  **      (2)如果TestAMP_Hor、TestAMP_Ver为假,但是开启了AMP_MRG宏,而且TestMergeAMP_Hor、TestMergeAMP_Ver为真,那么还是可以处理2NxnU、2NxnD、nLx2N、nRx2N这四种模式
		  **          否则不再处理2NxnU、2NxnD、nLx2N、nRx2N这四种模式
		  **      (3)由于上面会根据一些条件来判断是否需要处理2NxnU、2NxnD、nLx2N、nRx2N这四种模式,因此某些时候速度会快一点
		  ** 3、如果AMP_ENC_SPEEDUP关闭
		  **      那么直接处理2NxnU、2NxnD、nLx2N、nRx2N这四种模式,因为没有了条件限制,这四种模式都要测试,因此,速度会慢一点

		  */
  //! Do horizontal AMP // TestAMP_Hor为真的话,可以使用2NxnU和2NxnD这两种划分模式
            if ( bTestAMP_Hor )
            {// 处理2NxnU模式 
              if(doNotBlockPu)
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug) );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
              if(doNotBlockPu) // 处理2NxnD模式 
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug) );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
            }
#if AMP_MRG // TestMergeAMP_Hor为真的话可以使用2NxnU、2NxnD这两种模式  
            else if ( bTestMergeAMP_Hor )
            {
              if(doNotBlockPu)// 处理2NxnU模式  
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug), true );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
              if(doNotBlockPu)// 处理2NxnD模式 
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug), true );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
            }
#endif

            //! Do horizontal AMP// TestAMP_Ver为真可以处理nLx2N、nRx2N两种模式  
            if ( bTestAMP_Ver )
            {
              if(doNotBlockPu)// 处理nLx2N模式
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug) );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
              if(doNotBlockPu) // 处理nRx2N模式 
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug) );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
              }
            }
#if AMP_MRG // TestMergeAMP_Ver为真可以处理nLx2N、nRx2N模式
            else if ( bTestMergeAMP_Ver )
            {
              if(doNotBlockPu)// 处理nLx2N模式 
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug), true );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
                if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N )
                {
                  doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0;
                }
              }
              if(doNotBlockPu)// 处理nRx2N模式
              {
                xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug), true );
                rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
              }
            }

}


xCompressCU的作用:从LCU开始深度遍历,计算每一个深度上最优的模式,再综合比较各个深度上最优的模式,选出最优的模式

xCompressCU中的帧间每一个模式的选择都会调用xCheckRDCostInter函数

xCheckRDCostInter主要的功能: 进行帧间搜索,计算当前CU划分模式的RDcost

xCheckRDCostInter->predInterSearch->encodeResAndCalcRdInterCU->xCheckDQP->xCheckBestMode

predInterSearch:帧间搜索

encodeResAndCalcRdInterCU:计算残差和RDcost

xCheckDQP:deltaQP检测

xCheckBestMode:比较RDcost设置最优模式

猜你喜欢

转载自blog.csdn.net/sinat_39372048/article/details/81270635