void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
{
CHECKD( !canSplit( split, cs ), "Trying to apply a prohibited split!" );
bool isImplicit = isSplitImplicit( split, cs );
bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
//也是存在m_partStack中的一个设置参数
bool qgEnable = currQgEnable();
bool qgChromaEnable = currQgChromaEnable();
switch( split )
{
case CU_QUAD_SPLIT:
m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs ) ) );
m_partStack.back().modeType = modeType;
break;
case CU_HORZ_SPLIT:
case CU_VERT_SPLIT:
m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) );
m_partStack.back().modeType = modeType;
break;
case CU_TRIH_SPLIT:
case CU_TRIV_SPLIT:
m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) );
m_partStack.back().modeType = modeType;
break;
//TU的划分
case TU_MAX_TR_SPLIT:
m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) );
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:
m_partStack.push_back( PartLevel( split, PartitionerImpl::getSbtTuTiling( currArea(), cs, split ) ) );
break;
default:
THROW( "Unknown split mode" );
break;
}
currDepth++;
currSubdiv++;
#if _DEBUG
m_currArea = m_partStack.back().parts.front();
#endif
//若当前划分为TU的划分模式
if( split == TU_MAX_TR_SPLIT )
{
currTrDepth++;
}
else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
{
currTrDepth++;
}
else
{
currTrDepth = 0;
}
//根据不同的划分模式,不同的深度变量加1
if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
{
currBtDepth++;
if( isImplicit ) currImplicitBtDepth++;//隐式划分BT深度
currMtDepth++;
if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
{
// first and last part of triple split are equivalent to double bt split
currBtDepth++;
currSubdiv++;
}
m_partStack.back().canQtSplit = canQtSplit;
}
else if( split == CU_QUAD_SPLIT )//为四叉树
{
CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
currMtDepth = 0;//两个深度置0
currBtDepth = 0;
currQtDepth++;
currSubdiv++;
}
qgEnable &= (currSubdiv <= cs.slice->getCuQpDeltaSubdiv());
qgChromaEnable &= (currSubdiv <= cs.slice->getCuChromaQpOffsetSubdiv());
m_partStack.back().qgEnable = qgEnable;
m_partStack.back().qgChromaEnable = qgChromaEnable;
if (qgEnable)
currQgPos = currArea().lumaPos();
if (qgChromaEnable)
currQgChromaPos = currArea().chromaPos();
}
前两个函数参考initCULevel()函数部分,cansplit()函数_青椒鸡汤的博客-CSDN博客
switch语句:将当前的划分模式存入
以QT为例
m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs ) ) )
- 先用getCUSubPartitions()得到用当前划分模式划分后各个CU的位置和尺寸
- 将PartLevel中新的split和part,输入到m_partStack中更新
m_currArea = m_partStack.back().parts.front():这里返回的是parts中第一个CU的位置和宽高。这里可以在运行到第二个CU的时候再具体看一下
这个函数最好每次递归时都来看一下,比较一下
Partitioning PartitionerImpl::getCUSubPartitions( const UnitArea &cuArea, const CodingStructure &cs, const PartSplit _splitType /*= CU_QUAD_SPLIT*/ )
{
const PartSplit splitType = _splitType;
if( splitType == CU_QUAD_SPLIT )
{
if( !cs.pcv->noChroma2x2 )
{
Partitioning sub;
sub.resize( 4, cuArea );
for( uint32_t i = 0; i < 4; i++ )
{
for( auto &blk : sub[i].blocks ) //将blk的值赋给这四个已划分的CU
{
blk.height >>= 1; //宽高除以4
blk.width >>= 1;
if( i >= 2 ) blk.y += blk.height;
if( i & 1 ) blk.x += blk.width;//i&1 按位与运算
}
CHECK( sub[i].lumaSize().height < MIN_TB_SIZEY, "the split causes the block to be smaller than the minimal TU size" );
}
return sub;
}
else//如果noChroma2x2 为true
{
const uint32_t minCUSize = 1 << cs.sps->getLog2MinCodingBlockSize();//最小CU尺寸
bool canSplit = cuArea.lumaSize().width > minCUSize && cuArea.lumaSize().height > minCUSize;//如果当前区域的亮度分量的宽和高都大于最小CU宽高,则为true
Partitioning ret;
if( canSplit )//允许chroma2x2且可划分
{
ret.resize( 4 );
if( cuArea.chromaFormat == CHROMA_400 ) //格式为400
{
CompArea blkY = cuArea.Y();
blkY.width >>= 1;
blkY.height >>= 1;
ret[0] = UnitArea( cuArea.chromaFormat, blkY );
blkY.x += blkY.width;
ret[1] = UnitArea( cuArea.chromaFormat, blkY );
blkY.x -= blkY.width;
blkY.y += blkY.height;
ret[2] = UnitArea( cuArea.chromaFormat, blkY );
blkY.x += blkY.width;
ret[3] = UnitArea( cuArea.chromaFormat, blkY );
}
else//不为400的具体的一些填充规则
{
for( uint32_t i = 0; i < 4; i++ )
{
ret[i] = cuArea;
CompArea &blkY = ret[i].Y();
CompArea &blkCb = ret[i].Cb();
CompArea &blkCr = ret[i].Cr();
blkY.width /= 2;
blkY.height /= 2;
// TODO: get those params from SPS
if( blkCb.width > 4 )
{
blkCb.width /= 2;
blkCb.height /= 2;
blkCr.width /= 2;
blkCr.height /= 2;
}
else if( i > 0 )
{
blkCb = CompArea();
blkCr = CompArea();
}
if( ( i & 1 ) == 1 )
{
blkY.x += blkY .width;
blkCb.x += blkCb.width;
blkCr.x += blkCr.width;
}
if( i > 1 )
{
blkY.y += blkY .height;
blkCb.y += blkCb.height;
blkCr.y += blkCr.height;
}
}
}
}
return ret;
}
}
//二叉树具体填充
else if( splitType == CU_HORZ_SPLIT )
{
Partitioning sub;
sub.resize(2, cuArea);
for (uint32_t i = 0; i < 2; i++)
{
for (auto &blk : sub[i].blocks)
{
blk.height >>= 1;
if (i == 1) blk.y += blk.height;
}
CHECK(sub[i].lumaSize().height < MIN_TB_SIZEY, "the cs split causes the block to be smaller than the minimal TU size");
}
return sub;
}
else if( splitType == CU_VERT_SPLIT )
{
Partitioning sub;
sub.resize( 2, cuArea );
for( uint32_t i = 0; i < 2; i++ )
{
for( auto &blk : sub[i].blocks )
{
blk.width >>= 1;
if( i == 1 ) blk.x += blk.width;
}
CHECK( sub[i].lumaSize().width < MIN_TB_SIZEY, "the split causes the block to be smaller than the minimal TU size" );
}
return sub;
}
//三叉树
else if( splitType == CU_TRIH_SPLIT )
{
Partitioning sub;
sub.resize( 3, cuArea );
for( int i = 0; i < 3; i++ )
{
for( auto &blk : sub[i].blocks )
{
blk.height >>= 1;
if( ( i + 1 ) & 1 ) blk.height >>= 1;
if( i == 1 ) blk.y += blk.height / 2;
if( i == 2 ) blk.y += 3 * blk.height;
}
CHECK( sub[i].lumaSize().height < MIN_TB_SIZEY, "the cs split causes the block to be smaller than the minimal TU size" );
}
return sub;
}
else if( splitType == CU_TRIV_SPLIT )
{
Partitioning sub;
sub.resize( 3, cuArea );
for( int i = 0; i < 3; i++ )
{
for( auto &blk : sub[i].blocks )
{
blk.width >>= 1;
if( ( i + 1 ) & 1 ) blk.width >>= 1;
if( i == 1 ) blk.x += blk.width / 2;
if( i == 2 ) blk.x += 3 * blk.width;
}
CHECK( sub[i].lumaSize().width < MIN_TB_SIZEY, "the cs split causes the block to be smaller than the minimal TU size" );
}
return sub;
}
else
{
THROW( "Unknown CU sub-partitioning" );
return Partitioning();
}
}
!cs.pcv->noChroma2x2 :这里默认设置为false
Partitioning:实质为存储UnitArea位置信息的容器的另取名
sub.resize( 4, cuArea ):4代表QT把CTU分成四份
for循环嵌套语句:第一个for循环表示有四个已被划分的块需要被填充,第二个for循环表示从YCbCr三个分量来填充,总共循环12次
这里以Y分量的for循环为例,i>=2和i&1是为了区分划分的CU位置