CU的划分、地址以及索引

CU的划分、地址以及索引



    在看HM源码的时候,最蛋疼的一件事就是被CU的划分以及它们的地址搞懵。为了搞清楚,仔细研究了一下源码,有什么错误请指出。为了弄清楚这个问题,必须要对扫描顺序、深度等概念有所理解。



扫描顺序


    HEVC中对像素块的扫描方式有两种:Raster和Zscan

    Raster扫描方式:从上到下,从左到右进行扫描,是最直观也是最容易理解的方式
    Zscan扫描方式:因为CU是递归划分的,因此为了方便处理,HM中使用了Z扫描,也就是从左上角按照Z字形扫描到右下角。下面是Zscan扫描的一个例子:





CU的划分


    CU按照四叉树的方式自上而下,进行递归划分,由于使用了这种递归的方式,因此HEVC中必须要使用Zscan的扫描方式。




深度


    1、深度等于0时,CU的尺寸是64x64,该CU下面4x4小块的数量是256
    2、深度等于1时,CU的尺寸是32x32,该CU下面4x4小块的数量是64
    3、深度等于2时,CU的尺寸是16x16,该CU下面4x4小块的数量是16
    4、深度等于3时,CU的尺寸是8x8,该CU下面4x4小块的数量是4



HEVC中对扫描顺序以及地址的处理



初始化扫描顺序


    1、把每一个LCU都划分为4x4的小块,分别以Raster和Zscan的方式对4x4的小块进行编号(也就是索引)

    2、把Raster到Zscan的编号映射存储在g_auiRasterToZscan数组中

    3、把Zscan到Raster的编号映射存储在g_auiZscanToRaster数组中

    4、把Raster索引到像素地址的映射放在g_auiRasterToPelX和g_auiRasterToPelY中

[cpp]  view plain  copy
  1. extern       UInt   g_auiZscanToRaster[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ]; //   
  2. extern       UInt   g_auiRasterToZscan[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ];  
  3. Void         initZscanToRaster ( Int iMaxDepth, Int iDepth, UInt uiStartVal, UInt*& rpuiCurrIdx );  
  4. Void         initRasterToZscan ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth         );  
  5. extern       UInt   g_auiRasterToPelX[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ];  
  6. extern       UInt   g_auiRasterToPelY[ MAX_NUM_SPU_W*MAX_NUM_SPU_W ];  
  7. Void         initRasterToPelXY ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth );  


[cpp]  view plain  copy
  1. // 计算Z型扫描的块索引  
  2. Void initZscanToRaster ( Int iMaxDepth, Int iDepth, UInt uiStartVal, UInt*& rpuiCurrIdx )  
  3. {  
  4.     // 偏移  
  5.     Int iStride = 1 << ( iMaxDepth - 1 );  
  6.   
  7.     // 已经到达最大深度,递归结束  
  8.     if ( iDepth == iMaxDepth )  
  9.     {  
  10.         rpuiCurrIdx[0] = uiStartVal;  
  11.         rpuiCurrIdx++;  
  12.     }  
  13.     else  
  14.     {  
  15.         // 尚未到达最大深度,使用递归继续往下处理  
  16.         Int iStep = iStride >> iDepth;  
  17.         initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal,                     rpuiCurrIdx );  
  18.         initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep,               rpuiCurrIdx );  
  19.         initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep*iStride,       rpuiCurrIdx );  
  20.         initZscanToRaster( iMaxDepth, iDepth+1, uiStartVal+iStep*iStride+iStep, rpuiCurrIdx );  
  21.     }  
  22. }  

[cpp]  view plain  copy
  1. Void initRasterToZscan ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth )  
  2. {  
  3.     UInt  uiMinCUWidth  = uiMaxCUWidth  >> ( uiMaxDepth - 1 );  
  4.     UInt  uiMinCUHeight = uiMaxCUHeight >> ( uiMaxDepth - 1 );  
  5.   
  6.     UInt  uiNumPartInWidth  = (UInt)uiMaxCUWidth  / uiMinCUWidth;  
  7.     UInt  uiNumPartInHeight = (UInt)uiMaxCUHeight / uiMinCUHeight;  
  8.   
  9.     for ( UInt i = 0; i < uiNumPartInWidth*uiNumPartInHeight; i++ )  
  10.     {  
  11.         g_auiRasterToZscan[ g_auiZscanToRaster[i] ] = i;  
  12.     }  
  13. }  

