【HEVC学习与研究】32、编码一个CU(帧内部分)1

来源:互联网 发布:淘宝店铺怎么修改价格 编辑:程序博客网 时间:2024/06/11 07:39

在一个compressSlice()中,在compressCU函数中实现对一个CU的编码,其中主要进行了CU的初始化,以及实际的编码操作。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TEncCu::compressCU( TComDataCU*& rpcCU )  
  2. {  
  3.   // initialize CU data  
  4.   m_ppcBestCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() );  
  5.   m_ppcTempCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() );  
  6.   
  7. #if RATE_CONTROL_LAMBDA_DOMAIN  
  8.   m_addSADDepth      = 0;  
  9.   m_LCUPredictionSAD = 0;  
  10.   m_temporalSAD      = 0;  
  11. #endif  
  12.   
  13.   // analysis of CU  
  14.   xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 );  
  15.   
  16. #if ADAPTIVE_QP_SELECTION  
  17.   if( m_pcEncCfg->getUseAdaptQpSelect() )  
  18.   {  
  19.     if(rpcCU->getSlice()->getSliceType()!=I_SLICE) //IIII  
  20.     {  
  21.       xLcuCollectARLStats( rpcCU);  
  22.     }  
  23.   }  
  24. #endif  
  25. }  
其中完成实际编码一个CU操作的是xCompressCU方法。前面的综述中已经描述过,每一个CTU按照四叉树结构进行划分,CompressCU中调用的xCompressCU则相当于四叉树的根节点。另外,在每一个xCompressCU方法中间,会对每一个CU进行分析判断是否进行下一级划分。

xCompressCU函数由于包含了Intra和InterFrame编码的代码,因此同样非常长,共有600余行。下面着重对帧内编码的部分做一下梳理。

实现帧内编码的部分代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth, PartSize eParentPartSize )  
  2. {  
  3. //......  
  4. // do normal intra modes  
  5.         if ( !bEarlySkip )  
  6.         {  
  7.           // speedup for inter frames  
  8.           if( rpcBestCU->getSlice()->getSliceType() == I_SLICE ||   
  9.             rpcBestCU->getCbf( 0, TEXT_LUMA     ) != 0   ||  
  10.             rpcBestCU->getCbf( 0, TEXT_CHROMA_U ) != 0   ||  
  11.             rpcBestCU->getCbf( 0, TEXT_CHROMA_V ) != 0     ) // avoid very complex intra if it is unlikely  
  12.           {  
  13.             xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_2Nx2N );  
  14.             rpcTempCU->initEstData( uiDepth, iQP );  
  15.             if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth )  
  16.             {  
  17.               if( rpcTempCU->getWidth(0) > ( 1 << rpcTempCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) )  
  18.               {  
  19.                 xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_NxN   );  
  20.                 rpcTempCU->initEstData( uiDepth, iQP );  
  21.               }  
  22.             }  
  23.           }  
  24.         }  
  25. //......  
  26. }  
