HM编码器代码阅读(37)——帧内预测(四)帧内预测之候选模式列表的建立

来源:互联网 发布:360软件强力卸载 编辑:程序博客网 时间:2024/04/30 22:03

候选模式列表的建立


注意:如果没有特别说明,操作的对象都是亮度块(Luma)


     帧内预测也可以分成两种方式,一种是常规方式,另一种是快速方式

在常规方式


    所有的35种帧内预测模式都被添加到候选模式列表中,在后续的惭怍中,对每一个模式都进行预测、变换、量化等操作,速度很慢。

    相关代码在estIntraPredQT函数中

UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ];//8Bool doFastSearch = (numModesForFullRD != numModesAvailable);//true// 使用快速模式if (doFastSearch){// 省略快速模式的实现代码}// 使用常规方式else{for( Int i=0; i < numModesForFullRD; i++){uiRdModeList[i] = i;}}



在快速方式


    先遍历35种帧内预测模式,对于每一种模式都进行预测操作,选出代价最优的几种模式作为候选模式,添加到候选模式列表中。

    同时,因为相邻的PU通常具有很强的相关性,因此,可以使用相邻PU的帧内模式来预测当前PU的帧内模式。预测之后可以得到若干个模式,把这些模式加入模式候选列表中。

    在后续的操作中,只对这几种模式进行预测、变换、量化等操作,因为候选列表中的模式的数量比较少,因此速度会很快。


    相关代码在estIntraPredQT函数中

UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ];//8Bool doFastSearch = (numModesForFullRD != numModesAvailable);//true// 使用快速模式if (doFastSearch){assert(numModesForFullRD < numModesAvailable);for( Int i=0; i < numModesForFullRD; i++ ) {// 用于存储每一种模式的消耗CandCostList[ i ] = MAX_DOUBLE;}CandNum = 0;// 遍历35种帧内预测模式,选取若干个代价比较小的模式作为后续处理的模式for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) // 总共有35种模式,numModesAvailable = 35{UInt uiMode = modeIdx;// 对亮度块进行预测predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );// use hadamard transform here// 使用hadamard变换,计算SATD的值UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );UInt   iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );// 计算此种模式的代价Double cost      = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();// 更新候选列表CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );}#if FAST_UDI_USE_MPMInt uiPreds[3] = {-1, -1, -1};Int iMode = -1;// 根据相邻块的预测模式来对当前块的模式进行预测,得到若干模式(称为预测模式),存放在uiPreds中Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode );if( iMode >= 0 ){// 将候选列表的索引设置为此模式numCand = iMode;}// 遍历预测的模式,如果它不在模式候选列表中,那么把它添加到模式候选列表中for( Int j=0; j < numCand; j++){Bool mostProbableModeIncluded = false;Int mostProbableMode = uiPreds[j];for( Int i=0; i < numModesForFullRD; i++){mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);}if (!mostProbableModeIncluded){uiRdModeList[numModesForFullRD++] = mostProbableMode;}}#endif // FAST_UDI_USE_MPM}// 使用常规方式else{for( Int i=0; i < numModesForFullRD; i++){uiRdModeList[i] = i;}}

从所有的35种模式中选出若干最优模式

// 遍历35种帧内预测模式,选取若干个代价比较小的模式作为后续处理的模式for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) // 总共有35种模式,numModesAvailable = 35{UInt uiMode = modeIdx;// 对亮度块进行预测predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );// use hadamard transform here// 使用hadamard变换,计算SATD的值UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );UInt   iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );// 计算此种模式的代价Double cost      = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();// 更新候选列表CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );}

亮度块的帧内预测函数

// 亮度块的帧内预测Void TComPrediction::predIntraLumaAng(TComPattern* pcTComPattern, UInt uiDirMode, Pel* piPred, UInt uiStride, Int iWidth, Int iHeight, Bool bAbove, Bool bLeft ){Pel *pDst = piPred;Int *ptrSrc;assert( g_aucConvertToBit[ iWidth ] >= 0 ); //   4x  4assert( g_aucConvertToBit[ iWidth ] <= 5 ); // 128x128assert( iWidth == iHeight  );// 获取数据的指针ptrSrc = pcTComPattern->getPredictorPtr( uiDirMode, g_aucConvertToBit[ iWidth ] + 2, m_piYuvExt );// get starting pixel in block// 获取块中的开始像素Int sw = 2 * iWidth + 1; // 9// Create the prediction// 如果指定了planar模式if ( uiDirMode == PLANAR_IDX ){// planar预测模式xPredIntraPlanar( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight );}else{// 没有指定planar模式// 区分水平或者垂直模式进行预测if ( (iWidth > 16) || (iHeight > 16) ){xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, false );}else{xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, true );// 观察是否为DC模式if( (uiDirMode == DC_IDX ) && bAbove && bLeft ){// 对DC模式进行滤波xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight);}}}}


