H.266/VVC code learning: initialization block scan sequence

The block scanning sequence of H.266/VVC includes diagonal scanning, horizontal scanning and vertical scanning sequence (take 4x4 block as an example)

/// coefficient scanning type used in ACS
//  系数扫描类型
enum CoeffScanType
{
  SCAN_DIAG = 0,        ///< up-right diagonal scan 对角扫描
  SCAN_TRAV_HOR = 1,    // 水平扫描
  SCAN_TRAV_VER = 2,    // 垂直扫描
  SCAN_NUMBER_OF_TYPES
};

 When scanning, it is divided into whole block scanning and sub-block scanning:

enum CoeffScanGroupType
{
  SCAN_UNGROUPED   = 0,//整块扫描
  SCAN_GROUPED_4x4 = 1,//子块扫描
  SCAN_NUMBER_OF_GROUP_TYPES = 2
};

For scanning according to sub-blocks, the width and height of sub-block scanning of transform blocks of each size are shown in the following table, where the value of N is 1 2 4 8 16 32 64 128.

uint32_t g_log2SbbSize[MAX_CU_DEPTH + 1][MAX_CU_DEPTH + 1][2] =
//===== luma/chroma =====
{
  { { 0,0 },{ 0,1 },{ 0,2 },{ 0,3 },{ 0,4 },{ 0,4 },{ 0,4 },{ 0,4 } },//1xN
  { { 1,0 },{ 1,1 },{ 1,1 },{ 1,3 },{ 1,3 },{ 1,3 },{ 1,3 },{ 1,3 } },//2xN
  { { 2,0 },{ 1,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } },//4xN
  { { 3,0 },{ 3,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } },//8xN
  { { 4,0 },{ 3,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } },//16xN
  { { 4,0 },{ 3,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } },//32xN
  { { 4,0 },{ 3,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } },//64xN
  { { 4,0 },{ 3,1 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 },{ 2,2 } } //128xN
};

For convenience, all scan orders in the VTM code are pre-stored in the g_scanOrder variable, as shown below. For each scan type, the ScanElement variable is used. Where idx represents the raster scan position of the current pixel in the block, and (x, y) represents the corresponding position of the current pixel in the block.

// flexible conversion from relative to absolute index
struct ScanElement
{
  uint32_t idx;
  uint16_t x;
  uint16_t y;
};
ScanElement *g_scanOrder[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1];

 VTM stores the idx, x, and y of the corresponding position in g_scanOrder according to each scan order (the scan order is the storage order). For sub-block scanning, the order between the sub-blocks is also determined according to the corresponding scanning order. Take the 8x8 diagonal scanning sequence as an example, as shown in the figure below (this scanning sequence is also the diagonal scanning sequence corresponding to 8x8LFNST)