在这部分代码中xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_2Nx2N )查看了各种intra预测模式下的代价:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TEncCu::xCheckRDCostIntra( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize eSize )  
  2. {  
  3.   UInt uiDepth = rpcTempCU->getDepth( 0 );  
  4.     
  5.   rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth );  
  6.   
  7.   rpcTempCU->setPartSizeSubParts( eSize, 0, uiDepth );  
  8.   rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth );  
  9.   rpcTempCU->setCUTransquantBypassSubParts( m_pcEncCfg->getCUTransquantBypassFlagValue(), 0, uiDepth );  
  10.     
  11.   Bool bSeparateLumaChroma = true// choose estimation mode  
  12.   UInt uiPreCalcDistC      = 0;  
  13.   if( !bSeparateLumaChroma )  
  14.   {  
  15.     m_pcPredSearch->preestChromaPredMode( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth] );  
  16.   }  
  17.   m_pcPredSearch  ->estIntraPredQT      ( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC, bSeparateLumaChroma );  
  18.   
  19.   m_ppcRecoYuvTemp[uiDepth]->copyToPicLuma(rpcTempCU->getPic()->getPicYuvRec(), rpcTempCU->getAddr(), rpcTempCU->getZorderIdxInCU() );  
  20.     
  21.   m_pcPredSearch  ->estIntraPredChromaQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC );  
  22.     
  23.   m_pcEntropyCoder->resetBits();  
  24.   if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag())  
  25.   {  
  26.     m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0,          true );  
  27.   }  
  28.   m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0,          true );  
  29.   m_pcEntropyCoder->encodePredMode( rpcTempCU, 0,          true );  
  30.   m_pcEntropyCoder->encodePartSize( rpcTempCU, 0, uiDepth, true );  
  31.   m_pcEntropyCoder->encodePredInfo( rpcTempCU, 0,          true );  
  32.   m_pcEntropyCoder->encodeIPCMInfo(rpcTempCU, 0, true );  
  33.   
  34.   // Encode Coefficients  
  35.   Bool bCodeDQP = getdQPFlag();  
  36.   m_pcEntropyCoder->encodeCoeff( rpcTempCU, 0, uiDepth, rpcTempCU->getWidth (0), rpcTempCU->getHeight(0), bCodeDQP );  
  37.   setdQPFlag( bCodeDQP );  
  38.     
  39.   if( m_bUseSBACRD ) m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]);  
  40.     
  41.   rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits();  
  42.   if(m_pcEncCfg->getUseSBACRD())  
  43.   {  
  44.     rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();  
  45.   }  
  46.   rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );  
  47.     
  48.   xCheckDQP( rpcTempCU );  
  49.   xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth);  
  50. }  

在这个函数中,调用了estIntraPredQT和estIntraPredChromaQT方法,这两个函数的作用是类似的,区别只在于前者针对亮度分量后者针对色度分量。我们重点关注对亮度分量的操作,即estIntraPredQT函数。

下面是estIntraPredQT的一段代码:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void   
  2. TEncSearch::estIntraPredQT( TComDataCU* pcCU,   
  3.                            TComYuv*    pcOrgYuv,   
  4.                            TComYuv*    pcPredYuv,   
  5.                            TComYuv*    pcResiYuv,   
  6.                            TComYuv*    pcRecoYuv,  
  7.                            UInt&       ruiDistC,  
  8.                            Bool        bLumaOnly )  
  9. {  
  10. //......  
  11.       for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )  
  12.       {  
  13.         UInt uiMode = modeIdx;  
  14.   
  15.         predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );  
  16.           
  17.         // use hadamard transform here  
  18.         UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );  
  19.           
  20.         UInt   iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );  
  21.         Double cost      = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();  
  22.           
  23.         CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );  
  24.       }  
  25. //......  
  26. }  

这个for循环的意义就是遍历多种帧内预测模式,其中numModesAvailable==35,对应整个intra的35个模式。

在predIntraLumaAng函数中,编码器完成计算出当前PU的预测值:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TComPrediction::predIntraLumaAng(TComPattern* pcTComPattern, UInt uiDirMode, Pel* piPred, UInt uiStride, Int iWidth, Int iHeight, Bool bAbove, Bool bLeft )  
  2. {  
  3.     Pel *pDst = piPred;  
  4.     Int *ptrSrc;  
  5.   
  6.     assert( g_aucConvertToBit[ iWidth ] >= 0 ); //   4x  4  
  7.     assert( g_aucConvertToBit[ iWidth ] <= 5 ); // 128x128  
  8.     assert( iWidth == iHeight  );  
  9.   
  10.     ptrSrc = pcTComPattern->getPredictorPtr( uiDirMode, g_aucConvertToBit[ iWidth ] + 2, m_piYuvExt );  
  11.   
  12.     // get starting pixel in block  
  13.     Int sw = 2 * iWidth + 1;  
  14.   
  15.     // Create the prediction  
  16.     if ( uiDirMode == PLANAR_IDX )  
  17.     {  
  18.         xPredIntraPlanar( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight );  
  19.     }  
  20.     else  
  21.     {  
  22.         if ( (iWidth > 16) || (iHeight > 16) )  
  23.         {  
  24.             xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, false );  
  25.         }  
  26.         else  
  27.         {  
  28.             xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, true );  
  29.   
  30.             if( (uiDirMode == DC_IDX ) && bAbove && bLeft )  
  31.             {  
  32.                 xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight);  
  33.             }  
  34.         }  
  35.     }  
  36. }  
