简介

    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帧的运动预测方式增加了运动估计的准确度,提高了编码效率,同时也有利于编码流程的统一。具体细节可以参考博客:点击打开链接

函数流程

TEncSearch::predInterSearch的详解:
1、有个GPB_SIMPLE_UNI宏,表示广义B帧技术GPB,MvdL1ZeroFlag是一个和GPB技术相关的标志,如果它为true,那么表示使用GPB技术
2、对于CU下的每一个PU,遍历参考列表中的每一个图像,进行运动估计,找出最合适的参考帧以及对应的MV
3、如果是B类型的slice,因为他有两个MV,我们需要对后向参考的预测块进行运动补偿,motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );在运动补偿之后,重新进行运动估计,找出合适的MV
4、保存MV的一些相关信息
5、如果分割类型不是2Nx2N,即一个CU会被划分成为多个PU,那么应该计算并合并它们的运动估计代价
6、进行运动补偿motionCompensation(cu, pu, *predYuv, true, bChromaMC);这是通用的,无论是P类型还是B类型的slice

下面的代码为了方便理解,删除了定义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
{// ---------删除无关代码// 当前CU下的所有PU,请注意PU是由CU划分得到的!for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ){// ---------删除无关代码// 得到某种模式下CU块的比特数xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);// 得到当前PU的索引和大小pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );#if AMP_MRGBool bTestNormalMC = true;if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ){bTestNormalMC = false;}if (bTestNormalMC){
#endif//  Uni-directional prediction// 遍历两个参考图像列表(如果是P帧,只参考一个列表;如果是B帧,会参考两个列表)// 过这里就找到了应该使用哪个参考帧以及以及对应的MVfor ( 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++ ){// ---------删除无关代码// AMVP处理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// list1(只有B帧使用)if ( iRefList == 1 )    // list 1{// 表示广义B帧技术GPBif ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ){// 对于使用了广义的B帧技术,不再进行运动估计,而是直接计算代价// ---------删除无关代码}// 普通的B帧else{// 运动估计xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );}}// list0(P帧或者B帧使用)else{// 直接进行运动估计xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );}
#else // else of GPB_SIMPLE_UNI// 没有使用广义B帧技术xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
#endif // end of GPB_SIMPLE_UNIxCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )// 选择最优的MVPxCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);// ---------删除无关代码}}//  Bi-directional prediction// 如果是B帧,且isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N),那么进入if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ){// ---------删除无关代码// MvdL1ZeroFlag这个东西也是和GPB相关的,那么进行运动补偿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];}// 4-times iteration (default)Int iNumIter = 4;// fast encoder setting: only one iterationif ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag()){iNumIter = 1;}// 遍历1次或者4次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;}// 如果不使用GPB技术,且是第一次迭代,那么进行运动补偿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++ ){// ---------删除无关代码// call ME// 运动估计xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true );xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo());// 检查最好的MVPxCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);// 如果找到了一个代价更小的方式,那么更新if ( uiCostTemp < uiCostBi ){// ---------删除无关代码}} // for loop-iRefIdxTempif ( !bChanged ){// ---------删除无关代码}} // for loop-iter} // if (B_SLICE)#if AMP_MRG} //end if bTestNormalMC
#endif// ---------删除无关代码#if AMP_MRG// 这个if里面只是保存了一些MV的信息if (bTestNormalMC){
#endif// ---------删除无关代码
#if AMP_MRG} // end if bTestNormalMC
#endif// 如果分割类型不是2Nx2N,即一个CU会被划分成为多个PU// 那么应该计算并合并它们的运动估计代价if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N ){// ---------删除无关代码
#if AMP_MRG// calculate ME cost// ---------删除无关代码if (bTestNormalMC){xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );}
#else// calculate ME cost// 计算运动估计的代价UInt uiMEError = MAX_UINT;xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );// ---------删除无关代码
#endif // save ME result.// ---------删除无关代码// find Merge resultUInt uiMRGCost = MAX_UINT;// 合并估计信息xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand);// 设置运动估计的结果if ( uiMRGCost < uiMECost ){// set Merge result// ---------删除无关代码}else{// set ME result// ---------删除无关代码}}//  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;
}

