void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] )
VTM3.0代码阅读:compressCtu函数_矛盾统一的博客-优快云博客
H.266/VVC代码学习13:VTM4.0中的CU层操作(compressCtu 、 xCompressCU)_海洋之心。的博客-优快云博客
cs:包含之前picture,slice全部的信息,如位置,色度亮度,preQP的设置等。不包括当前CTU的信息。这个之后再确认一下
area,ctuRsAddr,prevQP, currQP:传输过来CTU的位置,ctuRsAddr的值,过去与现在QP的设置,这些都是当前CPU的值。
ctuRsAddr为当前ctu的rs扫描地址。这个之后再确认一下
m_modeCtrl->initCTUEncoding( *cs.slice );
cs.treeType = TREE_D;
cs.slice->m_mapPltCost[0].clear();
cs.slice->m_mapPltCost[1].clear();
// init the partitioning manager
QTBTPartitioner partitioner;
partitioner.initCtu(area, CH_L, *cs.slice);// 用当前area初始化partitioner
initCTUEncoding():进行模式控制类实例的CTU级初始化
enum TreeType
{
TREE_D = 0, //树的状态设置 (for single-tree slice, TREE_D means joint tree; for dual-tree I slice, TREE_D means TREE_L for luma and TREE_C for chroma)//single tree应该是对应于dual tree,表明亮度色度都有相同的编码树结构。joint tree应该表示亮色度共用同一种树结构。对于I 帧的dual_tree,不同的变量来表示
TREE_L = 1, //separate tree only contains luma (may split) 可再分,对single tree和dual tree来说TREE_L 都代表亮度树
TREE_C = 2, //separate tree only contains chroma (not split), to avoid small chroma block//不可再分,以免出现过小的色度块
};
QTBTPartitioner partitioner:是管理划分的变量,包含划分的栈、CU/PU/TU划分信息(划分深度、UnitArea等信息)、设置划分限制的方法以及划分合理性检查(canSplit)
initCtu():进行划分类实例的初始化,接收传输过来的数据
if (m_pcEncCfg->getIBCMode())
{
if (area.lx() == 0 && area.ly() == 0)
{
m_pcInterSearch->resetIbcSearch();
}
m_pcInterSearch->resetCtuRecord();
m_ctuIbcSearchRangeX = m_pcEncCfg->getIBCLocalSearchRangeX();
m_ctuIbcSearchRangeY = m_pcEncCfg->getIBCLocalSearchRangeY();
}
if (m_pcEncCfg->getIBCMode() && m_pcEncCfg->getIBCHashSearch() && (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE))
{
const int hashHitRatio = m_ibcHashMap.getHashHitRatio(area.Y()); // in percent
if (hashHitRatio < 5) // 5%
{
m_ctuIbcSearchRangeX >>= 1;
m_ctuIbcSearchRangeY >>= 1;
}
if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 0)
{
m_ctuIbcSearchRangeX >>= 1;
m_ctuIbcSearchRangeY >>= 1;
}
}
IBC:IntraBlockCopy(帧内块复制)模式,默认false,jvetw2002 3.91节有介绍先跳过
// init current context pointer 初始化当前上下文指针
m_CurrCtx = m_CtxBuffer.data();
CodingStructure *tempCS = m_pTempCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
CodingStructure *bestCS = m_pBestCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
cs.initSubStructure(*tempCS, partitioner.chType, partitioner.currArea(), false);
cs.initSubStructure(*bestCS, partitioner.chType, partitioner.currArea(), false);
tempCS->currQP[CH_L] = bestCS->currQP[CH_L] =
tempCS->baseQP = bestCS->baseQP = currQP[CH_L];//把当前亮度QP统一赋给temp和best
tempCS->prevQP[CH_L] = bestCS->prevQP[CH_L] = prevQP[CH_L];
xCompressCU(tempCS, bestCS, partitioner);
tempCS和bestCS:当前临时的Coding Struct结构和最佳模式的Coding Structure结构,对于每一个尺寸的CU和CTU,都可以根据尺寸在m_pTempCS和m_pBestCS得到对应的CS结构,通过父cs调用initSubStructure将相应信息复制到子cs中(sps、pps等)
gp_sizeIdxInfo->idxFrom():得到当前块的亮度分量的宽度或高度。因为当前area是传输过来的CTUarea,所以此时得到的是当前CTU的宽高
tempCS:得到当前块的宽高后,从m_pTempCS中得到当前块尺寸对应的临时Coding Struct结构(当前待划分CTU的临时Coding Struct结构)
bestCS:得到当前块的宽高后,从m_pBestCS中得到当前块尺寸对应的最佳Coding Struct结构(当前待划分CTU的最佳Coding Struct结构)
VTM3.0代码阅读:xCompressCU函数_矛盾统一的博客-优快云博客
复制的:tempCS用来存储当前compress区域的各种模式下处理得到的数据,如果tempCS的cost小于bestCS,那么赋给给bestCS;如果差于bestCS,那么丢弃tempCS中数据。bestCS在xCompressCU函数中的任何位置,都用来存储到目前为止所得到的最优划分和最优模式数据。 这个之后看代码再具体理解‘
重要重要:initSubStructure():picture级别的CS通过调用这个函数把SPS,PPS还有preQP等基础参数传给了tempCS和bestCS(CTU级别),注意CS所代表的区域
第一个xCompressCU():因为CTU也可以被看作最大的CU,所以没有encode cu,进入CompressCU()
cs.slice->m_mapPltCost[0].clear();
cs.slice->m_mapPltCost[1].clear();
// all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS
const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1;
cs.useSubStructure(*bestCS, partitioner.chType, CS::getArea(*bestCS, area, partitioner.chType), copyUnsplitCTUSignals,
false, false, copyUnsplitCTUSignals, true);
copyUnsplitCTUSignals:默认为false
if (CS::isDualITree (cs) && isChromaEnabled (cs.pcv->chrFormat))
{
m_CABACEstimator->getCtx() = m_CurrCtx->start;
partitioner.initCtu(area, CH_C, *cs.slice);
cs.initSubStructure(*tempCS, partitioner.chType, partitioner.currArea(), false);
cs.initSubStructure(*bestCS, partitioner.chType, partitioner.currArea(), false);
tempCS->currQP[CH_C] = bestCS->currQP[CH_C] =
tempCS->baseQP = bestCS->baseQP = currQP[CH_C];
tempCS->prevQP[CH_C] = bestCS->prevQP[CH_C] = prevQP[CH_C];
xCompressCU(tempCS, bestCS, partitioner);
const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1;
cs.useSubStructure(*bestCS, partitioner.chType, CS::getArea(*bestCS, area, partitioner.chType),
copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals, true);
}
if (m_pcEncCfg->getUseRateCtrl())
{
(m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_actualMSE = (double)bestCS->dist / (double)m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr).m_numberOfPixel;
}
// reset context states and uninit context pointer
m_CABACEstimator->getCtx() = m_CurrCtx->start;
m_CurrCtx = 0;
// Ensure that a coding was found
// Selected mode's RD-cost must be not MAX_DOUBLE.
CHECK( bestCS->cus.empty() , "No possible encoding found" );
CHECK( bestCS->cus[0]->predMode == NUMBER_OF_PREDICTION_MODES, "No possible encoding found" );
CHECK( bestCS->cost == MAX_DOUBLE , "No possible encoding found" );
}
if语句:如果当前为dualtree且色度采样格式不为4:0:0,则再对色度进行一次划分。与上面基本相同,只是变为了色度分量