因为最近要提取H.265中变换编码的DCT系数,所以将看见的几个函数给发出来,希望有用。
TEncSbac::codeCoeffNxN 是SBAC熵编码底层函数用于Encode Transform Coefficients,HM16.9代码片段附上
Void TEncSbac::codeCoeffNxN( TComTU &rTu, TCoeff* pcCoef, const ComponentID compID )
{
//get初始化参数
TComDataCU* pcCU=rTu.getCU();
const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(compID);
const TComRectangle &tuRect=rTu.getRect(compID);
const UInt uiWidth=tuRect.width;
const UInt uiHeight=tuRect.height;
const TComSPS &sps=*(pcCU->getSlice()->getSPS());
//调用宏定义,如果打开宏ENC_DEC_TRACE(在typeDef.h中)则会生成TraceEnc.txt或者TraceDec.txt文件,该文件中包含如下信息
DTRACE_CABAC_VL( g_nSymbolCounter++ )
DTRACE_CABAC_T( "\tparseCoeffNxN()\teType=" )
DTRACE_CABAC_V( compID )
DTRACE_CABAC_T( "\twidth=" )
DTRACE_CABAC_V( uiWidth )
DTRACE_CABAC_T( "\theight=" )
DTRACE_CABAC_V( uiHeight )
DTRACE_CABAC_T( "\tdepth=" )
// DTRACE_CABAC_V( rTu.GetTransformDepthTotalAdj(compID) )
DTRACE_CABAC_V( rTu.GetTransformDepthTotal() )
DTRACE_CABAC_T( "\tabspartidx=" )
DTRACE_CABAC_V( uiAbsPartIdx )
DTRACE_CABAC_T( "\ttoCU-X=" )
DTRACE_CABAC_V( pcCU->getCUPelX() )
DTRACE_CABAC_T( "\ttoCU-Y=" )
DTRACE_CABAC_V( pcCU->getCUPelY() )
DTRACE_CABAC_T( "\tCU-addr=" )
DTRACE_CABAC_V( pcCU->getCtuRsAddr() )
DTRACE_CABAC_T( "\tinCU-X=" )
// DTRACE_CABAC_V( g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ] )
DTRACE_CABAC_V( g_auiRasterToPelX[ g_auiZscanToRaster[rTu.GetAbsPartIdxTU(compID)] ] )
DTRACE_CABAC_T( "\tinCU-Y=" )
// DTRACE_CABAC_V( g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ] )
DTRACE_CABAC_V( g_auiRasterToPelY[ g_auiZscanToRaster[rTu.GetAbsPartIdxTU(compID)] ] )
DTRACE_CABAC_T( "\tpredmode=" )
DTRACE_CABAC_V( pcCU->getPredictionMode( uiAbsPartIdx ) )
DTRACE_CABAC_T( "\n" )
//getMaxTrSize是get最大TU尺寸,如果当前uiWidth 大于最大TU尺寸,则报错,后结束
if( uiWidth > sps.getMaxTrSize() )
{
std::cerr << "ERROR: codeCoeffNxN was passed a TU with dimensions larger than the maximum allowed size" << std::endl;
assert(false);
exit(1);
}
//计算coefficients的非0值数量
// compute number of significant coefficients
UInt uiNumSig = TEncEntropy::countNonZeroCoeffs(pcCoef, uiWidth * uiHeight);
if ( uiNumSig == 0 )
{
std::cerr << "ERROR: codeCoeffNxN called for empty TU!" << std::endl;
assert(false);
exit(1);
}
//--------------------------------------------------------------------------------------------------
//set parameters
const ChannelType chType = toChannelType(compID);
const UInt uiLog2BlockWidth = g_aucConvertToBit[ uiWidth ] + 2;
const UInt uiLog2BlockHeight = g_aucConvertToBit[ uiHeight ] + 2;
const ChannelType channelType = toChannelType(compID);
const Bool extendedPrecision = sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag();
const Bool alignCABACBeforeBypass = sps.getSpsRangeExtension().getCabacBypassAlignmentEnabledFlag();
const Int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(channelType);
Bool beValid;//设置有效值
{
Int uiIntraMode = -1;
const Bool bIsLuma = isLuma(compID);
Int isIntra = pcCU->isIntra(uiAbsPartIdx) ? 1 : 0;
if ( isIntra )
{
uiIntraMode = pcCU->getIntraDir( toChannelType(compID), uiAbsPartIdx );
const UInt partsPerMinCU = 1<<(2*(sps.getMaxTotalCUDepth() - sps.getLog2DiffMaxMinCodingBlockSize()));
uiIntraMode = (uiIntraMode==DM_CHROMA_IDX && !bIsLuma) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, rTu.GetChromaFormat(), partsPerMinCU)) : uiIntraMode;
uiIntraMode = ((rTu.GetChromaFormat() == CHROMA_422) && !bIsLuma) ? g_chroma422IntraAngleMappingTable[uiIntraMode] : uiIntraMode;
}
Int transformSkip = pcCU->getTransformSkip( uiAbsPartIdx,compID) ? 1 : 0;
Bool rdpcm_lossy = ( transformSkip && isIntra && ( (uiIntraMode == HOR_IDX) || (uiIntraMode == VER_IDX) ) ) && pcCU->isRDPCMEnabled(uiAbsPartIdx);
if ( (pcCU->getCUTransquantBypass(uiAbsPartIdx)) || rdpcm_lossy )
{
beValid = false;
if ( (!pcCU->isIntra(uiAbsPartIdx)) && pcCU->isRDPCMEnabled(uiAbsPartIdx))
{
codeExplicitRdpcmMode( rTu, compID);
}
}
else
{
beValid = pcCU->getSlice()->getPPS()->getSignHideFlag();
}
}
//--------------------------------------------------------------------------------------------------
//是否执行变换编码跳过模式
if(pcCU->getSlice()->getPPS()->getUseTransformSkip())
{
codeTransformSkipFlags(rTu, compID);
if(pcCU->getTransformSkip(uiAbsPartIdx, compID) && !pcCU->isIntra(uiAbsPartIdx) && pcCU->isRDPCMEnabled(uiAbsPartIdx))
{
// This TU has coefficients and is transform skipped. Check whether is inter coded and if yes encode the explicit RDPCM mode
codeExplicitRdpcmMode( rTu, compID);
if(pcCU->getExplicitRdpcmMode(compID, uiAbsPartIdx) != RDPCM_OFF)
{
// Sign data hiding is avoided for horizontal and vertical explicit RDPCM modes
beValid = false;
}
}
}
//--------------------------------------------------------------------------------------------------
const Bool bUseGolombRiceParameterAdaptation = sps.getSpsRangeExtension().getPersistentRiceAdaptationEnabledFlag();
UInt ¤tGolombRiceStatistic = m_golombRiceAdaptationStatistics[rTu.getGolombRiceStatisticsIndex(compID)];
//select scans
TUEntropyCodingParameters codingParameters;//TUEntropyCodingParameters 是一个class
getTUEntropyCodingParameters(codingParameters, rTu, compID);//get Parameters
//----- encode significance map -----
//找到最后一个系数位置
// Find position of last coefficient
Int scanPosLast = -1;
Int posLast;
UInt uiSigCoeffGroupFlag[ MLS_GRP_NUM ];
memset( uiSigCoeffGroupFlag, 0, sizeof(UInt) * MLS_GRP_NUM );
do
{
posLast = codingParameters.scan[ ++scanPosLast ];//扫描顺序
if( pcCoef[ posLast ] != 0 )
{
// get L1 sig map
UInt uiPosY = posLast >> uiLog2BlockWidth;
UInt uiPosX = posLast - ( uiPosY << uiLog2BlockWidth );
UInt uiBlkIdx = (codingParameters.widthInGroups * (uiPosY >> MLS_CG_LOG2_HEIGHT)) + (uiPosX >> MLS_CG_LOG2_WIDTH);
uiSigCoeffGroupFlag[ uiBlkIdx ] = 1;
uiNumSig--;//这是之前get的系数有效值
}
} while ( uiNumSig > 0 );
//最后一个系数的编码位置
// Code position of last coefficient
Int posLastY = posLast >> uiLog2BlockWidth;
Int posLastX = posLast - ( posLastY << uiLog2BlockWidth );
codeLastSignificantXY(posLastX, posLastY, uiWidth, uiHeight, compID, codingParameters.scanType);
//===== code significance flag =====
ContextModel * const baseCoeffGroupCtx = m_cCUSigCoeffGroupSCModel.get( 0, chType );
ContextModel * const baseCtx = m_cCUSigSCModel.get( 0, 0 ) + getSignificanceMapContextOffset(compID);
const Int iLastScanSet = scanPosLast >> MLS_CG_SIZE;
UInt c1 = 1;
UInt uiGoRiceParam = 0;
Int iScanPosSig = scanPosLast;
//开始编码
for( Int iSubSet = iLastScanSet; iSubSet >= 0; iSubSet-- )
{
Int numNonZero = 0;
Int iSubPos = iSubSet << MLS_CG_SIZE;
uiGoRiceParam = currentGolombRiceStatistic / RExt__GOLOMB_RICE_INCREMENT_DIVISOR;
Bool updateGolombRiceStatistics = bUseGolombRiceParameterAdaptation; //leave the statistics at 0 when not using the adaptation system
UInt coeffSigns = 0;
Int absCoeff[1 << MLS_CG_SIZE];
Int lastNZPosInCG = -1;
Int firstNZPosInCG = 1 << MLS_CG_SIZE;
Bool escapeDataPresentInGroup = false;
if( iScanPosSig == scanPosLast )
{
absCoeff[ 0 ] = Int(abs( pcCoef[ posLast ] ));
coeffSigns = ( pcCoef[ posLast ] < 0 );
numNonZero = 1;
lastNZPosInCG = iScanPosSig;
firstNZPosInCG = iScanPosSig;
iScanPosSig--;
}
// encode significant_coeffgroup_flag
Int iCGBlkPos = codingParameters.scanCG[ iSubSet ];
Int iCGPosY = iCGBlkPos / codingParameters.widthInGroups;
Int iCGPosX = iCGBlkPos - (iCGPosY * codingParameters.widthInGroups);
if( iSubSet == iLastScanSet || iSubSet == 0)
{
uiSigCoeffGroupFlag[ iCGBlkPos ] = 1;
}
else
{
UInt uiSigCoeffGroup = (uiSigCoeffGroupFlag[ iCGBlkPos ] != 0);
UInt uiCtxSig = TComTrQuant::getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, iCGPosX, iCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups );
m_pcBinIf->encodeBin( uiSigCoeffGroup, baseCoeffGroupCtx[ uiCtxSig ] );
}
//有效编码位置
// encode significant_coeff_flag
if( uiSigCoeffGroupFlag[ iCGBlkPos ] )
{
//返回当前系数组的编码模式
const Int patternSigCtx = TComTrQuant::calcPatternSigCtx(uiSigCoeffGroupFlag, iCGPosX, iCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups);
UInt uiBlkPos, uiSig, uiCtxSig;
for( ; iScanPosSig >= iSubPos; iScanPosSig-- )
{
uiBlkPos = codingParameters.scan[ iScanPosSig ];
uiSig = (pcCoef[ uiBlkPos ] != 0);
if( iScanPosSig > iSubPos || iSubSet == 0 || numNonZero )
{
uiCtxSig = TComTrQuant::getSigCtxInc( patternSigCtx, codingParameters, iScanPosSig, uiLog2BlockWidth, uiLog2BlockHeight, chType );
//返回ctxInc的当前扫描位置
m_pcBinIf->encodeBin( uiSig, baseCtx[ uiCtxSig ] );
}
if( uiSig )
{
absCoeff[ numNonZero ] = Int(abs( pcCoef[ uiBlkPos ] ));
coeffSigns = 2 * coeffSigns + ( pcCoef[ uiBlkPos ] < 0 );
numNonZero++;
if( lastNZPosInCG == -1 )
{
lastNZPosInCG = iScanPosSig;
}
firstNZPosInCG = iScanPosSig;
}
}
}
else
{
iScanPosSig = iSubPos - 1;
}
if( numNonZero > 0 )
{
Bool signHidden = ( lastNZPosInCG - firstNZPosInCG >= SBH_THRESHOLD );
const UInt uiCtxSet = getContextSetIndex(compID, iSubSet, (c1 == 0));
c1 = 1;
ContextModel *baseCtxMod = m_cCUOneSCModel.get( 0, 0 ) + (NUM_ONE_FLAG_CTX_PER_SET * uiCtxSet);
Int numC1Flag = min(numNonZero, C1FLAG_NUMBER);
Int firstC2FlagIdx = -1;
for( Int idx = 0; idx < numC1Flag; idx++ )
{
UInt uiSymbol = absCoeff[ idx ] > 1;
m_pcBinIf->encodeBin( uiSymbol, baseCtxMod[c1] );
if( uiSymbol )
{
c1 = 0;
if (firstC2FlagIdx == -1)
{
firstC2FlagIdx = idx;
}
else //if a greater-than-one has been encountered already this group
{
escapeDataPresentInGroup = true;
}
}
else if( (c1 < 3) && (c1 > 0) )
{
c1++;
}
}
if (c1 == 0)
{
baseCtxMod = m_cCUAbsSCModel.get( 0, 0 ) + (NUM_ABS_FLAG_CTX_PER_SET * uiCtxSet);
if ( firstC2FlagIdx != -1)
{
UInt symbol = absCoeff[ firstC2FlagIdx ] > 2;
m_pcBinIf->encodeBin( symbol, baseCtxMod[0] );
if (symbol != 0)
{
escapeDataPresentInGroup = true;
}
}
}
escapeDataPresentInGroup = escapeDataPresentInGroup || (numNonZero > C1FLAG_NUMBER);
if (escapeDataPresentInGroup && alignCABACBeforeBypass)
{
m_pcBinIf->align();
}
if( beValid && signHidden )
{
m_pcBinIf->encodeBinsEP( (coeffSigns >> 1), numNonZero-1 );
}
else
{
m_pcBinIf->encodeBinsEP( coeffSigns, numNonZero );
}
Int iFirstCoeff2 = 1;
if (escapeDataPresentInGroup)
{
for ( Int idx = 0; idx < numNonZero; idx++ )
{
UInt baseLevel = (idx < C1FLAG_NUMBER)? (2 + iFirstCoeff2 ) : 1;
if( absCoeff[ idx ] >= baseLevel)
{
const UInt escapeCodeValue = absCoeff[idx] - baseLevel;
xWriteCoefRemainExGolomb( escapeCodeValue, uiGoRiceParam, extendedPrecision, maxLog2TrDynamicRange );
if (absCoeff[idx] > (3 << uiGoRiceParam))
{
uiGoRiceParam = bUseGolombRiceParameterAdaptation ? (uiGoRiceParam + 1) : (std::min<UInt>((uiGoRiceParam + 1), 4));
}
if (updateGolombRiceStatistics)
{
const UInt initialGolombRiceParameter = currentGolombRiceStatistic / RExt__GOLOMB_RICE_INCREMENT_DIVISOR;
if (escapeCodeValue >= (3 << initialGolombRiceParameter))
{
currentGolombRiceStatistic++;
}
else if (((escapeCodeValue * 2) < (1 << initialGolombRiceParameter)) && (currentGolombRiceStatistic > 0))
{
currentGolombRiceStatistic--;
}
updateGolombRiceStatistics = false;
}
}
if(absCoeff[ idx ] >= 2)
{
iFirstCoeff2 = 0;
}
}
}
}
}
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
printSBACCoeffData(posLastX, posLastY, uiWidth, uiHeight, compID, uiAbsPartIdx, codingParameters.scanType, pcCoef, pcCU->getSlice()->getFinalized());
//输出本次SBAC编码的有效数据
#endif
return;
}
TEncSbac::codeCoeffNxN 是底层编码函数,有些部分没看明白,大致上了解了其意思,其他的以后再说。