VTM10.0代码学习14:estIntraPredLumaQT()

此系列是为了记录自己学习VTM10.0的过程,目前正在看编码端。主要的参考文档有JVET-S2001-vH和JVET-S2002-v1。由于本人水平有限,出现的错误恳请大家指正,欢迎与大家一起交流进步。


上一篇博文提到(VTM10.0代码学习13)帧内模式是分亮度和色度处理的,这篇博文就先讲处理亮度的函数estIntraPredLumaQT()。这个函数会先用化简版的RDcost对帧内的亮度模式进行一个筛选,然后对筛选出来的模式执行完整的RDcost计算,来得到最佳的帧内亮度预测模式。


1. 预备变量

CodingStructure       &cs            = *cu.cs;
const SPS             &sps           = *cs.sps;
const uint32_t             uiWidthBit    = floorLog2(partitioner.currArea().lwidth() );
const uint32_t             uiHeightBit   = floorLog2(partitioner.currArea().lheight());

// Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantization divisor is 1.
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( ) * FRAC_BITS_SCALE;

uiWidthBit和uiHeightBit:分别表示宽度和高度是2的几次方

sqrtLambdaForFirstPass:化简版RDcost的lambda


const TempCtx ctxStart          ( m_CtxCache, m_CABACEstimator->getCtx() );
const TempCtx ctxStartMipFlag    ( m_CtxCache, SubCtx( Ctx::MipFlag,          m_CABACEstimator->getCtx() ) );
const TempCtx ctxStartIspMode    ( m_CtxCache, SubCtx( Ctx::ISPMode,          m_CABACEstimator->getCtx() ) );
const TempCtx ctxStartPlanarFlag ( m_CtxCache, SubCtx( Ctx::IntraLumaPlanarFlag, m_CABACEstimator->getCtx() ) );
const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::IntraLumaMpmFlag, m_CABACEstimator->getCtx()));
const TempCtx ctxStartMrlIdx      ( m_CtxCache, SubCtx( Ctx::MultiRefLineIdx,        m_CABACEstimator->getCtx() ) );

CABAC相关的变量


bool LFNSTLoadFlag = sps.getUseLFNST() && cu.lfnstIdx != 0;
bool LFNSTSaveFlag = sps.getUseLFNST() && cu.lfnstIdx == 0;

LFNSTSaveFlag &= sps.getUseIntraMTS() ? cu.mtsFlag == 0 : true;

const uint32_t lfnstIdx = cu.lfnstIdx;
double costInterCU = findInterCUCost( cu );

const int width  = partitioner.currArea().lwidth();
const int height = partitioner.currArea().lheight();

uint8_t mtsUsageFlag = 0;
const int maxSizeEMT = MTS_INTRA_MAX_CU_SIZE;
if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getUseIntraMTS() )
{
   
    mtsUsageFlag = ( sps.getUseLFNST() && cu.mtsFlag == 1 ) ? 2 : 1;
}

if( width * height < 64 && !m_pcEncCfg->getUseFastLFNST() )
{
   
    mtsUsageFlag = 0;
}

LFNSTLoadFlag:为True表示需要加载LFNST相关变量

LFNSTSaveFlag:为True表示需要保存LFNST相关变量

costInterCU:当前CU的帧间模式的RDcost,这个不确定

mtsUsageFlag:为0表示当前CU不允许开启MTS,为1表示当前CU允许开启MTS且正在测试变换为DCT2的情况,为2表示当前CU允许开启MTS且正在测试变换为非DCT2的情况


double bestCurrentCost = bestCostSoFar;//亮度分量目前最佳RDcost
bool ispCanBeUsed   = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP(width, height, cu.cs->sps->getMaxTbSize());//当前CU是否可以开启ISP
bool saveDataForISP = ispCanBeUsed;
bool testISP        = ispCanBeUsed;
    