模式的预测

    因为相邻的PU通常具有很强的相关性,因此,可以使用相邻PU的帧内模式来预测当前PU的帧内模式。预测之后可以得到若干个模式,把这些模式加入模式候选列表中。

    相关代码在estIntraPredQT函数中

Int uiPreds[3] = {-1, -1, -1};Int iMode = -1;// 根据相邻块的预测模式来对当前块的模式进行预测,得到若干模式(称为预测模式),存放在uiPreds中Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode );if( iMode >= 0 ){// 将候选列表的索引设置为此模式numCand = iMode;}// 遍历预测的模式,如果它不在模式候选列表中,那么把它添加到模式候选列表中for( Int j=0; j < numCand; j++){Bool mostProbableModeIncluded = false;Int mostProbableMode = uiPreds[j];for( Int i=0; i < numModesForFullRD; i++){mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);}if (!mostProbableModeIncluded){uiRdModeList[numModesForFullRD++] = mostProbableMode;}}

模式预测函数

预测的步骤如下:

1、假设当前块的左边是A,上面的是B,candList数组用于存放预测的模式    
2、如果modeA==modeB
    (1)modeA和modeB都是planar或者DC模式,那么candList[0] =planar,candList[1]=DC,candList[2]=26
    (2)modeA和modeB都是角度模式,那么,candList[0]=modeA,candList[1]和candList[2]等于modeA相邻的两个模式
3、如果modeA!=modeB,那么candList[0]=modeA,candList[1]=modeB,candList[2]则要分几种情况
   (1)modeA和modeB都不是planar模式,那么candList[2]=planar
   (2)当(1)不满足,而且modeA和modeB都不是DC模式,那么candList[2]=DC
   (3)当(1)和(2)不满足,candList[2]=26

Int TComDataCU::getIntraDirLumaPredictor( UInt uiAbsPartIdx, Int* uiIntraDirPred, Int* piMode  ){TComDataCU* pcTempCU;UInt        uiTempPartIdx;Int         iLeftIntraDir, iAboveIntraDir;Int         uiPredNum = 0;// Get intra direction of left PUpcTempCU = getPULeft( uiTempPartIdx, m_uiAbsIdxInLCU + uiAbsPartIdx );iLeftIntraDir  = pcTempCU ? ( pcTempCU->isIntra( uiTempPartIdx ) ? pcTempCU->getLumaIntraDir( uiTempPartIdx ) : DC_IDX ) : DC_IDX;// Get intra direction of above PUpcTempCU = getPUAbove( uiTempPartIdx, m_uiAbsIdxInLCU + uiAbsPartIdx, true, true );iAboveIntraDir = pcTempCU ? ( pcTempCU->isIntra( uiTempPartIdx ) ? pcTempCU->getLumaIntraDir( uiTempPartIdx ) : DC_IDX ) : DC_IDX;uiPredNum = 3;if(iLeftIntraDir == iAboveIntraDir){if( piMode ){*piMode = 1;}if (iLeftIntraDir > 1) // angular modes{uiIntraDirPred[0] = iLeftIntraDir;uiIntraDirPred[1] = ((iLeftIntraDir + 29) % 32) + 2;uiIntraDirPred[2] = ((iLeftIntraDir - 1 ) % 32) + 2;}else //non-angular{uiIntraDirPred[0] = PLANAR_IDX;uiIntraDirPred[1] = DC_IDX;uiIntraDirPred[2] = VER_IDX; }}else{if( piMode ){*piMode = 2;}uiIntraDirPred[0] = iLeftIntraDir;uiIntraDirPred[1] = iAboveIntraDir;if (iLeftIntraDir && iAboveIntraDir ) //both modes are non-planar{uiIntraDirPred[2] = PLANAR_IDX;}else{uiIntraDirPred[2] =  (iLeftIntraDir+iAboveIntraDir)<2? VER_IDX : DC_IDX;}}return uiPredNum;}



1 0
原创粉丝点击