VTM10.0反量化反变换技术
Posted 神遁克里苏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTM10.0反量化反变换技术相关的知识,希望对你有一定的参考价值。
void TrQuant::invTransformNxN( TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQP )
{//反量化与反变换
const CompArea &area = tu.blocks[compID];
const uint32_t uiWidth = area.width;
const uint32_t uiHeight = area.height;
CHECK( uiWidth > tu.cs->sps->getMaxTbSize() || uiHeight > tu.cs->sps->getMaxTbSize(), "Maximal allowed transformation size exceeded!" );
CoeffBuf tempCoeff = CoeffBuf(m_tempCoeff, area);
xDeQuant(tu, tempCoeff, compID, cQP);//进行反量化
DTRACE_COEFF_BUF(D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID);
if (tu.cs->sps->getUseLFNST())//如果使用了LFNST,则进行反LFNST
{
xInvLfnst(tu, compID);
}
if (tu.mtsIdx[compID] == MTS_SKIP)//如果MTS跳过
{
xITransformSkip(tempCoeff, pResi, tu, compID);//则不用进行反变换,直接就是resi
}
else
{
xIT(tu, compID, tempCoeff, pResi);//反MTS变换
}
//DTRACE_BLOCK_COEFF(tu.getCoeffs(compID), tu, tu.cu->predMode, compID);
DTRACE_PEL_BUF( D_RESIDUALS, pResi, tu, tu.cu->predMode, compID);
}
xDeQuant进入反量化
void TrQuant::xDeQuant(const TransformUnit &tu,
CoeffBuf &dstCoeff,
const ComponentID &compID,
const QpParam &cQP)
{
m_quant->dequant( tu, dstCoeff, compID, cQP );
}
dequant中执行反量化的步骤
void DepQuant::dequant( const TransformUnit &tu, CoeffBuf &dstCoeff, const ComponentID &compID, const QpParam &cQP )
{
const bool useRegularResidualCoding = tu.cu->slice->getTSResidualCodingDisabledFlag() || tu.mtsIdx[compID] != MTS_SKIP;
if( tu.cs->slice->getDepQuantEnabledFlag() && useRegularResidualCoding )
{//反DQ
const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1;
const int qpPer = qpDQ / 6;
const int qpRem = qpDQ - 6 * qpPer;
const CompArea &rect = tu.blocks[compID];
const int width = rect.width;
const int height = rect.height;
uint32_t scalingListType = getScalingListType(tu.cu->predMode, compID);
CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list");
const uint32_t log2TrWidth = floorLog2(width);
const uint32_t log2TrHeight = floorLog2(height);
const bool disableSMForLFNST = tu.cs->slice->getExplicitScalingListUsed() ? tu.cs->slice->getSPS()->getDisableScalingMatrixForLfnstBlks() : false;
const bool isLfnstApplied = tu.cu->lfnstIdx > 0 && (tu.cu->isSepTree() ? true : isLuma(compID));
const bool disableSMForACT = tu.cs->slice->getSPS()->getScalingMatrixForAlternativeColourSpaceDisabledFlag() && (tu.cs->slice->getSPS()->getScalingMatrixDesignatedColourSpaceFlag() == tu.cu->colorTransform);
const bool enableScalingLists = getUseScalingList(width, height, (tu.mtsIdx[compID] == MTS_SKIP), isLfnstApplied, disableSMForLFNST, disableSMForACT);
static_cast<DQIntern::DepQuant*>(p)->dequant( tu, dstCoeff, compID, cQP, enableScalingLists, Quant::getDequantCoeff(scalingListType, qpRem, log2TrWidth, log2TrHeight) );
}
else
{//反RDOQ
QuantRDOQ::dequant( tu, dstCoeff, compID, cQP );
}
}
反量化结束后,进行反变换。
如果开启LFNST模式,则先lfnst反变换
void TrQuant::xInvLfnst( const TransformUnit &tu, const ComponentID compID )
{
#if JVET_R0351_HIGH_BIT_DEPTH_SUPPORT
const int maxLog2TrDynamicRange = tu.cs->sps->getMaxLog2TrDynamicRange(toChannelType(compID));
#endif
const CompArea& area = tu.blocks[ compID ];
const uint32_t width = area.width;
const uint32_t height = area.height;
const uint32_t lfnstIdx = tu.cu->lfnstIdx;
if( lfnstIdx && tu.mtsIdx[compID] != MTS_SKIP && (tu.cu->isSepTree() ? true : isLuma(compID)) )
{
const bool whge3 = width >= 8 && height >= 8;
const ScanElement * scan = whge3 ? g_coefTopLeftDiagScan8x8[ gp_sizeIdxInfo->idxFrom( width ) ] : g_scanOrder[ SCAN_GROUPED_4x4 ][ SCAN_DIAG ][ gp_sizeIdxInfo->idxFrom( width ) ][ gp_sizeIdxInfo->idxFrom( height ) ];
uint32_t intraMode = PU::getFinalIntraMode( *tu.cs->getPU( area.pos(), toChannelType( compID ) ), toChannelType( compID ) );
if( PU::isLMCMode( tu.cs->getPU( area.pos(), toChannelType( compID ) )->intraDir[ toChannelType( compID ) ] ) )
{//如果是CCLM模式,那么就获取中间的亮度块的模式
intraMode = PU::getCoLocatedIntraLumaMode( *tu.cs->getPU( area.pos(), toChannelType( compID ) ) );
}
if (PU::isMIP(*tu.cs->getPU(area.pos(), toChannelType(compID)), toChannelType(compID)))
{//如果是MIP模式,则变成planar模式
intraMode = PLANAR_IDX;
}
CHECK( intraMode >= NUM_INTRA_MODE - 1, "Invalid intra mode" );
if( lfnstIdx < 3 )
{
intraMode = getLFNSTIntraMode( PU::getWideAngle( tu, intraMode, compID ) );
#if RExt__DECODER_DEBUG_TOOL_STATISTICS
CodingStatistics::IncrementStatisticTool( CodingStatisticsClassType { STATS__TOOL_LFNST, width, height, compID } );
#endif
bool transposeFlag = getTransposeFlag( intraMode );
const int sbSize = whge3 ? 8 : 4;
//判断是使用4x4的还是8x8的
bool tu4x4Flag = ( width == 4 && height == 4 );
bool tu8x8Flag = ( width == 8 && height == 8 );
TCoeff* lfnstTemp;
TCoeff* coeffTemp;
int y;
lfnstTemp = m_tempInMatrix; // inverse spectral rearrangement
coeffTemp = m_tempCoeff;
TCoeff *dst = lfnstTemp;
const ScanElement *scanPtr = scan;
for (y = 0; y < 16; y++)
{
*dst++ = coeffTemp[scanPtr->idx];
scanPtr++;
}
#if JVET_R0351_HIGH_BIT_DEPTH_SUPPORT
//进行主要的LFNST
invLfnstNxN(m_tempInMatrix, m_tempOutMatrix, g_lfnstLut[intraMode], lfnstIdx - 1, sbSize,
(tu4x4Flag || tu8x8Flag) ? 8 : 16, maxLog2TrDynamicRange);
#else
invLfnstNxN(m_tempInMatrix, m_tempOutMatrix, g_lfnstLut[intraMode], lfnstIdx - 1, sbSize,
(tu4x4Flag || tu8x8Flag) ? 8 : 16);
#endif
lfnstTemp = m_tempOutMatrix; // inverse spectral rearrangement
if (transposeFlag)
{
if (sbSize == 4)
{
for (y = 0; y < 4; y++)
{
coeffTemp[0] = lfnstTemp[0];
coeffTemp[1] = lfnstTemp[4];
coeffTemp[2] = lfnstTemp[8];
coeffTemp[3] = lfnstTemp[12];
lfnstTemp++;
coeffTemp += width;
}
}
else // ( sbSize == 8 )
{
for (y = 0; y < 8; y++)
{
coeffTemp[0] = lfnstTemp[0];
coeffTemp[1] = lfnstTemp[8];
coeffTemp[2] = lfnstTemp[16];
coeffTemp[3] = lfnstTemp[24];
if (y < 4)
{
coeffTemp[4] = lfnstTemp[32];
coeffTemp[5] = lfnstTemp[36];
coeffTemp[6] = lfnstTemp[40];
coeffTemp[7] = lfnstTemp[44];
}
lfnstTemp++;
coeffTemp += width;
}
}
}
else
{
for (y = 0; y < sbSize; y++)
{
uint32_t uiStride = (y < 4) ? sbSize : 4;
::memcpy(coeffTemp, lfnstTemp, uiStride * sizeof(TCoeff));
lfnstTemp += uiStride;
coeffTemp += width;
}
}
}
}
}
//如果一次变换跳过,则反量化后(或是LFNST后)后的值就是resi
void TrQuant::xITransformSkip(const CCoeffBuf &pCoeff,
PelBuf &pResidual,
const TransformUnit &tu,
const ComponentID &compID)
{
const CompArea &area = tu.blocks[compID];
const int width = area.width;
const int height = area.height;
for (uint32_t y = 0; y < height; y++)
{
for (uint32_t x = 0; x < width; x++)
{
pResidual.at(x, y) = Pel(pCoeff.at(x, y));
}
}
}
如果不是MTS跳过,则进行反一次变换
void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pCoeff, PelBuf &pResidual )
{
const int width = pCoeff.width;
const int height = pCoeff.height;
const unsigned maxLog2TrDynamicRange = tu.cs->sps->getMaxLog2TrDynamicRange( toChannelType( compID ) );
const unsigned bitDepth = tu.cs->sps->getBitDepth( toChannelType( compID ) );
const int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE];
const TCoeff clipMinimum = -( 1 << maxLog2TrDynamicRange );
const TCoeff clipMaximum = ( 1 << maxLog2TrDynamicRange ) - 1;
const uint32_t transformWidthIndex = floorLog2(width ) - 1; // nLog2WidthMinus1, since transform start from 2-point
const uint32_t transformHeightIndex = floorLog2(height) - 1; // nLog2HeightMinus1, since transform start from 2-point
//先假定水平与垂直方向都是DCT2
int trTypeHor = DCT2;
int trTypeVer = DCT2;
//调用getTrTypes得到水平和垂直方向使用的变换核
getTrTypes ( tu, compID, trTypeHor, trTypeVer );
int skipWidth = ( trTypeHor != DCT2 && width == 32 ) ? 16 : width > JVET_C0024_ZERO_OUT_TH ? width - JVET_C0024_ZERO_OUT_TH : 0;
int skipHeight = ( trTypeVer != DCT2 && height == 32 ) ? 16 : height > JVET_C0024_ZERO_OUT_TH ? height - JVET_C0024_ZERO_OUT_TH : 0;
if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx )
{
if( (width == 4 && height > 4) || (width > 4 && height == 4) )
{
skipWidth = width - 4;
skipHeight = height - 4;
}
else if( (width >= 8 && height >= 8) )
{
skipWidth = width - 8;
skipHeight = height - 8;
}
}
TCoeff *block = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) );
//进行反MTS变换
if( width > 1 && height > 1 ) //2-D transform
{
const int shift_1st = TRANSFORM_MATRIX_SHIFT + 1 + COM16_C806_TRANS_PREC; // 1 has been added to shift_1st at the expense of shift_2nd
const int shift_2nd = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC;
CHECK( shift_1st < 0, "Negative shift" );
CHECK( shift_2nd < 0, "Negative shift" );
TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) );
fastInvTrans[trTypeVer][transformHeightIndex](pCoeff.buf, tmp, shift_1st, width, skipWidth, skipHeight, clipMinimum, clipMaximum);
fastInvTrans[trTypeHor][transformWidthIndex] (tmp, block, shift_2nd, height, 0, skipWidth, clipMinimum, clipMaximum);
}
else if( width == 1 ) //1-D vertical transform
{
int shift = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC;
CHECK( shift < 0, "Negative shift" );
CHECK( ( transformHeightIndex < 0 ), "There is a problem with the height." );
fastInvTrans[trTypeVer][transformHeightIndex]( pCoeff.buf, block, shift + 1, 1, 0, skipHeight, clipMinimum, clipMaximum );
}
else //if(iHeight == 1) //1-D horizontal transform
{
const int shift = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC;
CHECK( shift < 0, "Negative shift" );
CHECK( ( transformWidthIndex < 0 ), "There is a problem with the width." );
fastInvTrans[trTypeHor][transformWidthIndex]( pCoeff.buf, block, shift + 1, 1, 0, skipWidth, clipMinimum, clipMaximum );
}
Pel *resiBuf = pResidual.buf;
int resiStride = pResidual.stride;
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
resiBuf[( y * resiStride ) + x] = Pel( block[( y * width ) + x] );
}
}
}
以上是关于VTM10.0反量化反变换技术的主要内容,如果未能解决你的问题,请参考以下文章