void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStructure& cs )
{
// Min/max depth
unsigned minDepth = 0;
unsigned maxDepth = floorLog2(cs.sps->getCTUSize()) - floorLog2(cs.sps->getMinQTSize( m_slice->getSliceType(), partitioner.chType ));
if( m_pcEncCfg->getUseFastLCTU() )
{
if( auto adPartitioner = dynamic_cast<AdaptiveDepthPartitioner*>( &partitioner ) )
{
// LARGE CTU
adPartitioner->setMaxMinDepth( minDepth, maxDepth, cs );
}
}
m_ComprCUCtxList.push_back( ComprCUCtx( cs, minDepth, maxDepth, NUM_EXTRA_FEATURES ) );
const CodingUnit* cuLeft = cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), partitioner.chType );
const CodingUnit* cuAbove = cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), partitioner.chType );
const bool qtBeforeBt = ( ( cuLeft && cuAbove && cuLeft ->qtDepth > partitioner.currQtDepth && cuAbove->qtDepth > partitioner.currQtDepth )
|| ( cuLeft && !cuAbove && cuLeft ->qtDepth > partitioner.currQtDepth )
|| ( !cuLeft && cuAbove && cuAbove->qtDepth > partitioner.currQtDepth )
|| ( !cuAbove && !cuLeft && cs.area.lwidth() >= ( 32 << cs.slice->getDepth() ) ) )
&& ( cs.area.lwidth() > ( cs.pcv->getMinQtSize( *cs.slice, partitioner.chType ) << 1 ) );
cuLeft:当前CU的左侧cu情况。如是第一个cu,则culeft就为NULL.
offset( -1, 0 ):表示当前CU位置向左移动一个单位的CU情况
qtBeforeBt:
- cuLeft,cuabove都存在且culeft的QT深度大于当前cu的QT深度,同时cuabove的QT深度大于当前cu的QT深度
- 只有culeft存在且culeft的QT深度大于当前cu的QT深度
- 只有cuabove存在且cuabove的QT深度大于当前cu的QT深度
- 都不存在且当前CTU的亮度width大于32 X 当前深度
若以上四个条件有任一个满足,且当前CTU的亮度分量width大于MinQtSize的2倍,则qtBeforeBt为真
2. initCULevel 函数调用的 cansplit()函数
bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs )
{
//当前亮度分量的位置和长宽
const CompArea area = currArea().Y();
const unsigned maxTrSize = cs.sps->getMaxTbSize();
bool canNo, canQt, canBh, canTh, canBv, canTv;
canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
switch( split )
{
case CTU_LEVEL:
THROW( "Checking if top level split is possible" );
return true;
break;
case TU_MAX_TR_SPLIT:
return area.width > maxTrSize || area.height > maxTrSize;
break;
case SBT_VER_HALF_POS0_SPLIT:
case SBT_VER_HALF_POS1_SPLIT:
case SBT_HOR_HALF_POS0_SPLIT:
case SBT_HOR_HALF_POS1_SPLIT:
case SBT_VER_QUAD_POS0_SPLIT:
case SBT_VER_QUAD_POS1_SPLIT:
case SBT_HOR_QUAD_POS0_SPLIT:
case SBT_HOR_QUAD_POS1_SPLIT:
return currTrDepth == 0;
break;
case CU_QUAD_SPLIT:
return canQt;
case CU_DONT_SPLIT:
return canNo;
case CU_HORZ_SPLIT:
return canBh;
case CU_VERT_SPLIT:
return canBv;
case CU_TRIH_SPLIT:
return canTh;
case CU_TRIV_SPLIT:
return canTv;
case CU_MT_SPLIT:
return ( canBh || canTh || canBv || canTv );
case CU_BT_SPLIT:
return ( canBh || canBv );
break;
default:
THROW( "Unknown split mode" );
return false;
break;
}
H.264/H.265/H.266三代视频编码的图像划分_@唔问的博客-CSDN博客_h266视频编码对照表
getMaxTbSize():得到最大的TB尺寸
swicth:根据当前传入的划分模式,判断是否加入测试列表
3.cansplit中调用的决定各个划分模式是否可行的cansplit函数
void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
{
//隐式分割设置
const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
//一些参数获取
//maxBT深度是要加上当前隐式分割的BT深度
const unsigned maxBTD = cs.pcv->getMaxBtDepth( *cs.slice, chType ) + currImplicitBtDepth;
const unsigned maxBtSize = cs.pcv->getMaxBtSize ( *cs.slice, chType );
const unsigned minBtSize = cs.pcv->getMinBtSize ( *cs.slice, chType );
const unsigned maxTtSize = cs.pcv->getMaxTtSize ( *cs.slice, chType );
const unsigned minTtSize = cs.pcv->getMinTtSize ( *cs.slice, chType );
const unsigned minQtSize = cs.pcv->getMinQtSize ( *cs.slice, chType );
canNo = canQt = canBh = canTh = canBv = canTv = true;
//若设置的BT最大深度大于当前MT的深度,则可以BT和TT
bool canBtt = currMtDepth < maxBTD;
// the minimal and maximal sizes are given in luma samples
const CompArea& area = currArea().Y();
const CompArea *areaC = (chType == CHANNEL_TYPE_CHROMA) ? &(currArea().Cb()) : nullptr;
PartLevel& level = m_partStack.back();
const PartSplit lastSplit = level.split;
const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
// don't allow QT-splitting below a BT split
//如果上次划分模式不是CTU_LEVEL 且不为CU_QUAD_SPLIT ,canQT为fasle
if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
if( area.width <= minQtSize ) canQt = false;
if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
// 若当前树类型为色度分离树
// 则二叉、三叉、四叉划分均不进行
if( treeType == TREE_C )
{
canQt = canBh = canTh = canBv = canTv = false;
return;
}
// 若隐含划分不为不划分
if( implicitSplit != CU_DONT_SPLIT )
{
// 则不划分、三叉树划分均不进行测试
canNo = canTh = canTv = false;
// 根据隐含划分决定二叉树划分是否测试
canBh = implicitSplit == CU_HORZ_SPLIT;
canBv = implicitSplit == CU_VERT_SPLIT;
// 若当前色度区域存在且色度区域宽度等于4,则不进行 BV
if (areaC && areaC->width == 4) canBv = false;
// 若不BH、BV、QT,则测试 QT
if( !canBh && !canBv && !canQt ) canQt = true;
return;
}
// 若上一划分模式为 TH,且当前块索引为 1,则不测试 BH,测试 BV
// 若上一划分模式为 TV,且当前块索引为 1,则不测试 BV,测试 BH
if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
{
canBh = parlSplit != CU_HORZ_SPLIT;
canBv = parlSplit != CU_VERT_SPLIT;
}
// 若同时满足当前 MT 深度小于最大 MT 深度、当前区域宽高均小于等于最小 BT 尺寸、当前区域宽高均小于等于最小 TT 尺寸,则将 canBtt 设为 false
if( canBtt && ( area.width <= minBtSize && area.height <= minBtSize )
&& ( ( area.width <= minTtSize && area.height <= minTtSize ) ) )
{
canBtt = false;
}
// 若同时满足当前 MT 深度小于最大 MT 深度、当前区域宽或高大于最大 BT 尺寸、当前区域宽或高大于最大 TT 尺寸,则将 canBtt 设为 false
if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
&& ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
{
canBtt = false;
}
if( !canBtt )
{
canBh = canTh = canBv = canTv = false;
return;
}
// 若当前区域宽或高大于最大 BT 尺寸
// 则不尝试 BT
if( area.width > maxBtSize || area.height > maxBtSize )
{
canBh = canBv = false;
}
// specific check for BT splits
// 若当前区域高小于等于最小 BT 尺寸,则不尝试 BH
if( area.height <= minBtSize ) canBh = false;
// 若当前区域宽大于最大 TB 尺寸,且当前区域高小于等于最大 TB 尺寸,则不尝试 BH
if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
// 若当前色度区域存在,且面积小于等于 16,则不尝试 BH
if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE ) canBh = false;
// 若当前区域宽小于等于最小 BT 尺寸,则不尝试 BV
if( area.width <= minBtSize ) canBv = false;
// 若当前区域宽小于等于最大 TB 尺寸,且当前区域高大于最大 TB 尺寸,则不尝试 BV
if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
// 若当前色度区域存在,且面积小于等于 16 或宽为 4,则不尝试 BV
if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE || areaC->width == 4)) canBv = false;
// 若为 INTER,且当前区域面积为 32,则不尝试 BT
if( modeType == MODE_TYPE_INTER && area.width * area.height == 32 ) canBv = canBh = false;
// 若当前区域高小于等于两倍最小 TT 尺寸,或当前区域高大于最大 TT 尺寸,或当前区域宽大于最大 TT 尺寸
// 则不尝试 TH
if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize )
canTh = false;
// 若当前区域宽大于最大 TB 尺寸,或当前区域高大于最大 TB 尺寸,则不尝试 TH
if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY ) canTh = false;
// 若当前色度区域存在,且面积小于等于 32,则不尝试 TH
if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE*2 ) canTh = false;
// 若当前区域宽度小于等于两倍最小 TT 尺寸,或当前区域宽大于最大 TT 尺寸,或当前区域高大于最大 TT 尺寸
// 则不尝试 TV
if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize )
canTv = false;
// 若当前区域宽大于最大 TB 尺寸,或当前区域高大于最大 TB 尺寸,则不尝试 TV
if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY ) canTv = false;
// 若当前色度区域存在,且面积小于等于 32 或 宽度为 8,则不尝试 TV
if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE * 2 || areaC->width == 8)) canTv = false;
// 若为 INTER,且当前区域面积为 64,则不尝试 TT
if( modeType == MODE_TYPE_INTER && area.width * area.height == 64 ) canTv = canTh = false;
}
maxBTD:最大BT深度,是psv中设置的maxBTdepth和当前隐式分割BTdepth的相加
PartLevel& level= m_partStack.back():将m_partStack中赋给level。m_partStack里为划分树的具体情况
lastSplit:表示的是上一次使用的划分模式
parlSplit:如果上一次为TH,则这次的划分模式BH,否则为BT,赋给parlSplit