[cpp]  view plain  copy
  1. // 光栅扫描顺序时,根据索引,定位出像素位置  
  2. Void initRasterToPelXY ( UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxDepth )  
  3. {  
  4.     UInt    i;  
  5.   
  6.     UInt* uiTempX = &g_auiRasterToPelX[0];  
  7.     UInt* uiTempY = &g_auiRasterToPelY[0];  
  8.   
  9.     UInt  uiMinCUWidth  = uiMaxCUWidth  >> ( uiMaxDepth - 1 );  
  10.     UInt  uiMinCUHeight = uiMaxCUHeight >> ( uiMaxDepth - 1 );  
  11.   
  12.     UInt  uiNumPartInWidth  = uiMaxCUWidth  / uiMinCUWidth;  
  13.     UInt  uiNumPartInHeight = uiMaxCUHeight / uiMinCUHeight;  
  14.   
  15.     uiTempX[0] = 0; uiTempX++;  
  16.     for ( i = 1; i < uiNumPartInWidth; i++ )  
  17.     {  
  18.         uiTempX[0] = uiTempX[-1] + uiMinCUWidth; uiTempX++;  
  19.     }  
  20.     for ( i = 1; i < uiNumPartInHeight; i++ )  
  21.     {  
  22.         memcpy(uiTempX, uiTempX-uiNumPartInWidth, sizeof(UInt)*uiNumPartInWidth);  
  23.         uiTempX += uiNumPartInWidth;  
  24.     }  
  25.   
  26.     for ( i = 1; i < uiNumPartInWidth*uiNumPartInHeight; i++ )  
  27.     {  
  28.         uiTempY[i] = ( i / uiNumPartInWidth ) * uiMinCUWidth;  
  29.     }  
  30. };  




根据扫描顺序得到地址



得到Zscan扫描顺序


    这个很简单,由于CU是按照四叉树的方式进行递归处理的,因此CU被处理的顺序就是Zscan扫描顺序。下面是Zscan扫描顺序的一个示意图。



根据Zscan顺序得到Raster扫描顺序

    得到Zscan扫描顺序之后还不够啊,我们需要知道某个块的地址才能对对它进行处理。获取地址需要Raster扫描顺序,可以直接使用g_auiZscanToRaster数组把Zscan顺序转换成Raster顺序。


根据Raster扫描顺序得到CU的地址


    使用g_auiRasterToPelX和g_auiRasterToPelY就可以把Raster扫描顺序转换成相对地址了。但是这个地址只是4x4小块的地址,我们需要的是某个CU的地址,可以按照下面的方式进行处理:

    1、开始的时候已知slice的起始地址、每个LCU的偏移地址,这些在初始化的时候都是确定。

    2、根据CU左上角的4x4块的地址可以算出CU在图像中的地址了。

    3、另外补充一点:根据深度可以确定CU的尺寸



在TEncCu中和CU有关的信息


    TEncCu中有下面一些属性是需要注意的

[cpp]  view plain  copy
  1. TComDataCU**            m_ppcBestCU; //每个深度下的最优CU,用于存储最优值,注意TComDataCU只有CU的信息,不存放数据  
  2. TComDataCU**            m_ppcTempCU;  //每个深度下的临时CU,这个是用于计算,每次计算完成之后都要和最优值进行比较,然后交换      
  3. UChar                   m_uhTotalDepth; //总的深度  
  4. TComYuv**               m_ppcPredYuvBest; //每个深度下最优的预测YUV  
  5. TComYuv**               m_ppcResiYuvBest; //每个深度下最优的残差YUV  
  6. TComYuv**               m_ppcRecoYuvBest; //每个深度下最优的重建YUV  
  7. TComYuv**               m_ppcPredYuvTemp; //每个深度下临时的预测YUV,用于计算过程,计算完成后和最优的进行比较,然后交换  
  8. TComYuv**               m_ppcResiYuvTemp; //每个深度下临时的残差YUV,同上  
  9. TComYuv**               m_ppcRecoYuvTemp; //每个深度下临时的重建YUV,同上  
  10. TComYuv**               m_ppcOrigYuv;    //YUV数据,在编码之前从TComPicYuv中得到,TComPicYuv在TComPic中  
    1、bestCU用于存放某个深度上CU的最优划分信息

    2、tempCU用于编码过程,每编码完成一个CU就将tempCU与bestCU进行比较,如果有需要就更新bestCU

    3、TComDataCU存放了CU中所有4x4小块的信息!



在编码过程中CU的地址和索引


LCU的地址


    在函数compressCU中,LCU被初始化,它根据传进来的TComPicSym的LCU信息,调用initCU进行初始化,得到LCU的地址等信息。这么做是因为在编码的过程中不对TComPicSym的LCU进行直接操作,需要复制它的信息到临时的对象中,编码完成后再把最优的信息复制回TComPicSym中。

    m_ppcBestCU表示某个深度下最优的CU信息,主要目的是存放最优的信息;m_ppcTempCU表示某个深度下临时的CU信息,它被用于编码操作,编码完成之后,再根据需要把最优信息保存到m_ppcBestCU中。

[cpp]  view plain  copy
  1. Void TEncCu::compressCU( TComDataCU*& rpcCU )//TComPicSym  
  2. {  
  3.     // initialize CU data  
  4.     // CU初始化  
  5.     // 初始化最佳CU和临时CU  
  6.     m_ppcBestCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() );  
  7.     m_ppcTempCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() );  
  8.   
  9.     // analysis of CU  
  10.     // 进行CU的切割  
  11.     // 起始的深度是0,即最开始进去的是LCU  
  12.     xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 );  
  13. }  
    1、开始的时候rpcCU表示一个LCU
    2、利用LCU的信息,对深度等于0的bestCU和tempCU进行初始化,m_ppcBestCU的下标表示深度
    3、调用xCompressCU


    initCU主要用于LCU的初始化,普通CU的初始化不使用它

