简介
predInterSearch主要的工作是ME(运动估计)和MC(运动补偿)。
函数中有一个bTestNormalMC变量,它表示是否进行正常的MC过程,正常的MC过程就是进行ME再进行MC。 正常的MC流程是,遍历所有的参考帧,进行ME(运动估计:xEstimateMvPredAMVP和xMotionEstimation),然后记录MVP或者MV的信息,进行MC(运动补偿,目的是选出最优的参数),然后更新最优的参数,遍历完所有的参考帧之后,就选出了最优的参数了;然后循环结束,接着进行正式的MC(运动补偿)。
广义B帧技术
在高效的预测模式下,HEVC仍然采用了H.264中的B预测方式,同时还增加了广义B(Generalized P and B picture,GPB)预测方式取代低时延应用场景中的P预测方式。GPB预测结构是指对传统P帧采取类似于B帧的双向预测方式进行预测。在这种预测方式下,前向和后向参考列表中的参考图像都必须为当前图像之前的图像,且两个参考列表完全一致。对P帧采取B帧的运动预测方式增加了运动估计的准确度,提高了编码效率,同时也有利于编码流程的统一。具体细节可以参考博客:点击打开链接
函数流程
predInterSearch主要的工作是ME(运动估计)和MC(运动补偿)。 函数中有一个bTestNormalMC变量,它表示是否进行正常的MC过程,正常的MC过程就是进行ME再进行MC。 正常的MC流程是,遍历所有的参考帧,进行ME(运动估计:xEstimateMvPredAMVP和xMotionEstimation),然后记录AVP或者MV的信息,进行MC(运动补偿,目的是选出最优的参数),然后更新最优的参数,遍历完所有的参考帧之后,就选出了最优的参数了;然后循环结束,接着进行正式的MC(运动补偿)。 TEncSearch::predInterSearch的详解: (1) 定义若干变量,注意AMVPInfo和TComMv等信息,它保存者运动信息 (2) 遍历当前CU被分成的若干个PU 1) 一个帧最多可以参考16个其他的帧 2) 调用xGetBlkBits,计算CU在ePartSize模式下所需要消耗的比特数 3) 计算当前PU的索引和大小 4) 遍历两个参考图像列表(list0和list1) a)遍历当前帧的所有参考帧: ①调用xEstimateMvPredAMVP,进行MV预测和AMVP的计算 ②记录这个参考帧计算出来的MVP索引,数量等信息 ③更新最优的参数 ④计算比特数 ⑤如果使用了list1(即B帧) Ⅰ)如果list0和list1之间有映射(即这个帧同时出现在list0和list1中),那么直接把在list0中的计算信息复制过来就行了。 Ⅱ)如果没有映射,那么调用xMotionEstimation进行运动估计。 ⑥如果对于使用list0的帧(P帧和B帧),调用xMotionEstimation进行运动估计。 ⑦复制AMVP信息 ⑧选择最优的MVP ⑨设置各种计算出来的运动信息 5) 如果当前帧是B帧 a)并且list1是空的(getMvdL1ZeroFlag标志为真),那么调用motionCompensation进行运动补偿运算 b)对当前CU的4个子CU进行遍历计算: ①如果是第一个子CU,并且getMvdL1ZeroFlag为false,那么调用motionCompensation进行运动补偿计算 ②遍历当前帧的所有参考帧: Ⅰ)调用xMotionEstimation,进行运动估计 Ⅱ)调用xCopyAMVPInfo复制AMVP信息,调用xCheckBestMVP选择最好的MVP Ⅲ)如果找到了更优的方式,那么更新信息,并且如果不是第一个子CU的话,还需要调用motionCompensation进行运动补偿 ③如果没有选择出更优的代价,那么复制AMVP信息,选择最优的MVP等 6) 设置各种MV的信息 7) 同样,还是设置各种MVP以及MV的信息 8) 对于分割类型不是2Nx2N(即当前CU没有划分) a)调用xGetInterPredictionError进行运动补偿(该函数内部实质是调用motionCompensation) b)调用xMergeEstimation,合并估计信息 9) 调用motionCompensation进行运动补偿计算 (3) 调用setWpScalingDistParam,设置wp(加权预测)参数
下面的代码为了方便理解,删除了定义ZERO_MVD_EST宏才会生效的代码,以及其他的无关的代码
#if AMP_MRG Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes, Bool bUseMRG ) #else Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes ) #endif { for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ) { xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits); pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); #if AMP_MRG Bool bTestNormalMC = true ; if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ) { bTestNormalMC = false ; } if (bTestNormalMC) { #endif for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) { RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) { xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false , &biPDistTemp); #if GPB_SIMPLE_UNI // 广义B帧技术GPB,相关细节可以参考http://blog.csdn.net/yangxiao_xiang/article/details/9045777 if ( iRefList == 1 ) { if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) { } else { xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); } } else { xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); } #else // else of GPB_SIMPLE_UNI xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); #endif // end of GPB_SIMPLE_UNI xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); } } if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false ) ) { if (pcCU->getSlice()->getMvdL1ZeroFlag()) { motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx ); } else { uiMotBits[0] = uiBits[0] - uiMbBits[0]; uiMotBits[1] = uiBits[1] - uiMbBits[1]; uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1]; } Int iNumIter = 4; if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag()) { iNumIter = 1; } for ( Int iIter = 0; iIter < iNumIter; iIter++ ) { Int iRefList = iIter % 2; if ( m_pcEncCfg->getUseFastEnc() ) { if ( uiCost[0] <= uiCost[1] ) { iRefList = 1; } else { iRefList = 0; } } else if ( iIter == 0 ) { iRefList = 0; } if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag()) { 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++ ) { xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true ); xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo()); xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); if ( uiCostTemp < uiCostBi ) { } } if ( !bChanged ) { } } } #if AMP_MRG } #endif #if AMP_MRG if (bTestNormalMC) { #endif #if AMP_MRG } #endif if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N ) { #if AMP_MRG if (bTestNormalMC) { xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() ); uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits ); } #else UInt uiMEError = MAX_UINT; xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() ); #endif UInt uiMRGCost = MAX_UINT; xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand); if ( uiMRGCost < uiMECost ) { } else { } } motionCompensation ( pcCU, rpcPredYuv, REF_PIC_LIST_X, iPartIdx ); } setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X ); return ; }