今天来看解码端的xDecompressCU函数。对应x
CompressCU,解码端有xDecompressCU函数,来完成CU的划分即各CU模式的选择。
相比编码端,解码端就简单多了,只需要按照编码端传递的参数来进行划分即可,不需要在进行复杂的选择。
主要流程如下:
1、初始化,读取各种信息
2、判断是否越界
3、当深度小于CU最大深度和设定的最大深度且不越界时,递归调用xDecompressCU。
4、清空残差,复制子块图像。
5、选择预测模式,构造预测块。
6、复制得到重构快。
从这里我们可以看到,编码器会传递CU深度和预测模式给解码器。
Void TDecCu::xDecompressCU( TComDataCU* pCtu, UInt uiAbsPartIdx, UInt uiDepth )
{
TComPic* pcPic = pCtu->getPic();
TComSlice * pcSlice = pCtu->getSlice();
const TComSPS &sps=*(pcSlice->getSPS());
Bool bBoundary = false;
UInt uiLPelX = pCtu->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
UInt uiRPelX = uiLPelX + (sps.getMaxCUWidth()>>uiDepth) - 1;
UInt uiTPelY = pCtu->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
UInt uiBPelY = uiTPelY + (sps.getMaxCUHeight()>>uiDepth) - 1;
if( ( uiRPelX >= sps.getPicWidthInLumaSamples() ) || ( uiBPelY >= sps.getPicHeightInLumaSamples() ) ) //检测是否越界
{
bBoundary = true;
}
//当小于CU最大深度和设定的最大深度,且未越界时,递归调用xDecompressCU
if( ( ( uiDepth < pCtu->getDepth( uiAbsPartIdx ) ) && ( uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() ) ) || bBoundary )
{
UInt uiNextDepth = uiDepth + 1;
UInt uiQNumParts = pCtu->getTotalNumPart() >> (uiNextDepth<<1);
UInt uiIdx = uiAbsPartIdx;
for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++ )
{
uiLPelX = pCtu->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiIdx] ];
uiTPelY = pCtu->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiIdx] ];
if( ( uiLPelX < sps.getPicWidthInLumaSamples() ) && ( uiTPelY < sps.getPicHeightInLumaSamples() ) )
{
xDecompressCU(pCtu, uiIdx, uiNextDepth );
}
uiIdx += uiQNumParts;
}
return;
}
// Residual reconstruction
m_ppcYuvResi[uiDepth]->clear(); //清空残差
m_ppcCU[uiDepth]->copySubCU( pCtu, uiAbsPartIdx ); //复制子块信息
switch( m_ppcCU[uiDepth]->getPredictionMode(0) ) //选择预测模式
{
case MODE_INTER: //帧间预测
xReconInter( m_ppcCU[uiDepth], uiDepth );
break;
case MODE_INTRA: //帧内预测
xReconIntraQT( m_ppcCU[uiDepth], uiDepth );
break;
default:
assert(0);
break;
}
#if DEBUG_STRING //默认关闭,用于打印选择的预测模式
const PredMode predMode=m_ppcCU[uiDepth]->getPredictionMode(0);
if (DebugOptionList::DebugString_Structure.getInt()&DebugStringGetPredModeMask(predMode))
{
PartSize eSize=m_ppcCU[uiDepth]->getPartitionSize(0);
std::ostream &ss(std::cout);
ss <<"###: " << (predMode==MODE_INTRA?"Intra ":"Inter ") << partSizeToString[eSize] << " CU at " << m_ppcCU[uiDepth]->getCUPelX() << ", " << m_ppcCU[uiDepth]->getCUPelY() << " width=" << UInt(m_ppcCU[uiDepth]->getWidth(0)) << std::endl;
}
#endif
if ( m_ppcCU[uiDepth]->isLosslessCoded(0) && (m_ppcCU[uiDepth]->getIPCMFlag(0) == false))
{
xFillPCMBuffer(m_ppcCU[uiDepth], uiDepth); //填充PCM Buffer
}
xCopyToPic( m_ppcCU[uiDepth], pcPic, uiAbsPartIdx, uiDepth ); //复制得到重构快
}