xReconIntraQT函数在decompressCtu中被调用,用来在解码端实现帧内预测模式cu的decompress。
根据解码得到的帧内亮度和色度的预测模式,得到预测像素pred,再有tu块的变换系数coeff,就可以重建得到cu帧内模式重建像素reco。
Void DecCu::xReconIntraQT( CodingUnit &cu )
{
if( cu.ipcm )
{
xReconPCM( *cu.firstTU ); //pcm模式
return;
}
//4:0:0采样时只有Y通道,其它采样模式时有Y、Cb、Cr三通道
const UInt numChType = ::getNumberValidChannels( cu.chromaFormat );
for( UInt chType = CHANNEL_TYPE_LUMA; chType < numChType; chType++ ) //L、C
{
if( cu.blocks[chType].valid() )
{
xIntraRecQT( cu, ChannelType( chType ) ); //cu分别对luma和chroma,实现帧内像素的重建
}
}
}
//luma和chroma的tu,都是调用xIntraRecBlk函数来进行tu像素的重建
Void DecCu::xIntraRecQT(CodingUnit &cu, const ChannelType chType)
{
for( auto &currTU : CU::traverseTUs( cu ) ) //cu的每个tu,分别进行帧内像素重建
{
if( isLuma( chType ) )
{
xIntraRecBlk( currTU, COMPONENT_Y ); //Y通道tu的像素重建
}
else
{
const UInt numValidComp = getNumberValidComponents( cu.chromaFormat );
for( UInt compID = COMPONENT_Cb; compID < numValidComp; compID++ )
{
xIntraRecBlk( currTU, ComponentID( compID ) ); //Cb、Cr通道tu的像素重建
#if ENABLE_CHROMA_422
if( cu.cs->pcv->multiBlock422 )
{
xIntraRecBlk( currTU, ComponentID( compID + SCND_TBLOCK_OFFSET ) );
}
#endif
}
}
}
}
对一个tu的帧内像素重建:
首先初始化帧内预测的参考像素模板,根据解码得到的预测模式进行帧内预测,得到预测像素pred;
然后对解码得到的变换系数Coeff,经过反变换之后得到残差像素resi;
最后将预测像素pred和残差像素resi求和,就得到了重建像素reco。cu的帧内模式像素的重建完毕。
Void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
{
if( !tu.blocks[ compID ].valid() )
{
return;
}
CodingStructure &cs = *tu.cs;
const CompArea &area = tu.blocks[compID];
const ChannelType chType = toChannelType( compID );
PelBuf piPred = cs.getPredBuf( area ); //pred像素
const PredictionUnit &pu = *tu.cs->getPU( area.pos(), chType );
//===== init availability pattern =====
const bool bUseFilteredPredictions = IntraPrediction::useFilteredIntraRefSamples( compID, pu, true, tu ); //帧内预测的参考像素是否滤波
m_pcIntraPred->initIntraPatternChType( *tu.cu, area, bUseFilteredPredictions ); //准备好当前pu进行帧内预测时的参考像素
//===== get prediction signal =====
{
m_pcIntraPred->predIntraAng( compID, piPred, pu, bUseFilteredPredictions ); //pu的帧内预测,预测像素存入piPred
}
//===== inverse transform =====
PelBuf piResi = cs.getResiBuf( area ); //resi像素
const QpParam cQP( tu, compID ); //量化系数
if( TU::getCbf( tu, compID ) )
{
m_pcTrQuant->invTransformNxN( tu, compID, piResi, cQP ); //tu的coeff经过反变换得到残差像素,存入piResi
}
else
{
piResi.fill( 0 );
}
//===== reconstruction =====
if( isChroma(compID) && tu.compAlpha[compID] != 0 ) //Cb/Cr
{ //CCLM
CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true );
}
PelBuf pReco = cs.getRecoBuf( area ); //重建像素
cs.setDecomp( area ); //设置当前tu区域已经解码完成
#if KEEP_PRED_AND_RESI_SIGNALS
pReco.reconstruct( piPred, piResi, tu.cu->cs->slice->clpRng( compID ) );
#else
piPred.reconstruct( piPred, piResi, tu.cu->cs->slice->clpRng( compID ) ); //pred像素和resi像素相加,就得到了reco像素
#endif
#if !KEEP_PRED_AND_RESI_SIGNALS
pReco.copyFrom( piPred );
#endif
}