Aprendizaje de código H.266 / VVC: secuencia de exploración del bloque de inicialización

La secuencia de exploración de bloques de H.266 / VVC incluye exploración diagonal, exploración horizontal y secuencia de exploración vertical (tome el bloque 4x4 como ejemplo)

/// 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
};

 Al escanear, se divide en escaneo de bloque completo y escaneo de subbloque:

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

Para el escaneo según sub-bloques, el ancho y alto del escaneo del sub-bloque de bloques de transformación de cada tamaño se muestran en la siguiente tabla, donde el valor de N es 1 2 4 8 16 32 64128.

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
};

Para mayor comodidad, todas las órdenes de escaneo en el código VTM se almacenan previamente en la variable g_scanOrder, como se muestra a continuación. Para cada tipo de análisis, se utiliza la variable ScanElement. Donde idx representa la posición de exploración de trama del píxel actual en el bloque, y (x, y) representa la posición correspondiente del píxel actual en el bloque.

// 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 almacena el idx, xey de la posición correspondiente en g_scanOrder de acuerdo con cada orden de escaneo (el orden de escaneo es el orden de almacenamiento). Para el escaneo de sub-bloques, el orden entre los sub-bloques también se determina de acuerdo con el orden de escaneo correspondiente. Tome la secuencia de escaneo diagonal de 8x8 como ejemplo, como se muestra en la figura siguiente (esta secuencia de escaneo es también la secuencia de escaneo diagonal correspondiente hasta 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
}

 

Supongo que te gusta

Origin blog.csdn.net/BigDream123/article/details/106358632
Recomendado
Clasificación