Apprentissage de la technologie H.266 / VVC: technologie Joint Chroma Coding (JCCR)

VVC prend en charge le codage conjoint du mode de chrominance résiduelle (JCCR).

L'utilisation (activation) du mode de codage de joint chroma est indiquée par l'indicateur de niveau TU tu_joint_cbcr_residual_flag , et le mode sélectionné est implicitement indiqué par les CBF de chrominance. Si un ou les deux CBF de chrominance d'une TU sont égaux à 1 (tu_cbf_cb ou tu_cbf_cr), il existe un indicateur tu_joint_cbcr_residual_flag .

Dans le PPS et la tête de coupe, la valeur de décalage QP de chrominance dans le mode de codage résiduel de chrominance conjointe est différente de la valeur de décalage QP de chrominance dans le mode de codage résiduel de chrominance conventionnel. Ces valeurs de décalage QP de chrominance sont utilisées pour dériver la valeur QP de chrominance de le bloc codé en utilisant le mode de codage résiduel de chrominance articulaire.

Le mode JCCR a 3 sous-modes. Lorsque le mode de codage de chrominance conjoint correspondant (mode 2 dans le tableau) est activé dans la TU, lorsque la TU est quantifiée et décodée, le décalage QP de chrominance est ajouté à la chrominance dérivée de la luminance appliquée QP (la chrominance dérivée de la luminance appliquée QP ). Pour les autres modes (mode 1 et mode 3 dans le tableau), la méthode de dérivation de la chrominance QPs est la même que celle des blocs Cb ou Cr classiques.

