Aprendizagem de tecnologia H.266 / VVC: tecnologia Joint Chroma Coding (JCCR)

O VVC oferece suporte à codificação conjunta do modo de croma residual (JCCR).

O uso (ativação) do modo de codificação de junção de croma é indicado pelo sinalizador de nível TU tu_joint_cbcr_residual_flag e o modo selecionado é implicitamente indicado pelos CBFs de croma. Se um ou ambos os CBFs de crominância de uma TU forem iguais a 1 (tu_cbf_cb ou tu_cbf_cr), há um sinalizador tu_joint_cbcr_residual_flag .

No PPS e no cabeçote de fatia, o valor de compensação QP de crominância no modo de codificação residual de crominância conjunta é diferente do valor de compensação QP de crominância no modo de codificação residual de crominância convencional. Esses valores de compensação QP de crominância são usados ​​para derivar o valor QP de crominância de o bloco codificado usando o modo de codificação residual de crominância conjunta.

O modo JCCR possui 3 submodos. Quando o modo de codificação de crominância conjunta correspondente (modo 2 na tabela) é ativado na TU, quando a TU é quantizada e decodificada, o deslocamento de QP de crominância é adicionado à crominância derivada de luminância aplicada QP (a croma derivada de luma aplicada QP ) Para outros modos (modo 1 e modo 3 na tabela), o método de derivação dos QPs de crominância é o mesmo dos blocos convencionais Cb ou Cr.

O processo de reconstrução do resíduo de crominância (resCb e resCr) do bloco de transformação de transmissão é mostrado na tabela. Quando o modo JCCR é ativado, um bloco residual de crominância conjunta (resJointC [x] [y] é passado e, em seguida, considerando várias informações (como tu_cbf_cb tu_cbf_cr, CSign), o bloco residual Cb (resCb) e o bloco de diferença residual Cr (resCr).

No lado do codificador, o componente de crominância da junta é derivado como segue. De acordo com o modo (conforme mostrado na tabela acima), o codificador gera resJointC {1,2} da seguinte maneira:

Se modo = 2 (único residual Cb = C, Cr = CSign * C após a reconstrução), então de acordo com

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

Caso contrário, se modo = 1 (o único residual reconstruído Cb = C, Cr = (CSign * C) / 2), então de acordo com

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

Caso contrário (modo = 3, o único residual reconstruído Cr = C, Cb = (CSign * C) / 2), de acordo com

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

 

tu_cbf_cb

tu_cbf_cr

reconstrução de resíduos de Cb e Cr

modo

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

Os três modos de codificação de croma conjunta acima são suportados apenas no I-chip. Em filmes P e B, apenas o modo 2 é compatível. Portanto, em fatias P e B, o elemento de sintaxe tu_joint_cbcr_residual_flag só existe quando os cbfs de croma são 1 (ou seja, tu_cbf_cb = 1 e tu_cbf_cr = 1).

O modo JCCR pode ser combinado com o modo Transform Skip (TS). A fim de acelerar a velocidade de seleção da extremidade de codificação, a escolha da transformação JCCR depende se a codificação independente dos componentes Cb e Cr seleciona DCT-2 ou TS como a melhor transformação, e se há coeficientes diferentes de zero na codificação de crominância independente. Especificamente dividido nas duas situações a seguir:

(1) Quando os componentes Cb e Cr usam DCT-2 ou quando apenas um componente de crominância (Cb ou Cr) tem um coeficiente diferente de zero e o componente de crominância seleciona DCT-2, o modo JCCR verifica apenas DCT-2. Da mesma forma, quando os componentes Cb e Cr usam TS, ou quando apenas um componente de croma tem um coeficiente diferente de zero e o componente seleciona TS, o modo JCCR verifica apenas TS.

(2) Quando as transformações seletivas dos componentes Cb e Cr são diferentes, ou seja, quando um escolhe DCT-2 e o outro escolhe TS ou vice-versa, o JCCR testa tanto o DCT-2 quanto o TS. Nestes casos, a verificação RD do modo DCT-2 é executada antes do modo TS e, se os coeficientes do DCT-2 forem todos zero, a verificação TS RD é ignorada.

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

A função invTransformCbCr é a seguinte, a função é principalmente para obter o residual Cr (Cb) através do residual 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; }
    }
  }
}

A função fwdTransformCbCr é encontrar ResJointC por meio de ResCb e 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);
}

 

Acho que você gosta

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