今天上午又看到一篇挺好的关于xCompressCU函数的总结文,不过是关于HM的,所以我就基于此文写一个JEM的吧。原文地址https://www.2cto.com/kf/201604/499329.html。
先来个文字版的简洁说明(写在下面的步骤不一定会执行,是需要经过条件判断的,其中还有很多步骤没写出来),代码记录在下一篇吧。
xCompressCU()
{
(1)从图像中获取原始YUV数据;
(2)计算最优CU的范围;
(3)计算QTBT的深度;
(4)调用xComputeQP计算QP;
(5)计算minQP和maxQP;
(6)if (!bBoundary
#if COM16_C806_LARGE_CTU
&& ucMinDepth <= uiDepth
#endif
#if JVET_C0024_QTBT
&& !bForceQT
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !(saveLoadSplit & 0x01)
#endif
)
{
A. for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)//遍历每一个QP,执行下面的步骤,选取最优QP
{
a.初始化当前CU的数据-----inistEstData();
b.如果不是I slice ,进行帧间模式选择:
1)xCheckRDCostInter;
2) xCheckRDCostAffineMerge2Nx2N;
3) xCheckRDCostMerge2Nx2N
4) xCheckRDCostMerge2Nx2NFRUC
5)xCheckRDCostInter
}
B. if (!earlyDetectionSkipMode)//如果不是earlyDetectionSkipMode;
{
for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)
{
a.初始化当前CU的数据------initEstData();
b.如果是I SLICE,则进行帧内模式选择:
for (iROTidx = 0; iROTidx < iNumberOfPassesROT; iROTidx++)
{
for (UChar ucCuFlag = 0; ucCuFlag < ucEmtUsage; ucCuFlag++)
{
xCheckRDCostIntra();
initEstData();
}
}
c. 如果使用PCM模式,则调用xCheckIntraPCM();
}
}
C.xCheckRDCostInterKLT(); //JEM新加的;
D. 重置熵编码器的比特数,对split标志进行编码,然后统计比特数,计算总的消耗
}
(7)重新计算minQP和maxQP.
(8)为了加速编码,判断是否要进行二叉树水平划分/垂直划分或者四叉树划分;
(9)if (bTestHorSplit) //如果要进行二叉树水平划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
initEstData();
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
{
xCompressCU();
}
统计当前CU的总比特数,二进制数和总的率失真代价;
xCheckBestMode();
}
}
(10)if (bTestVerSplit) //如果要进行二叉树垂直划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
initEstData();
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
{
xCompressCU();
}
统计当前CU的总比特数,二进制数和总的率失真代价;
xCheckBestMode();
}
}
(11)if( bQTSplit)//如果要进行四叉树划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
initEstData();
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx <4; uiPartUnitIdx++ )
{
xCompressCU();
}
统计当前CU的总比特数,二进制数和总的率失真代价;
xCheckBestMode();
}
}
}