if ( saveDataForISP )
{
   
    //reset the intra modes lists variables
    m_ispCandListHor.clear();
    m_ispCandListVer.clear();
}
if( testISP )
{
   
    //reset the variables used for the tests
    m_regIntraRDListWithCosts.clear();
    int numTotalPartsHor = (int)width  >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT));//ISP划分后垂直切几块
    int numTotalPartsVer = (int)height >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT));//ISP划分后水平切几块
    m_ispTestedModes[0].init( numTotalPartsHor, numTotalPartsVer );
    //the total number of subpartitions is modified to take into account the cases where LFNST cannot be combined with ISP due to size restrictions
    //初始化开启LFNST下ISP的情况
    numTotalPartsHor = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), HOR_INTRA_SUBPARTITIONS) ? numTotalPartsHor : 0;
    numTotalPartsVer = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), VER_INTRA_SUBPARTITIONS) ? numTotalPartsVer : 0;
    for (int j = 1; j < NUM_LFNST_NUM_PER_SET; j++)
    {
   
        m_ispTestedModes[j].init(numTotalPartsHor, numTotalPartsVer);
    }
}

bestCurrentCost:亮度分量目前最佳RDcost

ispCanBeUsed:当前CU是否可以开启ISP

后面两个if都是用来初始化ISP相关变量


static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList;
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList;
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList;

auto &pu = *cu.firstPU;
bool validReturn = false;

CandHadList.clear();
CandCostList.clear();
uiHadModeList.clear();

uiHadModeList:存储着以SAD/SATD为指标的模式候选列表的模式信息,按指标从小往大排

CandCostList:存储着以化简版RDcost为指标的模式候选列表的RDcost信息,按指标从小往大排

CandHadList:存储着以SAD/SATD为指标的模式候选列表的SAD/SATD信息,按指标从小往大排

validReturn:为True表示成功选出亮度最佳模式

这里解释一下SATD,SAD大家都知道是什么意思,SATD就是在预测值和原始值都进行hadamard变换之后再进行SAD计算。为什么要这么做呢,因为化简版的RDcost的R只包括表示预测模式所花费的比特数,那表示残差的比特数光靠SAD是体现不出来的。大多数CU都要进行变换把残差转换到频域,SAD是时域的准则。所以SAD小不一定会代表残差经过VVC的编码方式出来的比特数会小,这时就需要SATD了。


int numModesAvailable = NUM_LUMA_MODE; // total number of Intra modes
const bool fastMip    = sps.getUseMIP() && m_pcEncCfg->getUseFastMIP();//是否使用MIP的快速算法
const bool mipAllowed = sps.getUseMIP() && isLuma(partitioner.chType) && ((cu.lfnstIdx == 0) || allowLfnstWithMip(cu.firstPU->lumaSize()));//是否允许开启MIP
const bool testMip = mipAllowed && !(cu.lwidth() > (8 * cu.lheight()) || cu.lheight() > (8 * cu.lwidth()));//是否测试MIP
const bool supportedMipBlkSize = pu.lwidth() <= MIP_MAX_WIDTH && pu.lheight() <= MIP_MAX_HEIGHT;//当前块大小是否支持开启MIP

static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeList;//存储着以化简版RDcost为指标的模式候选列表的模式信息,按指标从小往大排

int numModesForFullRD = 3;//以化简版RDcost为指标的模式候选列表的长度
numModesForFullRD = g_aucIntraModeNumFast_UseMPM_2D[uiWidthBit - MIN_CU_LOG2][uiHeightBit - MIN_CU_LOG2];

numModesAvailable:亮度预测的大部分模式,即DC+Planar+65种角度模式

fastMip:是否使用MIP的快速算法,默认是不开启的

testMip:是否测试MIP

supportedMipBlkSize:当前块大小是否支持开启MIP

uiRdModeList:存储着以化简版RDcost为指标的模式候选列表的模式信息,按指标从小往大排

numModesForFullRD:以化简版RDcost为指标的模式候选列表的长度,这个是会变动的


2. 用化简版RDcost筛选出模式候选列表

if (mtsUsageFlag != 2)
{
   
}
else   // mtsUsage = 2 (here we potentially reduce the number of modes that will be full-RD checked)
{
   
    if ((m_pcEncCfg->getUseFastLFNST() || !cu.slice->isIntra()) && m_bestModeCostValid[lfnstIdx])
    {
   
        numModesForFullRD = 0;

        double thresholdSkipMode = 1.0 + ((cu.lfnstIdx > 0) ? 0.1 : 1.0) * (1.4 / sqrt((double) (width * height)));

        // Skip checking the modes with much larger R-D cost than the best mode
        for (int i = 0; i < m_savedNumRdModes[lfnstIdx]; i++)
        {
   
            if (m_modeCostStore[lfnstIdx][i] <= thresholdSkipMode * m_be
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值