[cpp]  view plain  copy
  1. // 实际上这是针对LCU的初始化,对于普通的CU,初始化使用initSubCU  
  2. Void TComDataCU::initCU( TComPic* pcPic, UInt iCUAddr )  
  3. {  
  4.     // 当前CU所属的图像  
  5.     m_pcPic              = pcPic;  
  6.     // 当前CU所属的slice  
  7.     m_pcSlice            = pcPic->getSlice(pcPic->getCurrSliceIdx());  
  8.     // CU的地址  
  9.     m_uiCUAddr           = iCUAddr;  
  10.     // LCU在图像中的实际像素地址  
  11.     m_uiCUPelX           = ( iCUAddr % pcPic->getFrameWidthInCU() ) * g_uiMaxCUWidth;  
  12.     m_uiCUPelY           = ( iCUAddr / pcPic->getFrameWidthInCU() ) * g_uiMaxCUHeight;  
  13.     m_uiAbsIdxInLCU      = 0;  
  14.     // 总的RD消耗  
  15.     m_dTotalCost         = MAX_DOUBLE;  
  16.     // 总的失真  
  17.     m_uiTotalDistortion  = 0;  
  18.     // 总的比特数  
  19.     m_uiTotalBits        = 0;  
  20.     // 总的二进制数  
  21.     m_uiTotalBins        = 0;  
  22.   
  23.     // 一帧图像最多可以分成256个CU(即深度是4,2^4 * 2^4 = 256)  
  24.     m_uiNumPartition     = pcPic->getNumPartInCU();  
  25.   
  26.     // m_sliceStartCU初始化之后全都是0  
  27.     for(Int i=0; i<pcPic->getNumPartInCU(); i++)  
  28.     {  
  29.         if(pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr)*pcPic->getNumPartInCU()+i>=getSlice()->getSliceCurStartCUAddr())  
  30.         {  
  31.             // 设置条带开始的CU的地址放到一个数组中  
  32.             m_sliceStartCU[i]=getSlice()->getSliceCurStartCUAddr();  
  33.         }  
  34.         else  
  35.         {  
  36.             // 获取slice中的所有CU,存放到一个数组中  
  37.             m_sliceStartCU[i]=pcPic->getCU(getAddr())->m_sliceStartCU[i];  
  38.         }  
  39.     }  
  40.   
  41.     for(Int i=0; i<pcPic->getNumPartInCU(); i++)  
  42.     {  
  43.         if(pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr)*pcPic->getNumPartInCU()+i>=getSlice()->getSliceSegmentCurStartCUAddr())  
  44.         {  
  45.             m_sliceSegmentStartCU[i]=getSlice()->getSliceSegmentCurStartCUAddr();  
  46.         }  
  47.         else  
  48.         {  
  49.             // 获取所有的条带片段中的CU,存放到数组中  
  50.             m_sliceSegmentStartCU[i]=pcPic->getCU(getAddr())->m_sliceSegmentStartCU[i];  
  51.         }  
  52.     }  
  53.   
  54.     // getInverseCUOrderMap 这个函数是根据CU的地址获取CU的顺序索引  
  55.     Int partStartIdx = getSlice()->getSliceSegmentCurStartCUAddr() - pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr) * pcPic->getNumPartInCU();  
  56.   
  57.     // 元素的个数  
  58.     Int numElements = min<Int>( partStartIdx, m_uiNumPartition );  
  59.     for ( Int ui = 0; ui < numElements; ui++ )  
  60.     {  
  61.         TComDataCU * pcFrom = pcPic->getCU(getAddr());  
  62.         m_skipFlag[ui]   = pcFrom->getSkipFlag(ui);  
  63.         m_pePartSize[ui] = pcFrom->getPartitionSize(ui);  
  64.         m_pePredMode[ui] = pcFrom->getPredictionMode(ui);  
  65.         m_CUTransquantBypass[ui] = pcFrom->getCUTransquantBypass(ui);  
  66.         m_puhDepth[ui] = pcFrom->getDepth(ui);  
  67.         m_puhWidth  [ui] = pcFrom->getWidth(ui);  
  68.         m_puhHeight [ui] = pcFrom->getHeight(ui);  
  69.         m_puhTrIdx  [ui] = pcFrom->getTransformIdx(ui);  
  70.         m_puhTransformSkip[0][ui] = pcFrom->getTransformSkip(ui,TEXT_LUMA);  
  71.         m_puhTransformSkip[1][ui] = pcFrom->getTransformSkip(ui,TEXT_CHROMA_U);  
  72.         m_puhTransformSkip[2][ui] = pcFrom->getTransformSkip(ui,TEXT_CHROMA_V);  
  73.         m_apiMVPIdx[0][ui] = pcFrom->m_apiMVPIdx[0][ui];;  
  74.         m_apiMVPIdx[1][ui] = pcFrom->m_apiMVPIdx[1][ui];  
  75.         m_apiMVPNum[0][ui] = pcFrom->m_apiMVPNum[0][ui];  
  76.         m_apiMVPNum[1][ui] = pcFrom->m_apiMVPNum[1][ui];  
  77.         m_phQP[ui]=pcFrom->m_phQP[ui];  
  78.         m_pbMergeFlag[ui]=pcFrom->m_pbMergeFlag[ui];  
  79.         m_puhMergeIndex[ui]=pcFrom->m_puhMergeIndex[ui];  
  80.         m_puhLumaIntraDir[ui]=pcFrom->m_puhLumaIntraDir[ui];  
  81.         m_puhChromaIntraDir[ui]=pcFrom->m_puhChromaIntraDir[ui];  
  82.         m_puhInterDir[ui]=pcFrom->m_puhInterDir[ui];  
  83.         m_puhCbf[0][ui]=pcFrom->m_puhCbf[0][ui];  
  84.         m_puhCbf[1][ui]=pcFrom->m_puhCbf[1][ui];  
  85.         m_puhCbf[2][ui]=pcFrom->m_puhCbf[2][ui];  
  86.         m_pbIPCMFlag[ui] = pcFrom->m_pbIPCMFlag[ui];  
  87.     }  
  88.   
  89.     // 第一个元素  
  90.     Int firstElement = max<Int>( partStartIdx, 0 );  
  91.   
  92.     // 元素的个数  
  93.     numElements = m_uiNumPartition - firstElement;  
  94.   
  95.     if ( numElements > 0 )  
  96.     {  
  97.         memset( m_skipFlag          + firstElement, false,                    numElements * sizeof( *m_skipFlag ) );  
  98.   
  99.         memset( m_pePartSize        + firstElement, SIZE_NONE,                numElements * sizeof( *m_pePartSize ) );  
  100.         memset( m_pePredMode        + firstElement, MODE_NONE,                numElements * sizeof( *m_pePredMode ) );  
  101.         memset( m_CUTransquantBypass+ firstElement, false,                    numElements * sizeof( *m_CUTransquantBypass) );  
  102.         memset( m_puhDepth          + firstElement, 0,                        numElements * sizeof( *m_puhDepth ) );  
  103.         memset( m_puhTrIdx          + firstElement, 0,                        numElements * sizeof( *m_puhTrIdx ) );  
  104.         memset( m_puhTransformSkip[0] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[0]) );  
  105.         memset( m_puhTransformSkip[1] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[1]) );  
  106.         memset( m_puhTransformSkip[2] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[2]) );  
  107.         memset( m_puhWidth          + firstElement, g_uiMaxCUWidth,           numElements * sizeof( *m_puhWidth ) );  
  108.         memset( m_puhHeight         + firstElement, g_uiMaxCUHeight,          numElements * sizeof( *m_puhHeight ) );  
  109.         memset( m_apiMVPIdx[0]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPIdx[0] ) );  
  110.         memset( m_apiMVPIdx[1]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPIdx[1] ) );  
  111.         memset( m_apiMVPNum[0]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPNum[0] ) );  
  112.         memset( m_apiMVPNum[1]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPNum[1] ) );  
  113.         memset( m_phQP              + firstElement, getSlice()->getSliceQp(), numElements * sizeof( *m_phQP ) );  
  114.         memset( m_pbMergeFlag       + firstElement, false,                    numElements * sizeof( *m_pbMergeFlag ) );  
  115.         memset( m_puhMergeIndex     + firstElement, 0,                        numElements * sizeof( *m_puhMergeIndex ) );  
  116.         memset( m_puhLumaIntraDir   + firstElement, DC_IDX,                   numElements * sizeof( *m_puhLumaIntraDir ) );  
  117.         memset( m_puhChromaIntraDir + firstElement, 0,                        numElements * sizeof( *m_puhChromaIntraDir ) );  
  118.         memset( m_puhInterDir       + firstElement, 0,                        numElements * sizeof( *m_puhInterDir ) );  
  119.         memset( m_puhCbf[0]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[0] ) );  
  120.         memset( m_puhCbf[1]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[1] ) );  
  121.         memset( m_puhCbf[2]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[2] ) );  
  122.         memset( m_pbIPCMFlag        + firstElement, false,                    numElements * sizeof( *m_pbIPCMFlag ) );  
  123.     }  
  124.   
  125.     UInt uiTmp = g_uiMaxCUWidth*g_uiMaxCUHeight;  
  126.     if ( 0 >= partStartIdx )   
  127.     {  
  128.         m_acCUMvField[0].clearMvField();  
  129.         m_acCUMvField[1].clearMvField();  
  130.         memset( m_pcTrCoeffY , 0, sizeof( TCoeff ) * uiTmp );  
  131. #if ADAPTIVE_QP_SELECTION  
  132.         memset( m_pcArlCoeffY , 0, sizeof( Int ) * uiTmp );    
  133. #endif  
  134.         memset( m_pcIPCMSampleY , 0, sizeof( Pel ) * uiTmp );  
  135.         uiTmp  >>= 2;  
  136.         memset( m_pcTrCoeffCb, 0, sizeof( TCoeff ) * uiTmp );  
  137.         memset( m_pcTrCoeffCr, 0, sizeof( TCoeff ) * uiTmp );  
  138. #if ADAPTIVE_QP_SELECTION    
  139.         memset( m_pcArlCoeffCb, 0, sizeof( Int ) * uiTmp );  
  140.         memset( m_pcArlCoeffCr, 0, sizeof( Int ) * uiTmp );  
  141. #endif  
  142.         memset( m_pcIPCMSampleCb , 0, sizeof( Pel ) * uiTmp );  
  143.         memset( m_pcIPCMSampleCr , 0, sizeof( Pel ) * uiTmp );  
  144.     }  
  145.     else   
  146.     {  
  147.         TComDataCU * pcFrom = pcPic->getCU(getAddr());  
  148.         m_acCUMvField[0].copyFrom(&pcFrom->m_acCUMvField[0],m_uiNumPartition,0);  
  149.         m_acCUMvField[1].copyFrom(&pcFrom->m_acCUMvField[1],m_uiNumPartition,0);  
  150.         for(Int i=0; i<uiTmp; i++)  
  151.         {  
  152.             m_pcTrCoeffY[i]=pcFrom->m_pcTrCoeffY[i];  
  153. #if ADAPTIVE_QP_SELECTION  
  154.             m_pcArlCoeffY[i]=pcFrom->m_pcArlCoeffY[i];  
  155. #endif  
  156.             m_pcIPCMSampleY[i]=pcFrom->m_pcIPCMSampleY[i];  
  157.         }  
  158.         for(Int i=0; i<(uiTmp>>2); i++)  
  159.         {  
  160.             m_pcTrCoeffCb[i]=pcFrom->m_pcTrCoeffCb[i];  
  161.             m_pcTrCoeffCr[i]=pcFrom->m_pcTrCoeffCr[i];  
  162. #if ADAPTIVE_QP_SELECTION  
  163.             m_pcArlCoeffCb[i]=pcFrom->m_pcArlCoeffCb[i];  
  164.             m_pcArlCoeffCr[i]=pcFrom->m_pcArlCoeffCr[i];  
  165. #endif  
  166.             m_pcIPCMSampleCb[i]=pcFrom->m_pcIPCMSampleCb[i];  
  167.             m_pcIPCMSampleCr[i]=pcFrom->m_pcIPCMSampleCr[i];  
  168.         }  
  169.     }  
  170.   
  171.     // Setting neighbor CU  
  172.     // 设置相邻CU  
  173.     m_pcCULeft        = NULL;           // 左边的CU  
  174.     m_pcCUAbove       = NULL;           // 上面的CU  
  175.     m_pcCUAboveLeft   = NULL;       // 左上方的CU  
  176.     m_pcCUAboveRight  = NULL;       // 右上方的CU  
  177.   
  178.     // 位置数组,有两个元素  
  179.     m_apcCUColocated[0] = NULL;  
  180.     m_apcCUColocated[1] = NULL;  
  181.   
  182.     // 获取一帧图片中,横向上CU的个数  
  183.     UInt uiWidthInCU = pcPic->getFrameWidthInCU();  
  184.   
  185.     // 分别获取当前CU各个方向上相邻的CU  
  186.   
  187.     // 如果CU地址不为图片上横向上CU个数的整数倍,那么它的左边有CU  
  188.     if ( m_uiCUAddr % uiWidthInCU )  
  189.     {  
  190.         m_pcCULeft = pcPic->getCU( m_uiCUAddr - 1 );  
  191.     }  
  192.   
  193.     // 如果CU地址不为图像纵向上CU个数的整数倍,那么它的上方存在CU  
  194.     if ( m_uiCUAddr / uiWidthInCU )  
  195.     {  
  196.         m_pcCUAbove = pcPic->getCU( m_uiCUAddr - uiWidthInCU );  
  197.     }  
  198.   
  199.     // 如果左边有CU,上方有CU,那么当前CU的上面有CU  
  200.     if ( m_pcCULeft && m_pcCUAbove )  
  201.     {  
  202.         m_pcCUAboveLeft = pcPic->getCU( m_uiCUAddr - uiWidthInCU - 1 );  
  203.     }  
  204.   
  205.     // 如果上边有CU,而且当前CU不是当前行最后一个CU,那么它的右上角有CU  
  206.     if ( m_pcCUAbove && ( (m_uiCUAddr%uiWidthInCU) < (uiWidthInCU-1) )  )  
  207.     {  
  208.         m_pcCUAboveRight = pcPic->getCU( m_uiCUAddr - uiWidthInCU + 1 );  
  209.     }  
  210.   
  211.     // getNumRefIdx从参考图片数组(数组0或1)获取参考图片的数量  
  212.     if ( getSlice()->getNumRefIdx( REF_PIC_LIST_0 ) > 0 )  
  213.     {  
  214.         m_apcCUColocated[0] = getSlice()->getRefPic( REF_PIC_LIST_0, 0)->getCU( m_uiCUAddr );  
  215.     }  
  216.   
  217.     if ( getSlice()->getNumRefIdx( REF_PIC_LIST_1 ) > 0 )  
  218.     {  
  219.         m_apcCUColocated[1] = getSlice()->getRefPic( REF_PIC_LIST_1, 0)->getCU( m_uiCUAddr );  
  220.     }  
  221. }  