HM编码器代码阅读(14)——帧间预测之AMVP模式(二)predInterSearch函数相关推荐

  1. HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取

    帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...

  2. HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程

    帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...

  3. HM编码器代码阅读(30)——帧间预测之AMVP模式(五)运动估计

    运动估计 通过 点击打开链接 介绍的方法得到MVP之后,可以根据该MVP确定运动估计的搜索起点,然后进行运动估计 xMotionEstimation就是进行运动估计的入口函数     1.先进行一些初 ...

  4. HM编码器代码阅读(15)——帧间预测之AMVP模式(三)xGetBlkBits函数

    GetBlkBits函数的主要功能是计算使用某种PU划分模式的时候,该种模式占用的比特数 Void TEncSearch::xGetBlkBits( PartSize eCUMode, Bool bP ...

  5. HM编码器代码阅读(32)——帧间预测之AMVP/Merge模式(七)encodeResAndCalcRdInterCU函数:残差计算、变换量化

    encodeResAndCalcRdInterCU 原理和细节 经过运动估计.运动补偿,我们得到了MV以及参考块,那么接下来是计算残差.计算MVD,然后对系数进行变换.量化. encodeResAnd ...

  6. HM编码器代码阅读(31)——帧间预测之AMVP/Merge模式(六)运动补偿

    运动补偿 原理 说实话一直很难理解运动补偿中"补偿"二字的意思,在参考了 http://blog.csdn.net/hevc_cjl/article/details/8457642 ...

  7. HM编码器代码阅读(14)——帧间预測之AMVP模式(二)predInterSearch函数

    简单介绍     predInterSearch基本的工作是ME(运动预计)和MC(运动补偿).     函数中有一个bTestNormalMC变量.它表示是否进行正常的MC过程,正常的MC过程就是进 ...

  8. HM编码器代码阅读(38)——帧内预测(五)帧内预测之正式的预测操作

    正式的预测操作 在前面的操作中,我们已经得到了模式候选列表,但是我们的目的是要得到一个最优的模式,因此我们还需要对这个列表中的模式进行遍历,对于每一个模式,进行预测操作,为了计算率失真代价还必须进行变 ...

  9. HM代码阅读1: 帧间预测函数Void TEncSearch::predInterSearch()

    AMVP理论知识简单回顾(含GPB) MVP主要是为了给当前PU提供一个运动矢量的预测,可加快ME的计算速度以及提升准确性.并且在后续编码中也只用编码MVD,减少了传输bit数. HM中获取每个参考图 ...

最新文章

  1. Hystrix 超时配置重写
  2. Android开发之通过CursorAdapter读取数据(源代码分享)
  3. js判断是由含有a节点_怎么判断某个dom节点是否包含某个dom节点?
  4. 致客户的一封信:关于产品生命周期管理与高可用版本的提供
  5. nacos 配置中心和注册中心依赖后报错,提示 org.apache.http.impl.client.HttpClientBuilder 这个类找不到
  6. 用隐马尔可夫模型(HMM)做命名实体识别——NER系列(二)
  7. 计算机应用基础在线作业南开,2017南开计算机应用基础在线作业满分的答案.doc...
  8. sas数据导入终极汇总-之二
  9. 【数据分析】reshape(-1,1)和numpy的广播机制
  10. 赋能数据智慧,InfoBeat让业务跃动起来
  11. java单个数组求积_[剑指offer][Java]构建乘积数组
  12. vue怎么注释html代码,vue如何注释
  13. sublime中的emmet插件的使用技巧
  14. Linux下部署Java,Tomcat环境
  15. 动态IP或无公网IP时外网访问内网固定端口管家婆等应用
  16. 火车头伪原创php-火车头采集伪原创插件
  17. python extract_convert.py对应代码解读抽取式提取+生成式提取摘要代码解读------摘要代码解读1
  18. Jenkins ERROR: Server rejected the 1 private key(s)
  19. 如何提高国际短信到达率?
  20. 第十三章:(1)CompletableFuture异步回调

热门文章

  1. 如何快速调整Excel中图表标签位置
  2. 寂静之城zz from woft.net [小百合海外站]
  3. 联想笔记本声音太小怎么办_联想笔记本电脑没声音了怎么办(大学生如何选择笔记本电脑)...
  4. 那些怪异的量化交易策略
  5. unity_DoTween Ease 动画效果展示
  6. 网易考拉海购Dubbok框架优化详解
  7. 百姓基因:新一代基因测序技术及其在肿瘤研究中的应用
  8. 国内支持原生android吗,定制安卓和原生Android到底有哪些不同之处?彻底真相了...
  9. 宏基因组公共数据挖掘基因组集再发Nature
  10. The valid characters are defined in RFC 7230 and RFC 3986