Le processus de reconstruction du résidu de chrominance (resCb et resCr) du bloc de transformation de transmission est indiqué dans le tableau. Lorsque le mode JCCR est activé, un bloc résiduel de chrominance joint (resJointC [x] [y] est passé, puis en considérant diverses informations (telles que tu_cbf_cb tu_cbf_cr, CSign), le bloc résiduel Cb (resCb) et le bloc différentiel résiduel Cr (resCr).

Du côté du codeur, la composante de chrominance conjointe est calculée comme suit. Selon le mode (comme indiqué dans le tableau ci-dessus), l'encodeur génère resJointC {1,2} comme suit:

Si mode = 2 (résidu unique Cb = C, Cr = CSign * C après reconstruction), alors selon

   -resJointC [x] [y] = (resCb [x] [y] + CSign * resCr [x] [y]) / 2.

Sinon, si mode = 1 (le résidu unique reconstruit Cb = C, Cr = (CSign * C) / 2), alors selon

   -resJointC [x] [y] = (4 * resCb [x] [y] + 2 * CSign * resCr [x] [y]) / 5.

Sinon (mode = 3, le résidu unique reconstruit Cr = C, Cb = (CSign * C) / 2), selon

   -resJointC [x] [y] = (4 * resCr [x] [y] + 2 * CSign * resCb [x] [y]) / 5.

 

tu_cbf_cb

tu_cbf_cr

reconstruction des résidus Cb et Cr

mode

1

0

resCb [x] [y] = resJointC [x] [y]
resCr [x] [y] = (CSign * resJointC [x] [y]) >> 1

1

1

1

resCb [x] [y] = resJointC [x] [y]
resCr [x] [y] = CSign * resJointC [x] [y]

2

0

1

resCb [x] [y] = (CSign * resJointC [x] [y]) >> 1
resCr [x] [y] = resJointC [x] [y]

3

Les trois modes de codage de chrominance conjoints ci-dessus ne sont pris en charge que sur la puce I. Dans les films P et B, seul le mode 2 est pris en charge. Par conséquent, dans les tranches P et B, l'élément de syntaxe tu_joint_cbcr_residual_flag n'existe que lorsque les chroma cbfs sont tous les deux 1 (c'est-à-dire tu_cbf_cb = 1 et tu_cbf_cr = 1).

Le mode JCCR peut être combiné avec le mode Transform Skip (TS). Afin d'accélérer la vitesse de sélection de l'extrémité de codage, le choix de la transformée JCCR dépend du fait que le codage indépendant des composantes Cb et Cr sélectionne DCT-2 ou TS comme meilleure transformée, et s'il existe des coefficients non nuls. dans le codage de chrominance indépendant. Spécifiquement divisé en deux situations:

(1) Lorsque les composants Cb et Cr utilisent DCT-2 ou lorsqu'un seul composant de chrominance (Cb ou Cr) a un coefficient différent de zéro et que le composant de chrominance sélectionne DCT-2, le mode JCCR ne vérifie que DCT-2. De même, lorsque les composants Cb et Cr utilisent TS, ou lorsqu'un seul composant chroma a un coefficient différent de zéro et que le composant sélectionne TS, le mode JCCR ne vérifie que TS.

(2) Lorsque les transformations sélectives des composants Cb et Cr sont différentes, c'est-à-dire quand l'un choisit DCT-2 et l'autre choisit TS ou vice versa, JCCR teste à la fois DCT-2 et TS. Dans ces cas, le contrôle RD du mode DCT-2 est effectué avant le mode TS, et si les coefficients de DCT-2 sont tous nuls, le contrôle TS RD est ignoré.

TrQuant::TrQuant() : m_quant( nullptr )
{
  // allocate temporary buffers

  {
    m_invICT      = m_invICTMem + maxAbsIctMode;
    m_invICT[ 0]  = invTransformCbCr< 0>;
    m_invICT[ 1]  = invTransformCbCr< 1>;
    m_invICT[-1]  = invTransformCbCr<-1>;
    m_invICT[ 2]  = invTransformCbCr< 2>;
    m_invICT[-2]  = invTransformCbCr<-2>;
    m_invICT[ 3]  = invTransformCbCr< 3>;
    m_invICT[-3]  = invTransformCbCr<-3>;
    m_fwdICT      = m_fwdICTMem + maxAbsIctMode;
    m_fwdICT[ 0]  = fwdTransformCbCr< 0>;
    m_fwdICT[ 1]  = fwdTransformCbCr< 1>;
    m_fwdICT[-1]  = fwdTransformCbCr<-1>;
    m_fwdICT[ 2]  = fwdTransformCbCr< 2>;
    m_fwdICT[-2]  = fwdTransformCbCr<-2>;
    m_fwdICT[ 3]  = fwdTransformCbCr< 3>;
    m_fwdICT[-3]  = fwdTransformCbCr<-3>;
  }
}

La fonction invTransformCbCr est la suivante, la fonction est principalement d'obtenir le résidu Cr (Cb) par le résidu Cb (Cr)

template<int signedMode> void invTransformCbCr( PelBuf &resCb, PelBuf &resCr )
{
  Pel*  cb  = resCb.buf;
  Pel*  cr  = resCr.buf;
  for( SizeType y = 0; y < resCb.height; y++, cb += resCb.stride, cr += resCr.stride )
  {
    for( SizeType x = 0; x < resCb.width; x++ )
    {
      if      ( signedMode ==  1 )  { cr[x] =  cb[x] >> 1;  }
      else if ( signedMode == -1 )  { cr[x] = -cb[x] >> 1;  }
      else if ( signedMode ==  2 )  { cr[x] =  cb[x]; }
      else if ( signedMode == -2 )  { cr[x] = (cb[x] == -32768 && sizeof(Pel) == 2) ? 32767 : -cb[x]; }   // non-normative clipping to prevent 16-bit overflow
      else if ( signedMode ==  3 )  { cb[x] =  cr[x] >> 1; }
      else if ( signedMode == -3 )  { cb[x] = -cr[x] >> 1; }
    }
  }
}

La fonction fwdTransformCbCr consiste à trouver ResJointC via ResCb et ResCr

template<int signedMode> std::pair<int64_t,int64_t> fwdTransformCbCr( const PelBuf &resCb, const PelBuf &resCr, PelBuf& resC1, PelBuf& resC2 )
{
  const Pel*  cb  = resCb.buf;
  const Pel*  cr  = resCr.buf;
  Pel*        c1  = resC1.buf;
  Pel*        c2  = resC2.buf;
  int64_t     d1  = 0;
  int64_t     d2  = 0;
  for( SizeType y = 0; y < resCb.height; y++, cb += resCb.stride, cr += resCr.stride, c1 += resC1.stride, c2 += resC2.stride )
  {
    for( SizeType x = 0; x < resCb.width; x++ )
    {
      int cbx = cb[x], crx = cr[x];
      if      ( signedMode ==  1 )
      {
        c1[x] = Pel( ( 4*cbx + 2*crx ) / 5 );
        d1   += square( cbx - c1[x] ) + square( crx - (c1[x]>>1) );
      }
      else if ( signedMode == -1 )
      {
        c1[x] = Pel( ( 4*cbx - 2*crx ) / 5 );
        d1   += square( cbx - c1[x] ) + square( crx - (-c1[x]>>1) );
      }
      else if ( signedMode ==  2 )
      {
        c1[x] = Pel( ( cbx + crx ) / 2 );
        d1   += square( cbx - c1[x] ) + square( crx - c1[x] );
      }
      else if ( signedMode == -2 )
      {
        c1[x] = Pel( ( cbx - crx ) / 2 );
        d1   += square( cbx - c1[x] ) + square( crx + c1[x] );
      }
      else if ( signedMode ==  3 )
      {
        c2[x] = Pel( ( 4*crx + 2*cbx ) / 5 );
        d1   += square( cbx - (c2[x]>>1) ) + square( crx - c2[x] );
      }
      else if ( signedMode == -3 )
      {
        c2[x] = Pel( ( 4*crx - 2*cbx ) / 5 );
        d1   += square( cbx - (-c2[x]>>1) ) + square( crx - c2[x] );
      }
      else
      {
        d1   += square( cbx );
        d2   += square( crx );
      }
    }
  }
  return std::make_pair(d1,d2);
}

 

Je suppose que tu aimes

Origine blog.csdn.net/BigDream123/article/details/106267476
conseillé
Classement