普通CU的地址

    在xCompressCU中,下列语句用于初始化下一层的子CU

[cpp]  view plain  copy
  1. UChar       uhNextDepth         = uiDepth+1;  
  2. TComDataCU* pcSubBestPartCU     = m_ppcBestCU[uhNextDepth];  
  3. TComDataCU* pcSubTempPartCU     = m_ppcTempCU[uhNextDepth];  
  4.   
  5. // 进一步的分割,当前CU又被划分成为4个子CU  
  6.   
  7. // 对子CU进行初始化,计算坐标索引等等,然后把父亲CU的信息复制给子CU  
  8. // 另外,tempSubCU会和rpcTempCU一样调用initEstData,进行清理,把旧的数据清除掉  
  9. for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )  
  10. {  
  11.     // <span style="font-family: Arial, Helvetica, sans-serif;">对子CU进行初始化,计算坐标索引等等,然后把父亲CU的信息复制给子CU</span>  
  12.     pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );           // clear sub partition datas or init.  
  13.   
  14.     pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );           // clear sub partition datas or init.  
  15.   
  16.     // ***  
  17. }  

    普通的CU初始化的时候不使用initCU,而是以父亲CU作为参数调用initSubCU进行初始化。

    1、计算当前CU在父亲CU中以partition(4x4大小的块)为单位的偏移

    2、计算当前CU的地址,利用父亲CU的地址和偏移量可以算出当前CU的地址

    3、计算当前CU在LCU中的Zscan顺序的索引,先获取父亲CU的Zscan索引,再加上偏移就可以得到当前CU的Zscan索引

    4、计算当前CU的坐标,利用父亲CU的坐标、当前CU的尺寸和当前CU在父亲CU中的索引可以计算

    5、最后请注意:LCU的相关信息通过initCU已经设置完成,因此对于32x32的CU,可以直接利用LCU调用initSubCU进行初始化!