在这个函数中主要起作用的是xPredIntraPlanar和xPredIntraAng两个函数,另外在PU大小小于16×16,且模式为DC模式时还会调用xDCPredFiltering函数。在这里我们主要关心前面两个。

xPredIntraPlanar的作用是以平面模式构建当前PU的帧内预测块:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TComPrediction::xPredIntraPlanar( Int* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height )  
  2. {  
  3.     assert(width == height);  
  4.     Int k, l, bottomLeft, topRight;  
  5.     Int horPred;  
  6.     Int leftColumn[MAX_CU_SIZE], topRow[MAX_CU_SIZE], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];  
  7.     UInt blkSize = width;  
  8.     UInt offset2D = width;  
  9.     UInt shift1D = g_aucConvertToBit[ width ] + 2;  
  10.     UInt shift2D = shift1D + 1;  
  11.   
  12.     // Get left and above reference column and row  
  13.     for(k=0;k<blkSize+1;k++)  
  14.     {  
  15.         topRow[k] = pSrc[k-srcStride];  
  16.         leftColumn[k] = pSrc[k*srcStride-1];  
  17.     }  
  18.   
  19.     // Prepare intermediate variables used in interpolation  
  20.     bottomLeft = leftColumn[blkSize];  
  21.     topRight   = topRow[blkSize];  
  22.     for (k=0;k<blkSize;k++)  
  23.     {  
  24.         bottomRow[k]   = bottomLeft - topRow[k];  
  25.         rightColumn[k] = topRight   - leftColumn[k];  
  26.         topRow[k]      <<= shift1D;  
  27.         leftColumn[k]  <<= shift1D;  
  28.     }  
  29.   
  30.     // Generate prediction signal  
  31.     for (k=0;k<blkSize;k++)  
  32.     {  
  33.         horPred = leftColumn[k] + offset2D;  
  34.         for (l=0;l<blkSize;l++)  
  35.         {  
  36.             horPred += rightColumn[k];  
  37.             topRow[l] += bottomRow[l];  
  38.             rpDst[k*dstStride+l] = ( (horPred + topRow[l]) >> shift2D );  
  39.         }  
  40.     }  
  41. }  