void initROM()
{
  gp_sizeIdxInfo = new SizeIndexInfoLog2();
  gp_sizeIdxInfo->init(MAX_CU_SIZE);

  //初始化m_sizeToIdxTab 1 2 4 8 16 32 64 128
  //初始化m_idxToSizeTab 0 1 2 3 4  5  6  7
  SizeIndexInfoLog2 sizeInfo;
  sizeInfo.init(MAX_CU_SIZE);

  // initialize scan orders
  // 初始化扫描顺序
  // blockHeightIdx和blockWidthIdx为m_idxToSizeTab中的值
  for (uint32_t blockHeightIdx = 0; blockHeightIdx < sizeInfo.numAllHeights(); blockHeightIdx++)
  {
    for (uint32_t blockWidthIdx = 0; blockWidthIdx < sizeInfo.numAllWidths(); blockWidthIdx++)
    {
      const uint32_t blockWidth  = sizeInfo.sizeFrom(blockWidthIdx);
      const uint32_t blockHeight = sizeInfo.sizeFrom(blockHeightIdx);
      const uint32_t totalValues = blockWidth * blockHeight;

      //--------------------------------------------------------------------------------------------------

      //non-grouped scan orders
      //整块扫描顺序
      //遍历扫描类型:对角扫描、水平扫描和垂直扫描顺序
      for (uint32_t scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++)
      {
        const CoeffScanType scanType = CoeffScanType(scanTypeIndex);
        ScanElement *       scan     = nullptr;

        if (blockWidthIdx < sizeInfo.numWidths() && blockHeightIdx < sizeInfo.numHeights())
        {
          scan = new ScanElement[totalValues];
        }

        g_scanOrder[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = scan;

        if (scan == nullptr)
        {
          continue;
        }

        ScanGenerator fullBlockScan(blockWidth, blockHeight, blockWidth, scanType);
        //按照扫描顺序存储在scan数组中
        //idx表示像素位置的光栅扫描位置
        //x和y分别表示像素在块中的位置
        for (uint32_t scanPosition = 0; scanPosition < totalValues; scanPosition++)
        {
          const int rasterPos = fullBlockScan.GetNextIndex( 0, 0 );
          const int posY      = rasterPos / blockWidth;
          const int posX      = rasterPos - ( posY * blockWidth );

          scan[scanPosition].idx = rasterPos;
          scan[scanPosition].x   = posX;
          scan[scanPosition].y   = posY;
        }
      }

      //--------------------------------------------------------------------------------------------------

      //grouped scan orders
      //子块扫描顺序
      //由于存在高频调零技术,子块扫描的时候对于尺寸为64的块仅扫描前32行/列的数据
      const uint32_t* log2Sbb        = g_log2SbbSize[floorLog2(blockWidth)][floorLog2(blockHeight)];
      const uint32_t  log2CGWidth    = log2Sbb[0];
      const uint32_t  log2CGHeight   = log2Sbb[1];

      const uint32_t  groupWidth     = 1 << log2CGWidth;//子块宽
      const uint32_t  groupHeight    = 1 << log2CGHeight;//子块高
      const uint32_t  widthInGroups = std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, blockWidth) >> log2CGWidth;
      const uint32_t  heightInGroups = std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, blockHeight) >> log2CGHeight;

      const uint32_t  groupSize      = groupWidth    * groupHeight;//子块尺寸
      const uint32_t  totalGroups    = widthInGroups * heightInGroups;//子块总数
      //遍历扫描类型:对角、水平和垂直扫描
      for (uint32_t scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++)
      {
        const CoeffScanType scanType = CoeffScanType(scanTypeIndex);

        ScanElement *scan = new ScanElement[totalValues];

        g_scanOrder[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = scan;

        if ( blockWidth > JVET_C0024_ZERO_OUT_TH || blockHeight > JVET_C0024_ZERO_OUT_TH )
        {
          for (uint32_t i = 0; i < totalValues; i++)
          {
            scan[i].idx = totalValues - 1;
            scan[i].x   = blockWidth - 1;
            scan[i].y   = blockHeight - 1;
          }
        }

        ScanGenerator fullBlockScan(widthInGroups, heightInGroups, groupWidth, scanType);

        for (uint32_t groupIndex = 0; groupIndex < totalGroups; groupIndex++)
        {
          const uint32_t groupPositionY  = fullBlockScan.GetCurrentY();
          const uint32_t groupPositionX  = fullBlockScan.GetCurrentX();
          const uint32_t groupOffsetX    = groupPositionX * groupWidth;
          const uint32_t groupOffsetY    = groupPositionY * groupHeight;
          const uint32_t groupOffsetScan = groupIndex     * groupSize;

          ScanGenerator groupScan(groupWidth, groupHeight, blockWidth, scanType);

          for (uint32_t scanPosition = 0; scanPosition < groupSize; scanPosition++)
          {
            const int rasterPos = groupScan.GetNextIndex( groupOffsetX, groupOffsetY );
            const int posY      = rasterPos / blockWidth;
            const int posX      = rasterPos - ( posY * blockWidth );

            scan[groupOffsetScan + scanPosition].idx = rasterPos;
            scan[groupOffsetScan + scanPosition].x   = posX;
            scan[groupOffsetScan + scanPosition].y   = posY;
          }

          fullBlockScan.GetNextIndex(0, 0);
        }
      }

      //--------------------------------------------------------------------------------------------------
    }
  }

  // initialize CoefTopLeftDiagScan8x8 for LFNST
  // 初始化LFNST的左上角8x8块的对角扫描顺序
  for( uint32_t blockWidthIdx = 0; blockWidthIdx < sizeInfo.numAllWidths(); blockWidthIdx++ )
  {
    const uint32_t blockWidth = sizeInfo.sizeFrom( blockWidthIdx );

    const static uint8_t g_auiXYDiagScan8x8[ 64 ][ 2 ] =
    {
      { 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, 2 }, { 1, 1 }, { 2, 0 }, { 0, 3 }, { 1, 2 },
      { 2, 1 }, { 3, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 }, { 2, 3 }, { 3, 2 }, { 3, 3 },
      { 0, 4 }, { 0, 5 }, { 1, 4 }, { 0, 6 }, { 1, 5 }, { 2, 4 }, { 0, 7 }, { 1, 6 },
      { 2, 5 }, { 3, 4 }, { 1, 7 }, { 2, 6 }, { 3, 5 }, { 2, 7 }, { 3, 6 }, { 3, 7 },
      { 4, 0 }, { 4, 1 }, { 5, 0 }, { 4, 2 }, { 5, 1 }, { 6, 0 }, { 4, 3 }, { 5, 2 },
      { 6, 1 }, { 7, 0 }, { 5, 3 }, { 6, 2 }, { 7, 1 }, { 6, 3 }, { 7, 2 }, { 7, 3 },
      { 4, 4 }, { 4, 5 }, { 5, 4 }, { 4, 6 }, { 5, 5 }, { 6, 4 }, { 4, 7 }, { 5, 6 },
      { 6, 5 }, { 7, 4 }, { 5, 7 }, { 6, 6 }, { 7, 5 }, { 6, 7 }, { 7, 6 }, { 7, 7 }
    };
    for( int i = 0; i < 64; i++ )
    {
      g_coefTopLeftDiagScan8x8[ blockWidthIdx ][ i ].idx = g_auiXYDiagScan8x8[ i ][ 0 ] + g_auiXYDiagScan8x8[ i ][ 1 ] * blockWidth;
      g_coefTopLeftDiagScan8x8[ blockWidthIdx ][ i ].x   = g_auiXYDiagScan8x8[ i ][ 0 ];
      g_coefTopLeftDiagScan8x8[ blockWidthIdx ][ i ].y   = g_auiXYDiagScan8x8[ i ][ 1 ];
    }
  }

#if !JVET_Q0806
  for( int idxH = MAX_CU_DEPTH - MIN_CU_LOG2; idxH >= 0; --idxH )
  {
    for( int idxW = MAX_CU_DEPTH - MIN_CU_LOG2; idxW >= 0; --idxW )
    {
      int numW   = 1 << idxW;
      int numH   = 1 << idxH;
      int ratioW = std::max( 0, idxW - idxH );
      int ratioH = std::max( 0, idxH - idxW );
      int sum    = std::max( (numW >> ratioW), (numH >> ratioH) ) - 1;
      for( int y = 0; y < numH; y++ )
      {
        int idxY = y >> ratioH;
        for( int x = 0; x < numW; x++ )
        {
          int idxX = x >> ratioW;
          g_triangleMvStorage[TRIANGLE_DIR_135][idxH][idxW][y][x] = (idxX == idxY) ? 2 : (idxX > idxY ? 0 : 1);
          g_triangleMvStorage[TRIANGLE_DIR_45][idxH][idxW][y][x] = (idxX + idxY == sum) ? 2 : (idxX + idxY > sum ? 1 : 0);
        }
      }
    }
  }

  for (int idxH = 0; idxH < MAX_CU_DEPTH - MIN_CU_LOG2 + 2; ++idxH)
  {
    for (int idxW = 0; idxW < MAX_CU_DEPTH - MIN_CU_LOG2 + 2; ++idxW)
    {
      const int nCbH = 1 << (idxH + 1);
      const int nCbW = 1 << (idxW + 1);
      const int nCbR = (nCbW > nCbH) ? nCbW / nCbH : nCbH / nCbW;

      // let SIMD can read at least 64-bit when at last row
      g_triangleWeights[0][idxH][idxW] = new int16_t[nCbH * nCbW + 4];
      g_triangleWeights[1][idxH][idxW] = new int16_t[nCbH * nCbW + 4];
      for (int y = 0; y < nCbH; y++)
      {
        for (int x = 0; x < nCbW; x++)
        {
          g_triangleWeights[0][idxH][idxW][y*nCbW + x] = (nCbW > nCbH) ? Clip3(0, 8, x / nCbR - y + 4) : Clip3(0, 8, x - y / nCbR + 4);
          g_triangleWeights[1][idxH][idxW][y*nCbW + x] = (nCbW > nCbH) ? Clip3(0, 8, nCbH - 1 - x / nCbR - y + 4) : Clip3(0, 8, nCbW - 1 - x - y / nCbR + 4);
        }
      }
    }
  }
#else
  initGeoTemplate();
#endif

  ::memset(g_isReusedUniMVsFilled, 0, sizeof(g_isReusedUniMVsFilled));

#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
  for (int qp = 0; qp < 57; qp++)
  {
    int qpRem = (qp + 12) % 6;
    int qpPer = (qp + 12) / 6;
    int quantiserScale = g_quantScales[0][qpRem];
    int quantiserRightShift = QUANT_SHIFT + qpPer;
    double threshQP = ((double)(1 << quantiserRightShift)) / quantiserScale;
    g_paletteQuant[qp] = (int)(threshQP*0.16 + 0.5);
  }
#endif
}

 

Guess you like

Origin blog.csdn.net/BigDream123/article/details/106358632