[cpp]  view plain  copy
  1. Void TComDataCU::initSubCU( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth, Int qp )  
  2. {  
  3.     assert( uiPartUnitIdx<4 );  
  4.   
  5.     // partition(也就是4x4大小的块)为单位的偏移  
  6.     // pcCU->getTotalNumPart()>>2表示当前CU中partition的数量是父亲CU的1/4,因为它的宽和高都是父亲CU的一半  
  7.     // 乘以uiPartUnitIdx的目的是计算当前CU在父亲CU中的偏移  
  8.     UInt uiPartOffset = ( pcCU->getTotalNumPart()>>2 )*uiPartUnitIdx;  
  9.   
  10.     m_pcPic              = pcCU->getPic();  
  11.     m_pcSlice            = m_pcPic->getSlice(m_pcPic->getCurrSliceIdx());  
  12.       
  13.     // 父亲CU的地址,利用父亲CU的地址和偏移可以计算出当前CU的地址  
  14.     m_uiCUAddr           = pcCU->getAddr();  
  15.       
  16.     // pcCU->getZorderIdxInCU()得到父亲CU在LCU中的Zscan顺序的索引,加上偏移之后得到当前CU在LCU中的索引  
  17.     m_uiAbsIdxInLCU      = pcCU->getZorderIdxInCU() + uiPartOffset;  
  18.   
  19.     // 计算当前CU的坐标(左上角)  
  20.     // pcCU->getCUPelX()得到父亲CU的坐标,利用当前CU的尺寸以及它在父亲CU中索引,计算出当前CU的坐标  
  21.     m_uiCUPelX           = pcCU->getCUPelX() + ( g_uiMaxCUWidth>>uiDepth  )*( uiPartUnitIdx &  1 );  
  22.     m_uiCUPelY           = pcCU->getCUPelY() + ( g_uiMaxCUHeight>>uiDepth  )*( uiPartUnitIdx >> 1 );  
  23.   
  24.     m_dTotalCost         = MAX_DOUBLE;  
  25.     m_uiTotalDistortion  = 0;  
  26.     m_uiTotalBits        = 0;  
  27.     m_uiTotalBins        = 0;  
  28.     m_uiNumPartition     = pcCU->getTotalNumPart() >> 2;  
  29.   
  30.     Int iSizeInUchar = sizeof( UChar  ) * m_uiNumPartition;  
  31.     Int iSizeInBool  = sizeof( Bool   ) * m_uiNumPartition;  
  32.   
  33.     Int sizeInChar = sizeof( Char  ) * m_uiNumPartition;  
  34.     memset( m_phQP,              qp,  sizeInChar );  
  35.   
  36.     memset( m_pbMergeFlag,        0, iSizeInBool  );  
  37.     memset( m_puhMergeIndex,      0, iSizeInUchar );  
  38.     memset( m_puhLumaIntraDir,    DC_IDX, iSizeInUchar );  
  39.     memset( m_puhChromaIntraDir,  0, iSizeInUchar );  
  40.     memset( m_puhInterDir,        0, iSizeInUchar );  
  41.     memset( m_puhTrIdx,           0, iSizeInUchar );  
  42.     memset( m_puhTransformSkip[0], 0, iSizeInUchar );  
  43.     memset( m_puhTransformSkip[1], 0, iSizeInUchar );  
  44.     memset( m_puhTransformSkip[2], 0, iSizeInUchar );  
  45.     memset( m_puhCbf[0],          0, iSizeInUchar );  
  46.     memset( m_puhCbf[1],          0, iSizeInUchar );  
  47.     memset( m_puhCbf[2],          0, iSizeInUchar );  
  48.     memset( m_puhDepth,     uiDepth, iSizeInUchar );  
  49.   
  50.     UChar uhWidth  = g_uiMaxCUWidth  >> uiDepth;  
  51.     UChar uhHeight = g_uiMaxCUHeight >> uiDepth;  
  52.     memset( m_puhWidth,          uhWidth,  iSizeInUchar );  
  53.     memset( m_puhHeight,         uhHeight, iSizeInUchar );  
  54.     memset( m_pbIPCMFlag,        0, iSizeInBool  );  
  55.     for (UInt ui = 0; ui < m_uiNumPartition; ui++)  
  56.     {  
  57.         m_skipFlag[ui]   = false;  
  58.         m_pePartSize[ui] = SIZE_NONE;  
  59.         m_pePredMode[ui] = MODE_NONE;  
  60.         m_CUTransquantBypass[ui] = false;  
  61.         m_apiMVPIdx[0][ui] = -1;  
  62.         m_apiMVPIdx[1][ui] = -1;  
  63.         m_apiMVPNum[0][ui] = -1;  
  64.         m_apiMVPNum[1][ui] = -1;  
  65.         if(m_pcPic->getPicSym()->getInverseCUOrderMap(getAddr())*m_pcPic->getNumPartInCU()+m_uiAbsIdxInLCU+ui<getSlice()->getSliceSegmentCurStartCUAddr())  
  66.         {  
  67.             m_apiMVPIdx[0][ui] = pcCU->m_apiMVPIdx[0][uiPartOffset+ui];  
  68.             m_apiMVPIdx[1][ui] = pcCU->m_apiMVPIdx[1][uiPartOffset+ui];;  
  69.             m_apiMVPNum[0][ui] = pcCU->m_apiMVPNum[0][uiPartOffset+ui];;  
  70.             m_apiMVPNum[1][ui] = pcCU->m_apiMVPNum[1][uiPartOffset+ui];;  
  71.             m_puhDepth  [ui] = pcCU->getDepth(uiPartOffset+ui);  
  72.             m_puhWidth  [ui] = pcCU->getWidth(uiPartOffset+ui);  
  73.             m_puhHeight  [ui] = pcCU->getHeight(uiPartOffset+ui);  
  74.             m_puhTrIdx  [ui] = pcCU->getTransformIdx(uiPartOffset+ui);  
  75.             m_puhTransformSkip[0][ui] = pcCU->getTransformSkip(uiPartOffset+ui,TEXT_LUMA);  
  76.             m_puhTransformSkip[1][ui] = pcCU->getTransformSkip(uiPartOffset+ui,TEXT_CHROMA_U);  
  77.             m_puhTransformSkip[2][ui] = pcCU->getTransformSkip(uiPartOffset+ui,TEXT_CHROMA_V);  
  78.             m_skipFlag[ui]   = pcCU->getSkipFlag(uiPartOffset+ui);  
  79.             m_pePartSize[ui] = pcCU->getPartitionSize(uiPartOffset+ui);  
  80.             m_pePredMode[ui] = pcCU->getPredictionMode(uiPartOffset+ui);  
  81.             m_CUTransquantBypass[ui] = pcCU->getCUTransquantBypass(uiPartOffset+ui);  
  82.             m_pbIPCMFlag[ui]=pcCU->m_pbIPCMFlag[uiPartOffset+ui];  
  83.             m_phQP[ui] = pcCU->m_phQP[uiPartOffset+ui];  
  84.             m_pbMergeFlag[ui]=pcCU->m_pbMergeFlag[uiPartOffset+ui];  
  85.             m_puhMergeIndex[ui]=pcCU->m_puhMergeIndex[uiPartOffset+ui];  
  86.             m_puhLumaIntraDir[ui]=pcCU->m_puhLumaIntraDir[uiPartOffset+ui];  
  87.             m_puhChromaIntraDir[ui]=pcCU->m_puhChromaIntraDir[uiPartOffset+ui];  
  88.             m_puhInterDir[ui]=pcCU->m_puhInterDir[uiPartOffset+ui];  
  89.             m_puhCbf[0][ui]=pcCU->m_puhCbf[0][uiPartOffset+ui];  
  90.             m_puhCbf[1][ui]=pcCU->m_puhCbf[1][uiPartOffset+ui];  
  91.             m_puhCbf[2][ui]=pcCU->m_puhCbf[2][uiPartOffset+ui];  
  92.   
  93.         }  
  94.     }  
  95.     UInt uiTmp = uhWidth*uhHeight;  
  96.     memset( m_pcTrCoeffY , 0, sizeof(TCoeff)*uiTmp );  
  97. #if ADAPTIVE_QP_SELECTION    
  98.     memset( m_pcArlCoeffY , 0, sizeof(Int)*uiTmp );  
  99. #endif  
  100.     memset( m_pcIPCMSampleY , 0, sizeof( Pel ) * uiTmp );  
  101.     uiTmp >>= 2;  
  102.     memset( m_pcTrCoeffCb, 0, sizeof(TCoeff)*uiTmp );  
  103.     memset( m_pcTrCoeffCr, 0, sizeof(TCoeff)*uiTmp );  
  104. #if ADAPTIVE_QP_SELECTION  
  105.     memset( m_pcArlCoeffCb, 0, sizeof(Int)*uiTmp );  
  106.     memset( m_pcArlCoeffCr, 0, sizeof(Int)*uiTmp );  
  107. #endif  
  108.     memset( m_pcIPCMSampleCb , 0, sizeof( Pel ) * uiTmp );  
  109.     memset( m_pcIPCMSampleCr , 0, sizeof( Pel ) * uiTmp );  
  110.     m_acCUMvField[0].clearMvField();  
  111.     m_acCUMvField[1].clearMvField();  
  112.   
  113.     if(m_pcPic->getPicSym()->getInverseCUOrderMap(getAddr())*m_pcPic->getNumPartInCU()+m_uiAbsIdxInLCU<getSlice()->getSliceSegmentCurStartCUAddr())  
  114.     {  
  115.         // Part of this CU contains data from an older slice. Now copy in that data.  
  116.         UInt uiMaxCuWidth=pcCU->getSlice()->getSPS()->getMaxCUWidth();  
  117.         UInt uiMaxCuHeight=pcCU->getSlice()->getSPS()->getMaxCUHeight();  
  118.         TComDataCU * bigCU = getPic()->getCU(getAddr());  
  119.         Int minui = uiPartOffset;  
  120.         minui = -minui;  
  121.         pcCU->m_acCUMvField[0].copyTo(&m_acCUMvField[0],minui,uiPartOffset,m_uiNumPartition);  
  122.         pcCU->m_acCUMvField[1].copyTo(&m_acCUMvField[1],minui,uiPartOffset,m_uiNumPartition);  
  123.         UInt uiCoffOffset = uiMaxCuWidth*uiMaxCuHeight*m_uiAbsIdxInLCU/pcCU->getPic()->getNumPartInCU();  
  124.         uiTmp = uhWidth*uhHeight;  
  125.         for(Int i=0; i<uiTmp; i++)  
  126.         {  
  127.             m_pcTrCoeffY[i]=bigCU->m_pcTrCoeffY[uiCoffOffset+i];  
  128. #if ADAPTIVE_QP_SELECTION  
  129.             m_pcArlCoeffY[i]=bigCU->m_pcArlCoeffY[uiCoffOffset+i];  
  130. #endif  
  131.             m_pcIPCMSampleY[i]=bigCU->m_pcIPCMSampleY[uiCoffOffset+i];  
  132.         }  
  133.         uiTmp>>=2;  
  134.         uiCoffOffset>>=2;  
  135.         for(Int i=0; i<uiTmp; i++)  
  136.         {  
  137.             m_pcTrCoeffCr[i]=bigCU->m_pcTrCoeffCr[uiCoffOffset+i];  
  138.             m_pcTrCoeffCb[i]=bigCU->m_pcTrCoeffCb[uiCoffOffset+i];  
  139. #if ADAPTIVE_QP_SELECTION  
  140.             m_pcArlCoeffCr[i]=bigCU->m_pcArlCoeffCr[uiCoffOffset+i];  
  141.             m_pcArlCoeffCb[i]=bigCU->m_pcArlCoeffCb[uiCoffOffset+i];  
  142. #endif  
  143.             m_pcIPCMSampleCb[i]=bigCU->m_pcIPCMSampleCb[uiCoffOffset+i];  
  144.             m_pcIPCMSampleCr[i]=bigCU->m_pcIPCMSampleCr[uiCoffOffset+i];  
  145.         }  
  146.     }  
  147.   
  148.     m_pcCULeft        = pcCU->getCULeft();  
  149.     m_pcCUAbove       = pcCU->getCUAbove();  
  150.     m_pcCUAboveLeft   = pcCU->getCUAboveLeft();  
  151.     m_pcCUAboveRight  = pcCU->getCUAboveRight();  
  152.   
  153.     m_apcCUColocated[0] = pcCU->getCUColocated(REF_PIC_LIST_0);  
  154.     m_apcCUColocated[1] = pcCU->getCUColocated(REF_PIC_LIST_1);  
  155.     memcpy(m_sliceStartCU,pcCU->m_sliceStartCU+uiPartOffset,sizeof(UInt)*m_uiNumPartition);  
  156.     memcpy(m_sliceSegmentStartCU,pcCU->m_sliceSegmentStartCU+uiPartOffset,sizeof(UInt)*m_uiNumPartition);  
  157. }  

    在xCompressCU中,下面四条语句用于获取bestCU的坐标

[cpp]  view plain  copy
  1. UInt uiLPelX   = rpcBestCU->getCUPelX();                         //  (left)  
  2. UInt uiRPelX   = uiLPelX + rpcBestCU->getWidth(0)  - 1;      //  (right)  
  3. UInt uiTPelY   = rpcBestCU->getCUPelY();                         //  (top)  
  4. UInt uiBPelY   = uiTPelY + rpcBestCU->getHeight(0) - 1;      //  (buttom)  
    1、getCUPelX返回CU的左上角的X坐标
    2、getWidth(0)返回当前CU的宽度,参数是深度值,0表示返回的是当前CU的宽度,而不是其子CU的宽度
    3、getCUPelY返回CU左上角的Y坐标
    4、getHeight(0)返回当前CU的高度,参数是深度值,0表示返回的是当前CU的高度,而不是其子CU的高度


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值