xPredIntraAng函数则承担了其他模式的预测块构建,也即,不同的模式索引值代表N多中不同的预测角度,从这些角度上以参考数据构建预测块。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter )  
  2. {  
  3.     Int k,l;  
  4.     Int blkSize        = width;  
  5.     Pel* pDst          = rpDst;  
  6.   
  7.     // Map the mode index to main prediction direction and angle  
  8.     assert( dirMode > 0 ); //no planar  
  9.     Bool modeDC        = dirMode < 2;  
  10.     Bool modeHor       = !modeDC && (dirMode < 18);  
  11.     Bool modeVer       = !modeDC && !modeHor;  
  12.     Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX : modeHor ? -((Int)dirMode - HOR_IDX) : 0;  
  13.     Int absAng         = abs(intraPredAngle);  
  14.     Int signAng        = intraPredAngle < 0 ? -1 : 1;  
  15.   
  16.     // Set bitshifts and scale the angle parameter to block size  
  17.     Int angTable[9]    = {0,    2,    5,   9,  13,  17,  21,  26,  32};  
  18.     Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle  
  19.     Int invAngle       = invAngTable[absAng];  
  20.     absAng             = angTable[absAng];  
  21.     intraPredAngle     = signAng * absAng;  
  22.   
  23.     // Do the DC prediction  
  24.     if (modeDC)  
  25.     {  
  26.         Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, blkAboveAvailable, blkLeftAvailable);  
  27.   
  28.         for (k=0;k<blkSize;k++)  
  29.         {  
  30.             for (l=0;l<blkSize;l++)  
  31.             {  
  32.                 pDst[k*dstStride+l] = dcval;  
  33.             }  
  34.         }  
  35.     }  
  36.   
  37.     // Do angular predictions  
  38.     else  
  39.     {  
  40.         Pel* refMain;  
  41.         Pel* refSide;  
  42.         Pel  refAbove[2*MAX_CU_SIZE+1];  
  43.         Pel  refLeft[2*MAX_CU_SIZE+1];  
  44.   
  45.         // Initialise the Main and Left reference array.  
  46.         if (intraPredAngle < 0)  
  47.         {  
  48.             for (k=0;k<blkSize+1;k++)  
  49.             {  
  50.                 refAbove[k+blkSize-1] = pSrc[k-srcStride-1];  
  51.             }  
  52.             for (k=0;k<blkSize+1;k++)  
  53.             {  
  54.                 refLeft[k+blkSize-1] = pSrc[(k-1)*srcStride-1];  
  55.             }  
  56.             refMain = (modeVer ? refAbove : refLeft) + (blkSize-1);  
  57.             refSide = (modeVer ? refLeft : refAbove) + (blkSize-1);  
  58.   
  59.             // Extend the Main reference to the left.  
  60.             Int invAngleSum    = 128;       // rounding for (shift by 8)  
  61.             for (k=-1; k>blkSize*intraPredAngle>>5; k--)  
  62.             {  
  63.                 invAngleSum += invAngle;  
  64.                 refMain[k] = refSide[invAngleSum>>8];  
  65.             }  
  66.         }  
  67.         else  
  68.         {  
  69.             for (k=0;k<2*blkSize+1;k++)  
  70.             {  
  71.                 refAbove[k] = pSrc[k-srcStride-1];  
  72.             }  
  73.             for (k=0;k<2*blkSize+1;k++)  
  74.             {  
  75.                 refLeft[k] = pSrc[(k-1)*srcStride-1];  
  76.             }  
  77.             refMain = modeVer ? refAbove : refLeft;  
  78.             refSide = modeVer ? refLeft  : refAbove;  
  79.         }  
  80.   
  81.         if (intraPredAngle == 0)  
  82.         {  
  83.             for (k=0;k<blkSize;k++)  
  84.             {  
  85.                 for (l=0;l<blkSize;l++)  
  86.                 {  
  87.                     pDst[k*dstStride+l] = refMain[l+1];  
  88.                 }  
  89.             }  
  90.   
  91.             if ( bFilter )  
  92.             {  
  93.                 for (k=0;k<blkSize;k++)  
  94.                 {  
  95.                     pDst[k*dstStride] = Clip3(0, (1<<bitDepth)-1, pDst[k*dstStride] + (( refSide[k+1] - refSide[0] ) >> 1) );  
  96.                 }  
  97.             }  
  98.         }  
  99.         else  
  100.         {  
  101.             Int deltaPos=0;  
  102.             Int deltaInt;  
  103.             Int deltaFract;  
  104.             Int refMainIndex;  
  105.   
  106.             for (k=0;k<blkSize;k++)  
  107.             {  
  108.                 deltaPos += intraPredAngle;  
  109.                 deltaInt   = deltaPos >> 5;  
  110.                 deltaFract = deltaPos & (32 - 1);  
  111.   
  112.                 if (deltaFract)  
  113.                 {  
  114.                     // Do linear filtering  
  115.                     for (l=0;l<blkSize;l++)  
  116.                     {  
  117.                         refMainIndex        = l+deltaInt+1;  
  118.                         pDst[k*dstStride+l] = (Pel) ( ((32-deltaFract)*refMain[refMainIndex]+deltaFract*refMain[refMainIndex+1]+16) >> 5 );  
  119.                     }  
  120.                 }  
  121.                 else  
  122.                 {  
  123.                     // Just copy the integer samples  
  124.                     for (l=0;l<blkSize;l++)  
  125.                     {  
  126.                         pDst[k*dstStride+l] = refMain[l+deltaInt+1];  
  127.                     }  
  128.                 }  
  129.             }  
  130.         }  
  131.   
  132.         // Flip the block if this is the horizontal mode  
  133.         if (modeHor)  
  134.         {  
  135.             Pel  tmp;  
  136.             for (k=0;k<blkSize-1;k++)  
  137.             {  
  138.                 for (l=k+1;l<blkSize;l++)  
  139.                 {  
  140.                     tmp                 = pDst[k*dstStride+l];  
  141.                     pDst[k*dstStride+l] = pDst[l*dstStride+k];  
  142.                     pDst[l*dstStride+k] = tmp;  
  143.                 }  
  144.             }  
  145.         }  
  146.     }  
  147. }  
具体的预测块构建的原理,将在下篇文章中详述。
0 0