變換:係數的編碼(一)

係數掃描模式的初始化:

// scanning order table  
UInt* g_auiSigLastScan[ 3 ][ MAX_CU_DEPTH ]; //!< [pattern][depth]  
  
const UInt g_sigLastScan8x8[ 3 ][ 4 ] =  
{  
  {0, 2, 1, 3}, //!< right-up diagonal  
  {0, 1, 2, 3}, //!< horizontal  
  {0, 2, 1, 3}  //!< vertical  
};  
UInt g_sigLastScanCG32x32[ 64 ];  

Void initSigLastScan(UInt* pBuffD, UInt* pBuffH, UInt* pBuffV, Int iWidth, Int iHeight, Int iDepth)  
{  
  const UInt  uiNumScanPos  = UInt( iWidth * iWidth );  
  UInt        uiNextScanPos = 0;  
  
  /* 
  ** 在這裏需要先作如下說明,以免對接下來代碼中的一些處理會有疑惑。 
  ** 首先,在初始化時,總共有2x2,4x4,8x8,16x16,32x32,64x64,128x128這7種情況,當然,我們實際使用 
  ** 的就只有4x4,8x8,16x16,32x32這4種,其餘的幾種至少目前的draft中是不採用的,故重點關注這4種即可。 
  ** 其次,這段初始化代碼是基於JCTVC-G644這個提案的,提案的具體內容請自行把這個提案下載下來閱讀,這裏 
  ** 不作詳細介紹。 
  */  
  
  if( iWidth < 16 )  
  {  
  UInt* pBuffTemp = pBuffD;  
  if( iWidth == 8 )  
  {  
    pBuffTemp = g_sigLastScanCG32x32; //!< 用於TU爲32x32時的係數掃描,CG爲Coefficient Group的縮寫  
  }  
  for( UInt uiScanLine = 0; uiNextScanPos < uiNumScanPos; uiScanLine++ )  
  {  
    Int    iPrimDim  = Int( uiScanLine );   //!< uiScanLine爲已經掃描過的反對角線數  
    Int    iScndDim  = 0;                       //!< 在某條反對角線上的計數  
    while( iPrimDim >= iWidth )              //!< 掃描的反對角線如果已經超過矩陣反對角線數的一半  
    {                                                   //!< 則根據該反對角線與反主對角線的距離,距離每增加1,則總元素數減1  
      iScndDim++;  
      iPrimDim--;  
    }  
    while( iPrimDim >= 0 && iScndDim < iWidth ) //!< 設置矩陣中某一條反對角線上(左下到右上)的元素的序號   
    {//!< pBuffTemp賦值的原理:iPrimDim控制當前掃描到的元素的行數,iiScndDim控制該元素在反對角線上的序號  
      pBuffTemp[ uiNextScanPos ] = iPrimDim * iWidth + iScndDim ;  
      uiNextScanPos++;  
      iScndDim++;  
      iPrimDim--;  
    }  
  }  
  }  
  if( iWidth > 4 )  
  {  
    UInt uiNumBlkSide = iWidth >> 2;                      //!< 以4x4像素爲一個單元  
    UInt uiNumBlks    = uiNumBlkSide * uiNumBlkSide; //!< 單元數  
    UInt log2Blk      = g_aucConvertToBit[ uiNumBlkSide ] + 1;  
  
    for( UInt uiBlk = 0; uiBlk < uiNumBlks; uiBlk++ )  
    {  
      uiNextScanPos   = 0;  
      UInt initBlkPos = g_auiSigLastScan[ SCAN_DIAG ][ log2Blk ][ uiBlk ]; //!< 以4x4塊爲單元的位置(序號)    
      if( iWidth == 32 )  
      {  
        initBlkPos = g_sigLastScanCG32x32[ uiBlk ]; //!< TU爲32x32時,不會再在16個4x4塊中進行up-right diamond掃描,而直接在整一個32x32中以4x4塊爲單元進行掃描  
      }  
      UInt offsetY    = initBlkPos / uiNumBlkSide;                  //!< 當前4x4塊垂直方向的偏移量  
      UInt offsetX    = initBlkPos - offsetY * uiNumBlkSide;    //!< 當前4x4塊水平方向的偏移量  
      UInt offsetD    = 4 * ( offsetX + offsetY * iWidth );     //!< 當前4x4塊第一個位置序號  
      UInt offsetScan = 16 * uiBlk; //!< 每一個4x4塊包含了16個像素(即係數),用於給出當前4x4塊第一個位置相對於第1個4x4塊第一個位置的偏移量  
      for( UInt uiScanLine = 0; uiNextScanPos < 16; uiScanLine++ ) //!< 對每個4x4塊進行掃描順序的確定    
      {  
        Int    iPrimDim  = Int( uiScanLine );  
        Int    iScndDim  = 0;  
        while( iPrimDim >= 4 ) //!< 則根據該反對角線與反主對角線的距離,距離每增加1,則總元素數減1  
        {  
          iScndDim++;  
          iPrimDim--;  
        }  
        while( iPrimDim >= 0 && iScndDim < 4 ) //!< 設置矩陣中某一條反對角線上(左下到右上)的元素的序號   
        {  
          pBuffD[ uiNextScanPos + offsetScan ] = iPrimDim * iWidth + iScndDim + offsetD;  
          uiNextScanPos++;  
          iScndDim++;  
          iPrimDim--;  
        }  
      }  
    }  
  }  
    
  UInt uiCnt = 0;  
  if( iWidth > 2 )  
  {//!< 水平掃描模式  
    UInt numBlkSide = iWidth >> 2;    
    for(Int blkY=0; blkY < numBlkSide; blkY++) //!< 以4x4塊爲單元,行優先  
    {  
      for(Int blkX=0; blkX < numBlkSide; blkX++)  
      {  
        UInt offset    = blkY * 4 * iWidth + blkX * 4; //!< 確定當前4x4塊的第一個位置序號  
        for(Int y=0; y < 4; y++) //!< 對每個4x4塊中的16個位置進行遍歷,行優先  
        {  
          for(Int x=0; x < 4; x++)  
          {  
            pBuffH[uiCnt] = y*iWidth + x + offset;  
            uiCnt ++;  
          }  
        }  
      }  
    }  
    //!< 垂直掃描模式  
    uiCnt = 0;  
    for(Int blkX=0; blkX < numBlkSide; blkX++) //!< 以4x4塊爲單元,列優先  
    {  
      for(Int blkY=0; blkY < numBlkSide; blkY++)  
      {  
        UInt offset    = blkY * 4 * iWidth + blkX * 4;  
        for(Int x=0; x < 4; x++) //!< //!< 對每個4x4塊中的16個位置進行遍歷,行優先  
        {  
          for(Int y=0; y < 4; y++)  
          {  
            pBuffV[uiCnt] = y*iWidth + x + offset;  
            uiCnt ++;  
          }  
        }  
      } //!< for(Int blkY=0; blkY < numBlkSide; blkY++)         
    } //!< for(Int blkX=0; blkX < numBlkSide; blkX++)       
  } //!< if( iWidth > 2 )     
  else  //!< if( iWidth <= 2 )  
  { //!< Horizontal scan pattern  
  for(Int iY=0; iY < iHeight; iY++)  
  {  
    for(Int iX=0; iX < iWidth; iX++)  
    {  
      pBuffH[uiCnt] = iY*iWidth + iX;  
      uiCnt ++;  
    }  
  }  
  
  //!< Vertical scan pattern  
  uiCnt = 0;  
  for(Int iX=0; iX < iWidth; iX++)  
  {  
    for(Int iY=0; iY < iHeight; iY++)  
    {  
      pBuffV[uiCnt] = iY*iWidth + iX;  
      uiCnt ++;  
    }  
  }      
  } //!< else //!< if( iWidth <= 2 )  
}  

4x4內部自然只能以像素爲單位進行掃描了,按照規定的三種pattern之一進行掃描。更大的塊,則是以4x4塊爲單位掃描的,這也可以理解爲一個遞歸的過程。規定的三種掃描方式:4*4塊內一個掃描順序,塊之間也是一個掃描順序。初始化三種順序的時候,要分if (iWidth > 4),if(iWidth > 2)
還詳細解析係數的文檔。就是說明:coeff_abs_level_greater1_flag[n], coeff_abs_level_greater2_flag[ n ]等的文檔:"Transform Coefficient Coding in HEVC"

發佈了20 篇原創文章 · 獲贊 21 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章