VTM10.0反量化之DQ技术
Posted 神遁克里苏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTM10.0反量化之DQ技术相关的知识,希望对你有一定的参考价值。
DQ反量化时,会把初始状态设置为0,然后根据level(也就是k)来进行下个点的state判断,如下图所示:
反DQ的函数是dequantBlock函数,个人理解见注释:
void Quantizer::dequantBlock( const TransformUnit& tu, const ComponentID compID, const QpParam& cQP, CoeffBuf& recCoeff, bool enableScalingLists, int* piDequantCoef) const
//----- set basic parameters -----
const CompArea& area = tu.blocks[ compID ];
const int numCoeff = area.area();//指area内的像素有多少
const SizeType hsId = gp_sizeIdxInfo->idxFrom( area.width );
const SizeType vsId = gp_sizeIdxInfo->idxFrom( area.height );
const CoeffScanType scanType = SCAN_DIAG;
const ScanElement *scan = g_scanOrder[SCAN_GROUPED_4x4][scanType][hsId][vsId];
const TCoeff* qCoeff = tu.getCoeffs( compID ).buf;
TCoeff* tCoeff = recCoeff.buf;
//----- reset coefficients and get last scan index -----
::memset( tCoeff, 0, numCoeff * sizeof(TCoeff) );
int lastScanIdx = -1;
for( int scanIdx = numCoeff - 1; scanIdx >= 0; scanIdx-- )
if (qCoeff[scan[scanIdx].idx])
lastScanIdx = scanIdx;//获得最后一个记录的系数的位置
break;
if( lastScanIdx < 0 )
return;
//----- set dequant parameters -----
const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1;
const int qpPer = qpDQ / 6;
const int qpRem = qpDQ - 6 * qpPer;
const SPS& sps = *tu.cs->sps;
const ChannelType chType = toChannelType( compID );
const int channelBitDepth = sps.getBitDepth( chType );
const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange( chType );
const TCoeff minTCoeff = -( 1 << maxLog2TrDynamicRange );
const TCoeff maxTCoeff = ( 1 << maxLog2TrDynamicRange ) - 1;
const int nomTransformShift = getTransformShift( channelBitDepth, area.size(), maxLog2TrDynamicRange );
const bool clipTransformShift = ( tu.mtsIdx[compID] == MTS_SKIP && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag());
const bool needsSqrt2ScaleAdjustment = TU::needsSqrt2Scale(tu, compID);
const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ) + (needsSqrt2ScaleAdjustment?-1:0);
Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0);
Intermediate_Int invQScale = g_invQuantScales[needsSqrt2ScaleAdjustment?1:0][ qpRem ];
Intermediate_Int add = (shift < 0) ? 0 : ((1 << shift) >> 1);
//----- dequant coefficients -----DQ解码,首先设置state为0
for( int state = 0, scanIdx = lastScanIdx; scanIdx >= 0; scanIdx-- )
const unsigned rasterPos = scan[scanIdx].idx;
const TCoeff& level = qCoeff[ rasterPos ];
if( level )//量化值为0就直接跳过了,因为量化为0的,反量化的值也为0,tCoeff[rasterPos]初始化的时候就全部设置的为0
if (enableScalingLists)//是否使用了量化矩阵
invQScale = piDequantCoef[rasterPos];//scalingfactor*levelScale
if (shift < 0 && (enableScalingLists || scanIdx == lastScanIdx))
invQScale <<= -shift;
//如果state是1或0,(state>>1)为0;如果state是2或3,(state>>1)为1。这是因为0,1的量化步长是偶数倍,2,3的量化步长是奇数倍
Intermediate_Int qIdx = ( level << 1 ) + ( level > 0 ? -(state>>1) : (state>>1) );
int64_t nomTCoeff = ((int64_t)qIdx * (int64_t)invQScale + add) >> ((shift < 0) ? 0 : shift);
tCoeff[rasterPos] = (TCoeff)Clip3<int64_t>(minTCoeff, maxTCoeff, nomTCoeff);//得到反量化后的值
//state状态改变
//32040 : 0111 1101 0010 1000,32040中每4位分别对应3,2,1,0的下一个候选state。
//如果本身是state1,那么下一个状态可能是3或1,那么(state<<2)就表示30240先右移8位,这时的低4位为1101
//然后根据level的奇偶判断是否还要右移两位,如果时level是奇数,再右移2位,低2位变成11,&3后结果为3,表示下一个状态是3。
state = ( 32040 >> ((state<<2)+((level&1)<<1)) ) & 3; // the 16-bit value "32040" represent the state transition table
以上是关于VTM10.0反量化之DQ技术的主要内容,如果未能解决你的问题,请参考以下文章