HM16.0之帧间预测——xCheckRDCostInter()函数
参考:https://blog.csdn.net/nb_vol_1/article/category/6179825/1?
1、源代码:
#if AMP_MRG Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG) #else Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize ) #endif {DEBUG_STRING_NEW(sTest) // 对rpcTempCU进行初始化UChar uhDepth = rpcTempCU->getDepth( 0 );rpcTempCU->setDepthSubParts( uhDepth, 0 );rpcTempCU->setSkipFlagSubParts( false, 0, uhDepth );rpcTempCU->setPartSizeSubParts ( ePartSize, 0, uhDepth );rpcTempCU->setPredModeSubParts ( MODE_INTER, 0, uhDepth );rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uhDepth );#if AMP_MRG // 进行Inter整像素搜索rpcTempCU->setMergeAMP (true);m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] DEBUG_STRING_PASS_INTO(sTest), false, bUseMRG ); #elsem_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] ); #endif#if AMP_MRGif ( !rpcTempCU->getMergeAMP() ){return;} #endif // 计算普通Inter模式残差及RDCostm_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false DEBUG_STRING_PASS_INTO(sTest) );// 存储总代价 rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );#ifdef DEBUG_STRINGDebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0))); #endif // DeltaQP检测xCheckDQP( rpcTempCU ); // 检测并设置最优模式xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest)); }
2、PartSize:
/// supported partition shape/// AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N) enum PartSize {SIZE_2Nx2N = 0, ///< symmetric motion partition, 2Nx2N SIZE_2NxN = 1, ///< symmetric motion partition, 2Nx N SIZE_Nx2N = 2, ///< symmetric motion partition, Nx2N SIZE_NxN = 3, ///< symmetric motion partition, Nx N SIZE_2NxnU = 4, ///< asymmetric motion partition, 2Nx( N/2) + 2Nx(3N/2) SIZE_2NxnD = 5, ///< asymmetric motion partition, 2Nx(3N/2) + 2Nx( N/2) SIZE_nLx2N = 6, ///< asymmetric motion partition, ( N/2)x2N + (3N/2)x2N SIZE_nRx2N = 7, ///< asymmetric motion partition, (3N/2)x2N + ( N/2)x2N NUMBER_OF_PART_SIZES = 8 };
3、帧间搜索predInterSearch:
// predInterSearch函数的主要工作是ME(运动估计)和MC(运动补偿)// 帧间搜索最佳候选/** search of the best candidate for inter prediction* \param pcCU* \param pcOrgYuv* \param rpcPredYuv* \param rpcResiYuv* \param rpcRecoYuv* \param bUseRes* \returns Void*/ #if AMP_MRG Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG ) #else Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes ) #endif {for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++){m_acYuvPred[i].clear();}m_cYuvPredTemp.clear();rpcPredYuv->clear();if ( !bUseRes ){rpcResiYuv->clear();}rpcRecoYuv->clear();TComMv cMvSrchRngLT; // 左上TComMv cMvSrchRngRB; // 右下TComMv cMvZero;TComMv TempMv; //kolya TComMv cMv[2];TComMv cMvBi[2];TComMv cMvTemp[2][33];Int iNumPart = pcCU->getNumPartitions(); // 分块数Int iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2; // 预测方向,P帧为1,B帧为2TComMv cMvPred[2][33]; // 记录前向参考帧的MVTComMv cMvPredBi[2][33]; // 记录后向参考帧的MVInt aaiMvpIdxBi[2][33]; // 记录后向参考帧的MVP索引Int aaiMvpIdx[2][33]; // 记录前向参考帧的MVP索引Int aaiMvpNum[2][33]; // 记录MVP的数量AMVPInfo aacAMVPInfo[2][33]; // 记录AMVP的信息Int iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.Int iRefIdxBi[2];UInt uiPartAddr;Int iRoiWidth, iRoiHeight;UInt uiMbBits[3] = {1, 1, 0};UInt uiLastMode = 0;Int iRefStart, iRefEnd;PartSize ePartSize = pcCU->getPartitionSize( 0 );Int bestBiPRefIdxL1 = 0;Int bestBiPMvpL1 = 0;Distortion biPDistTemp = std::numeric_limits<Distortion>::max(); // 将失真置为最大#if ZERO_MVD_ESTInt aiZeroMvdMvpIdx[2] = {-1, -1};Int aiZeroMvdRefIdx[2] = {0, 0};Int iZeroMvdDir = -1; #endifTComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists 为了双向MV,长度为2倍 UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];Int numValidMergeCand = 0 ; // 初始化,将所有分块的失真都置为最大for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ){Distortion uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };Distortion uiCostBi = std::numeric_limits<Distortion>::max();Distortion uiCostTemp;UInt uiBits[3];UInt uiBitsTemp; #if ZERO_MVD_ESTDistortion uiZeroMvdCost = std::numeric_limits<Distortion>::max();Distortion uiZeroMvdCostTemp;UInt uiZeroMvdBitsTemp;Distortion uiZeroMvdDistTemp = std::numeric_limits<Distortion>::max();UInt auiZeroMvdBits[3]; #endifDistortion bestBiPDist = std::numeric_limits<Distortion>::max();Distortion uiCostTempL0[MAX_NUM_REF];for (Int iNumRef=0; iNumRef < MAX_NUM_REF; iNumRef++) // 将各参考图像的失真置为最大{uiCostTempL0[iNumRef] = std::numeric_limits<Distortion>::max();}UInt uiBitsTempL0[MAX_NUM_REF];TComMv mvValidList1;Int refIdxValidList1 = 0;UInt bitsValidList1 = MAX_UINT;Distortion costValidList1 = std::numeric_limits<Distortion>::max(); // 获取CU块的比特数xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits); // 获取CU的宽、高、起始地址信息pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );#if AMP_MRGBool bTestNormalMC = true; // 指示是否进行正常的MC(ME+MC) // bUseMRG为真、CU大于8且分块为SIZE_2NxN时,不能进行正常的MCif ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ){bTestNormalMC = false;} // 正常MCif (bTestNormalMC){ #endif// Uni-directional prediction // 建立参考列表,P帧只有一个,B帧有两个for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) // iRefList为当前参考列表{RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); // 前向后参考列表 // 遍历这个参考列表的所有参考帧 for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) // iRefIdxTemp为当前参考帧索引{uiBitsTemp = uiMbBits[iRefList]; // 存储参考列表的比特数if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ) // 如果参考列表中的帧数大于1,计算所有参考帧的总比特数{uiBitsTemp += iRefIdxTemp+1; // 最后一帧比特数减1if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) uiBitsTemp--;} #if ZERO_MVD_ESTxEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp, &uiZeroMvdDistTemp); #else // 执行AMVP,进行MV预测和AMVP计算xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp); #endifaaiMvpIdx[iRefList][iRefIdxTemp] = pcCU->getMVPIdx(eRefPicList, uiPartAddr); // 获取MVP索引aaiMvpNum[iRefList][iRefIdxTemp] = pcCU->getMVPNum(eRefPicList, uiPartAddr); // 获取MVP数量 // 使用广义帧且失真小于最优失真时,更新最优参数if(pcCU->getSlice()->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist){bestBiPDist = biPDistTemp;bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp];bestBiPRefIdxL1 = iRefIdxTemp;}uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // 记录比特数 #if ZERO_MVD_ESTif ( iRefList == 0 || pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ){uiZeroMvdBitsTemp = uiBitsTemp;uiZeroMvdBitsTemp += 2; //zero mvd bits m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost(uiZeroMvdBitsTemp);if (uiZeroMvdCostTemp < uiZeroMvdCost){uiZeroMvdCost = uiZeroMvdCostTemp;iZeroMvdDir = iRefList + 1;aiZeroMvdRefIdx[iRefList] = iRefIdxTemp;aiZeroMvdMvpIdx[iRefList] = aaiMvpIdx[iRefList][iRefIdxTemp];auiZeroMvdBits[iRefList] = uiZeroMvdBitsTemp;}} #endif#if GPB_SIMPLE_UNIif ( iRefList == 1 ) // list 1(B帧) {if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) // 如果使用广义B帧,则list1直接复制list0的信息{cMvTemp[1][iRefIdxTemp] = cMvTemp[0][pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )];uiCostTemp = uiCostTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )];/*first subtract the bit-rate part of the cost of the other list*/uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )] );/*correct the bit-rate part of the current ref*/m_pcRdCost->setPredictor ( cMvPred[iRefList][iRefIdxTemp] );uiBitsTemp += m_pcRdCost->getBits( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer() );/*calculate the correct cost*/uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );}else{xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );}} // 不使用广义B帧就直接进行运动估计xMotionEstimationelse{xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );} #elsexMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); #endif // 将AMVP信息写入当前CU,并检查是否是最优MVPxCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE ) xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); // 更新失真和比特信息if ( iRefList == 0 ){uiCostTempL0[iRefIdxTemp] = uiCostTemp;uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;}if ( uiCostTemp < uiCost[iRefList] ){uiCost[iRefList] = uiCostTemp;uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction// set motioncMv[iRefList] = cMvTemp[iRefList][iRefIdxTemp];iRefIdx[iRefList] = iRefIdxTemp;}if ( iRefList == 1 && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ){costValidList1 = uiCostTemp;bitsValidList1 = uiBitsTemp;// set motionmvValidList1 = cMvTemp[iRefList][iRefIdxTemp];refIdxValidList1 = iRefIdxTemp;}}}// Bi-directional prediction 双向预测if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ) // isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N){cMvBi[0] = cMv[0]; cMvBi[1] = cMv[1];iRefIdxBi[0] = iRefIdx[0]; iRefIdxBi[1] = iRefIdx[1];::memcpy(cMvPredBi, cMvPred, sizeof(cMvPred));::memcpy(aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx));UInt uiMotBits[2]; // 使用广义B帧,则进行运动补偿motionCompensationif(pcCU->getSlice()->getMvdL1ZeroFlag()){xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());pcCU->setMVPIdxSubParts( bestBiPMvpL1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;cMvPredBi[1][bestBiPRefIdxL1] = pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()->m_acMvCand[bestBiPMvpL1];cMvBi[1] = cMvPredBi[1][bestBiPRefIdxL1];iRefIdxBi[1] = bestBiPRefIdxL1;pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv* pcYuvPred = &m_acYuvPred[REF_PIC_LIST_1];motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );uiMotBits[0] = uiBits[0] - uiMbBits[0];uiMotBits[1] = uiMbBits[1];if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 ){uiMotBits[1] += bestBiPRefIdxL1+1;if ( bestBiPRefIdxL1 == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1 ) uiMotBits[1]--;}uiMotBits[1] += m_auiMVPIdxCost[aaiMvpIdxBi[1][bestBiPRefIdxL1]][AMVP_MAX_NUM_CANDS];uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];cMvTemp[1][bestBiPRefIdxL1] = cMvBi[1];}else{uiMotBits[0] = uiBits[0] - uiMbBits[0];uiMotBits[1] = uiBits[1] - uiMbBits[1];uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];}// 4-times iteration (default) 默认4次迭代Int iNumIter = 4; // 如果不使用广义B帧技术,且是第一次迭代,则进行运动补偿// fast encoder setting: only one iterationif ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag()){iNumIter = 1;}for ( Int iIter = 0; iIter < iNumIter; iIter++ ){Int iRefList = iIter % 2;if ( m_pcEncCfg->getUseFastEnc() ) // 使用快速编码,则选择代价大的list{if( uiCost[0] <= uiCost[1] ){iRefList = 1;}else{iRefList = 0;}}else if ( iIter == 0 ) // 如果是整个子块,则选择list0{iRefList = 0;}if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag()) // 如果是第一个子块且list1不为空,进行list0的运动补偿{pcCU->getCUMvField(RefPicList(1-iRefList))->setAllMv( cMv[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(RefPicList(1-iRefList))->setAllRefIdx( iRefIdx[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv* pcYuvPred = &m_acYuvPred[1-iRefList];motionCompensation ( pcCU, pcYuvPred, RefPicList(1-iRefList), iPartIdx );}RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );if(pcCU->getSlice()->getMvdL1ZeroFlag()){iRefList = 0;eRefPicList = REF_PIC_LIST_0;}Bool bChanged = false;iRefStart = 0; // 起始参考帧iRefEnd = pcCU->getSlice()->getNumRefIdx(eRefPicList)-1; // 结束参考帧 // 遍历所有参考帧进行运动估计for ( Int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ ){uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList]; // 更新比特信息if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ){uiBitsTemp += iRefIdxTemp+1;if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) uiBitsTemp--;}uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];// call ME 运动估计xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true ); // 找最优MVPxCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo());xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); // 如果代价更小,且不是第一个子块,则进行运动补偿if ( uiCostTemp < uiCostBi ){bChanged = true;cMvBi[iRefList] = cMvTemp[iRefList][iRefIdxTemp];iRefIdxBi[iRefList] = iRefIdxTemp;uiCostBi = uiCostTemp;uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList];uiBits[2] = uiBitsTemp;if(iNumIter!=1){// Set motionpcCU->getCUMvField( eRefPicList )->setAllMv( cMvBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( eRefPicList )->setAllRefIdx( iRefIdxBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv* pcYuvPred = &m_acYuvPred[iRefList];motionCompensation( pcCU, pcYuvPred, eRefPicList, iPartIdx );}}} // for loop-iRefIdxTemp // 如果找到更优的代价,则复制AMVP选出最优的MVPif ( !bChanged ){if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ){xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], pcCU->getCUMvField(REF_PIC_LIST_0)->getAMVPInfo());xCheckBestMVP(pcCU, REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi);if(!pcCU->getSlice()->getMvdL1ZeroFlag()){xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());xCheckBestMVP(pcCU, REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], uiBits[2], uiCostBi);}}break;}} // for loop-iter} // if (B_SLICE) #if ZERO_MVD_ESTif ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ){m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );for ( Int iL0RefIdxTemp = 0; iL0RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)-1; iL0RefIdxTemp++ )for ( Int iL1RefIdxTemp = 0; iL1RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1; iL1RefIdxTemp++ ){UInt uiRefIdxBitsTemp = 0;if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0) > 1 ){uiRefIdxBitsTemp += iL0RefIdxTemp+1;if ( iL0RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)-1 ) uiRefIdxBitsTemp--;}if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 ){uiRefIdxBitsTemp += iL1RefIdxTemp+1;if ( iL1RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1 ) uiRefIdxBitsTemp--;}Int iL0MVPIdx = 0;Int iL1MVPIdx = 0;for (iL0MVPIdx = 0; iL0MVPIdx < aaiMvpNum[0][iL0RefIdxTemp]; iL0MVPIdx++){for (iL1MVPIdx = 0; iL1MVPIdx < aaiMvpNum[1][iL1RefIdxTemp]; iL1MVPIdx++){uiZeroMvdBitsTemp = uiRefIdxBitsTemp;uiZeroMvdBitsTemp += uiMbBits[2];uiZeroMvdBitsTemp += m_auiMVPIdxCost[iL0MVPIdx][aaiMvpNum[0][iL0RefIdxTemp]] + m_auiMVPIdxCost[iL1MVPIdx][aaiMvpNum[1][iL1RefIdxTemp]];uiZeroMvdBitsTemp += 4; //zero mvd for both directionspcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( aacAMVPInfo[0][iL0RefIdxTemp].m_acMvCand[iL0MVPIdx], iL0RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( aacAMVPInfo[1][iL1RefIdxTemp].m_acMvCand[iL1MVPIdx], iL1RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, 0 );xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiZeroMvdDistTemp, m_pcEncCfg->getUseHADME() );uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost( uiZeroMvdBitsTemp );if (uiZeroMvdCostTemp < uiZeroMvdCost){uiZeroMvdCost = uiZeroMvdCostTemp;iZeroMvdDir = 3;aiZeroMvdMvpIdx[0] = iL0MVPIdx;aiZeroMvdMvpIdx[1] = iL1MVPIdx;aiZeroMvdRefIdx[0] = iL0RefIdxTemp;aiZeroMvdRefIdx[1] = iL1RefIdxTemp;auiZeroMvdBits[2] = uiZeroMvdBitsTemp;}}}}} #endif#if AMP_MRG} //end if bTestNormalMC #endif // 设置MV信息// Clear Motion FieldpcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));UInt uiMEBits = 0;// Set Motion Field_cMv[1] = mvValidList1;iRefIdx[1] = refIdxValidList1;uiBits[1] = bitsValidList1;uiCost[1] = costValidList1;#if AMP_MRG// 设置MV、MVP、MVD信息if (bTestNormalMC){ #endif #if ZERO_MVD_ESTif (uiZeroMvdCost <= uiCostBi && uiZeroMvdCost <= uiCost[0] && uiZeroMvdCost <= uiCost[1]){if (iZeroMvdDir == 3){uiLastMode = 2;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[0][aiZeroMvdRefIdx[0]].m_acMvCand[aiZeroMvdMvpIdx[0]], aiZeroMvdRefIdx[0], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[1][aiZeroMvdRefIdx[1]].m_acMvCand[aiZeroMvdMvpIdx[1]], aiZeroMvdRefIdx[1], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[0], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][aiZeroMvdRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[1], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][aiZeroMvdRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[2];}else if (iZeroMvdDir == 1){uiLastMode = 0;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[0][aiZeroMvdRefIdx[0]].m_acMvCand[aiZeroMvdMvpIdx[0]], aiZeroMvdRefIdx[0], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[0], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][aiZeroMvdRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[0];}else if (iZeroMvdDir == 2){uiLastMode = 1;pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[1][aiZeroMvdRefIdx[1]].m_acMvCand[aiZeroMvdMvpIdx[1]], aiZeroMvdRefIdx[1], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[1], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][aiZeroMvdRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[1];}else{assert(0);}}else #endifif ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]){uiLastMode = 2;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMvBi[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdxBi[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx ); // 计算并存储MVDTempMv = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]];pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]];pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdxBi[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( aaiMvpIdxBi[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[2];}else if ( uiCost[0] <= uiCost[1] ){uiLastMode = 0;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMv[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdx[0], ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMv[0] - cMvPred[0][iRefIdx[0]];pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdx[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[0];}else{uiLastMode = 1;pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMv[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdx[1], ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMv[1] - cMvPred[1][iRefIdx[1]];pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdx[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[1];} #if AMP_MRG} // end if bTestNormalMC #endif // 如果不是2Nx2N,即一个CU会被划分为多个PU,则应该计算并合并它们的运动估计代价if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N ){UInt uiMRGInterDir = 0;TComMvField cMRGMvField[2];UInt uiMRGIndex = 0;UInt uiMEInterDir = 0;TComMvField cMEMvField[2];m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );#if AMP_MRG// calculate ME costDistortion uiMEError = std::numeric_limits<Distortion>::max();Distortion uiMECost = std::numeric_limits<Distortion>::max();if (bTestNormalMC){// xGetInterPredictionError中进行了运动补偿xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );} #else// calculate ME costDistortion uiMEError = std::numeric_limits<Distortion>::max();xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );Distortion uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits ); #endif// save ME result.uiMEInterDir = pcCU->getInterDir( uiPartAddr );pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_0, cMEMvField[0] );pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[1] );// find Merge resultDistortion uiMRGCost = std::numeric_limits<Distortion>::max(); // 合并估计信息xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand); // 设置运动估计的结果if ( uiMRGCost < uiMECost ){// set Merge resultpcCU->setMergeFlagSubParts ( true, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->setMergeIndexSubParts( uiMRGIndex, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->setInterDirSubParts ( uiMRGInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMRGMvField[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMRGMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));}else{// set ME resultpcCU->setMergeFlagSubParts( false, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->setInterDirSubParts ( uiMEInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMEMvField[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );}}// MC 运动补偿 motionCompensation ( pcCU, rpcPredYuv, REF_PIC_LIST_X, iPartIdx );} // end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ) // 设置加权预测setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );return; }
4、xEstimateMvPredAMVP(AMVP的入口函数,执行AMVP操作):
// AMVP #if ZERO_MVD_EST Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP, Distortion* puiDist ) #else Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP ) #endif {AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo();TComMv cBestMv;Int iBestIdx = 0;TComMv cZeroMv;TComMv cMvPred;Distortion uiBestCost = std::numeric_limits<Distortion>::max();UInt uiPartAddr = 0;Int iRoiWidth, iRoiHeight;Int i; // 得到此次分割的索引和大小pcCU->getPartIndexAndSize( uiPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );// Fill the MV Candidates // 获取MVP(即预测的MV),MVP存放在pcAMVPInfo中if (!bFilled){pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, pcAMVPInfo );}// initialize Mvp index & Mvp // 最优MVP的默认索引为0iBestIdx = 0; // 最优MVP默认是列表第一个cBestMv = pcAMVPInfo->m_acMvCand[0]; #if !ZERO_MVD_EST // 如果MVP候选列表中MVP的数量是0或者1if (pcAMVPInfo->iN <= 1){ // 得到了最优的MVPrcMvPred = cBestMv;pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); // 如果参考列表是list1(表示这是B Slice)if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefPicList==REF_PIC_LIST_1){(*puiDistBiP) = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);}return;} #endif// 如果MVP候选列表已经填充完毕,那么直接返回MVP就行了 // 注意:fillMvpCand并不会修改bFilled的值,bFilled的值是函数传进来的if (bFilled){assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0); // 选择相应的MVPrcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)];return;}m_cYuvPredTemp.clear(); #if ZERO_MVD_ESTDistortion uiDist; #endif//-- Check Minimum Cost. // 遍历每一个MVP,选出代价最小的那个for ( i = 0 ; i < pcAMVPInfo->iN; i++){Distortion uiTmpCost; #if ZERO_MVD_ESTuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight, uiDist ); #elseuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight); #endifif ( uiBestCost > uiTmpCost ){uiBestCost = uiTmpCost;cBestMv = pcAMVPInfo->m_acMvCand[i];iBestIdx = i;(*puiDistBiP) = uiTmpCost; #if ZERO_MVD_EST(*puiDist) = uiDist; #endif}}m_cYuvPredTemp.clear();// Setting Best MVPrcMvPred = cBestMv;pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));return; }
5、xMotionEstimation(运动估计的入口函数,进行运动搜索,找到MV):
Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, Distortion& ruiCost, Bool bBi ) {UInt uiPartAddr;Int iRoiWidth;Int iRoiHeight;TComMv cMvHalf, cMvQter; // 定义1/2和1/4精度MVTComMv cMvSrchRngLT;TComMv cMvSrchRngRB;TComYuv* pcYuv = pcYuvOrg; // 图像首地址assert(eRefPicList < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdxPred<Int(MAX_IDX_ADAPT_SR));m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred]; // 根据参考帧列表类型、参考帧序号自适应设置搜索范围Int iSrchRng = ( bBi ? m_bipredSearchRange : m_iSearchRange ); // 根据是否是双向预测设置搜索范围TComPattern tmpPattern;TComPattern* pcPatternKey = &tmpPattern; // TComPattern是用于访问相邻块/像素的一个工具类,用于获取neighbor的信息Double fWeight = 1.0;pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); // 获取PU的地址,宽度和高度 if ( bBi ) // B帧{TComYuv* pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList];pcYuv = &m_cYuvPredTemp;pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight );pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight );fWeight = 0.5;}// Search key pattern initialization // 初始化待搜索的PU的首地址,宽度,高度,跨度,比特深度pcPatternKey->initPattern( pcYuv->getAddr ( COMPONENT_Y, uiPartAddr ),iRoiWidth,iRoiHeight,pcYuv->getStride(COMPONENT_Y) ); // 获取参考图像首地址和跨度Pel* piRefY = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getAddr(), pcCU->getZorderIdxInCU() + uiPartAddr );Int iRefStride = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride(COMPONENT_Y);TComMv cMvPred = *pcMvPred; // 设置运动估计的搜索范围,LeftTop & RightBottomif ( bBi ) xSetSearchRange ( pcCU, rcMv , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );else xSetSearchRange ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB );m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) ); // 计算率失真代价m_pcRdCost->setPredictor ( *pcMvPred ); // 设置预测得到的MVm_pcRdCost->setCostScale ( 2 );setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList ); // 设置跟weighted prediction相关的参数// Do integer search // 整像素搜索if ( !m_iFastSearch || bBi ){ // 如果是B帧或者不是快速搜索模式,进行常规搜索 xPatternSearch ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );}else{ // 进行快速搜索rcMv = *pcMvPred;const TComMv *pIntegerMv2Nx2NPred=0;if (pcCU->getPartitionSize(0) != SIZE_2Nx2N || pcCU->getDepth(0) != 0){ #if RExt__BACKWARDS_COMPATIBILITY_MOTION_ESTIMATION_R0105const Profile::Name profileIdc=pcCU->getSlice()->getSPS()->getPTL()->getGeneralPTL()->getProfileIdc(); // TODO: RExt - temporary profile check to ensure backwards compatibility with HM.if (profileIdc != Profile::MAIN && profileIdc != Profile::MAIN10 && profileIdc != Profile::MAINSTILLPICTURE) #endifpIntegerMv2Nx2NPred = &(m_integerMv2Nx2N[eRefPicList][iRefIdxPred]);}xPatternSearchFast ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost, pIntegerMv2Nx2NPred );if (pcCU->getPartitionSize(0) == SIZE_2Nx2N){m_integerMv2Nx2N[eRefPicList][iRefIdxPred] = rcMv;}}m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );m_pcRdCost->setCostScale ( 1 );const Bool bIsLosslessCoded = pcCU->getCUTransquantBypass(uiPartAddr) != 0;xPatternSearchFracDIF( bIsLosslessCoded, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost ,bBi ); // 分像素搜索m_pcRdCost->setCostScale( 0 );rcMv <<= 2; // 整像素rcMv += (cMvHalf <<= 1); // 1/2像素rcMv += cMvQter; // 1/4像素,最终MV单位为1/4精度UInt uiMvBits = m_pcRdCost->getBits( rcMv.getHor(), rcMv.getVer() );ruiBits += uiMvBits;ruiCost = (Distortion)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) ); }
6、motionCompensation(运动补偿的入口函数,进行运动补偿,构造匹配块信息):
Void TComPrediction::motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList, Int iPartIdx ) {Int iWidth;Int iHeight;UInt uiPartAddr; // 如果PU的索引是有效值,那么直接处理该PU,然后返回if ( iPartIdx >= 0 ){pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); // 有效的参考列表,即明确地标明了使用哪个参考列表,那么就在对应方向上进行单向预测if ( eRefPicList != REF_PIC_LIST_X ){ // 先进行插值操作if( pcCU->getSlice()->getPPS()->getUseWP()){xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true );}else{xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );} // 加权预测if ( pcCU->getSlice()->getPPS()->getUseWP() ){xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );}} // 没有指明明确的参考列表,那么判断PU两个方向上的参考帧是否一样else{ // 如果PU的两个参考列表是相同的,即它们的运动是一致的,那么直接使用单向预测if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ){xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );} // 否则使用双向预测else{xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );}}return;} // 否则处理CU下的所有PUfor ( iPartIdx = 0; iPartIdx < pcCU->getNumPartitions(); iPartIdx++ ){pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight );if ( eRefPicList != REF_PIC_LIST_X ){if( pcCU->getSlice()->getPPS()->getUseWP()){xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true );}else{xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );}if ( pcCU->getSlice()->getPPS()->getUseWP() ){xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );}}else{if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ){xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );}else{xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );}}}return; }
转载于:https://www.cnblogs.com/lucifer1997/p/10993771.html
HM16.0之帧间预测——xCheckRDCostInter()函数相关推荐
- HEVC代码学习:帧间预测——MVP过程中MV的获取、传递及存储
作为一个视频编码小白,最近开始着手啃HEVC帧间预测的代码,想用博客记录一下自己的学习过程,也想与大家分享.交流一下. HEVC代码的学习主要是参考两位大神岳麓吹雪.NB_vol_1的博客以及HM参考 ...
- HM编码器代码阅读(32)——帧间预测之AMVP/Merge模式(七)encodeResAndCalcRdInterCU函数:残差计算、变换量化
encodeResAndCalcRdInterCU 原理和细节 经过运动估计.运动补偿,我们得到了MV以及参考块,那么接下来是计算残差.计算MVD,然后对系数进行变换.量化. encodeResAnd ...
- 【VTM10.0代码学习】帧间预测xCheckRdCostMerge2N*2N
xCheckRdCostMerge函数在xCompressCU中被调用,这里包括了常规Merge模式.CIIP模式和MMVD模式,GPM在xCheckRDCostGeo函数中.也就是说常规Merg ...
- SVAC1.0帧间预测技术分析
###Date:2017/10/21 ###Content:SVAC1.0帧间预测技术分析 1.参考帧选择 P条带或B条带最多可有两个参考帧或四个参考场.,它们应为最临近当前解码图像的参考帧或参考场. ...
- HEVC参考软件HM源码分析--帧间预测(1)--xCompressCU
本文首先对HM中帧间预测的基本流程作简要介绍,接着对代码中关键变量的用途作出说明,最后以源代码+注释的形式进行具体分析. 备注:这位大神的博客对楼主帮助很大,解决了我的不少疑惑,最后才能顺利写下这篇博 ...
- HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程
帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...
- H.266/VVC帧间预测总结
一.帧间预测基本原理 帧间预测是利用视频帧与帧之间的相关性,去除视频帧间的时间冗余信息.统计表明,帧间差绝对值超过3的像素平均不到一帧像素的4%,因此,采用高效的帧间编码方式,可以很大程度上提高视频压 ...
- HEVC参考软件HM源码分析--帧间预测(3)--predInterSearch
帧间预测基本知识 对帧间预测有所了解的同学应该都知道,帧间预测操作一般都是由两个最基本也是最核心的操作组成:运动估计(ME)和运动补偿(MC). 运动估计:负责找到当前帧和参考帧之间的匹配运动矢量(M ...
- HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取
帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...
最新文章
- ubuntu 使用阿里云 apt 源
- Android Json生成及解析实例
- winform修改、打开窗体、构造函数传值
- jsp:include标签与include指令的区别
- websocket python unity_Unity中Websocket的简单使用
- 如何在悬停而不是单击时使Twitter Bootstrap菜单下拉列表
- linux安装 web2py,TurnkeyLinux上用于Web2Py到MySQL的DAL连接字符串
- 《麦肯锡方法》第1章建立解决方案-思维导图
- 学习数码相框1.3.0.0在LCD上显示一个矢量字体_在LCD上显示多行文字
- 公文排版插件for Word/WPS【快点公文助手——让公文排版更快一点】
- Python 爬取科技部计划申报指南pdf文件并作词频分析
- 揭秘小红书的种草套路
- 嵌入式系统概述3-嵌入式系统的开发流程和学习基础、方法
- 数学分析第一型曲面积分2021.6.5
- 今日头条Android适配方案,android 今日头条的屏幕适配理解
- 【SAMF】A Scale Adaptive Kernel Correlation Filter Tracker with Feature Integration 论文阅读笔记
- python如何读取下一行_python读取行停止,然后在下一行继续
- 韩信点兵(hanxin)
- 微信小程序 自定义tab不煽动
- 变色龙哈希函数Chameleon Hash Functions
热门文章
- 深入struts2.0(七)--ActionInvocation接口以及3DefaultActionInvocation类
- 编写高性能的 Lua 代码
- 安卓入门笔记之Activity
- UIMenuController的使用,对UILabel拷贝以及定制菜单
- 软件随想: 软件 = 程序 + 软件工程
- LOCALALLOC和GLOBALLOC有什么区别? 全局内存和局部内存有什么区别?(转)
- Java范例集锦(一)
- iosanimationWithKeyPath
- 数据挖掘经典算法——先验算法
- div嵌套div 背景图片 不显示的问题