帧间预测之predInterSearch函数

来源:互联网 发布:爱赚网是什么软件 编辑:程序博客网 时间:2024/06/09 17:05

简介

    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宏才会生效的代码,以及其他的无关的代码
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #if AMP_MRG  
  2. Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes, Bool bUseMRG )  
  3. #else  
  4. Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes )  
  5. #endif  
  6. {  
  7.     // ---------删除无关代码  
  8.   
  9.     // 当前CU下的所有PU,请注意PU是由CU划分得到的!  
  10.     for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )  
  11.     {  
  12.         // ---------删除无关代码  
  13.   
  14.         // 得到某种模式下CU块的比特数  
  15.         xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);  
  16.   
  17.         // 得到当前PU的索引和大小  
  18.         pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );  
  19.   
  20. #if AMP_MRG  
  21.         Bool bTestNormalMC = true;  
  22.   
  23.         if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 )  
  24.         {  
  25.             bTestNormalMC = false;  
  26.         }  
  27.   
  28.         if (bTestNormalMC)  
  29.         {  
  30. #endif  
  31.             //  Uni-directional prediction  
  32.             // 遍历两个参考图像列表(如果是P帧,只参考一个列表;如果是B帧,会参考两个列表)  
  33.             // 过这里就找到了应该使用哪个参考帧以及以及对应的MV  
  34.             for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ )  
  35.             {  
  36.                 // 选出参考列表  
  37.                 RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );  
  38.   
  39.                 // 遍历这个参考列表的所有参考帧  
  40.                 for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ )  
  41.                 {  
  42.                     // ---------删除无关代码  
  43.   
  44.                     // AMVP处理  
  45.                     xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp);  
  46.                     // ---------删除无关代码  
  47.                       
  48.                     // 更新最优的参数  
  49.                     // ---------删除无关代码  
  50.                       
  51.   
  52. #if GPB_SIMPLE_UNI // 广义B帧技术GPB,相关细节可以参考http://blog.csdn.net/yangxiao_xiang/article/details/9045777  
  53.                     // list1(只有B帧使用)  
  54.                     if ( iRefList == 1 )    // list 1  
  55.                     {  
  56.                         // 表示广义B帧技术GPB  
  57.                         if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 )  
  58.                         {  
  59.                             // 对于使用了广义的B帧技术,不再进行运动估计,而是直接计算代价  
  60.                               
  61.                             // ---------删除无关代码  
  62.                         }  
  63.                         // 普通的B帧  
  64.                         else  
  65.                         {  
  66.                             // 运动估计  
  67.                             xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );  
  68.                         }  
  69.                     }  
  70.                     // list0(P帧或者B帧使用)  
  71.                     else  
  72.                     {  
  73.                         // 直接进行运动估计  
  74.                         xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );  
  75.                     }  
  76. #else // else of GPB_SIMPLE_UNI  
  77.   
  78.                     // 没有使用广义B帧技术  
  79.                     xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );  
  80. #endif // end of GPB_SIMPLE_UNI  
  81.   
  82.                     xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )  
  83.                     // 选择最优的MVP  
  84.                     xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);  
  85.   
  86.                     // ---------删除无关代码  
  87.                 }  
  88.             }  
  89.               
  90.             //  Bi-directional prediction  
  91.             // 如果是B帧,且isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N),那么进入  
  92.             if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) )  
  93.             {  
  94.   
  95.                 // ---------删除无关代码  
  96.                   
  97.                 // MvdL1ZeroFlag这个东西也是和GPB相关的,那么进行运动补偿  
  98.                 if(pcCU->getSlice()->getMvdL1ZeroFlag())  
  99.                 {  
  100.                     // ---------删除无关代码  
  101.   
  102.                     // 运动补偿  
  103.                     motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );  
  104.   
  105.                     // ---------删除无关代码  
  106.                 }  
  107.                 else  
  108.                 {  
  109.                     uiMotBits[0] = uiBits[0] - uiMbBits[0];  
  110.                     uiMotBits[1] = uiBits[1] - uiMbBits[1];  
  111.                     uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];  
  112.                 }  
  113.   
  114.                 // 4-times iteration (default)  
  115.                 Int iNumIter = 4;  
  116.   
  117.                 // fast encoder setting: only one iteration  
  118.                 if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag())  
  119.                 {  
  120.                     iNumIter = 1;  
  121.                 }  
  122.   
  123.                 // 遍历1次或者4次  
  124.                 for ( Int iIter = 0; iIter < iNumIter; iIter++ )  
  125.                 {  
  126.   
  127.                     Int         iRefList    = iIter % 2;  
  128.                     if ( m_pcEncCfg->getUseFastEnc() )  
  129.                     {  
  130.                         if( uiCost[0] <= uiCost[1] )  
  131.                         {  
  132.                             iRefList = 1;  
  133.                         }  
  134.                         else  
  135.                         {  
  136.                             iRefList = 0;  
  137.                         }  
  138.                     }  
  139.                     else if ( iIter == 0 )  
  140.                     {  
  141.                         iRefList = 0;  
  142.                     }  
  143.                       
  144.                     // 如果不使用GPB技术,且是第一次迭代,那么进行运动补偿  
  145.                     if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag())  
  146.                     {  
  147.                         // ---------删除无关代码  
  148.                         // 运动补偿  
  149.                         motionCompensation ( pcCU, pcYuvPred, RefPicList(1-iRefList), iPartIdx );  
  150.                     }  
  151.                       
  152.                     // 当前的参考列表  
  153.                     RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );  
  154.   
  155.                     if(pcCU->getSlice()->getMvdL1ZeroFlag())  
  156.                     {  
  157.                         iRefList = 0;  
  158.                         eRefPicList = REF_PIC_LIST_0;  
  159.                     }  
  160.   
  161.                     Bool bChanged = false;  
  162.   
  163.                     iRefStart = 0;  
  164.                     iRefEnd   = pcCU->getSlice()->getNumRefIdx(eRefPicList)-1;  
  165.                       
  166.                     // 遍历参考列表的所有参考帧,进行运动估计  
  167.                     for ( Int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ )  
  168.                     {  
  169.                         // ---------删除无关代码  
  170.                           
  171.                         // call ME  
  172.                         // 运动估计  
  173.                         xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true );  
  174.                         xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo());  
  175.                         // 检查最好的MVP  
  176.                         xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);  
  177.   
  178.                         // 如果找到了一个代价更小的方式,那么更新  
  179.                         if ( uiCostTemp < uiCostBi )  
  180.                         {  
  181.                             // ---------删除无关代码  
  182.                         }  
  183.                     } // for loop-iRefIdxTemp  
  184.   
  185.                     if ( !bChanged )  
  186.                     {  
  187.                         // ---------删除无关代码  
  188.                     }  
  189.                 } // for loop-iter  
  190.             } // if (B_SLICE)  
  191.   
  192.   
  193. #if AMP_MRG  
  194.         } //end if bTestNormalMC  
  195. #endif  
  196.         // ---------删除无关代码  
  197.           
  198. #if AMP_MRG  
  199.         // 这个if里面只是保存了一些MV的信息  
  200.         if (bTestNormalMC)  
  201.         {  
  202. #endif  
  203.                 // ---------删除无关代码  
  204. #if AMP_MRG  
  205.         } // end if bTestNormalMC  
  206. #endif  
  207.   
  208.         // 如果分割类型不是2Nx2N,即一个CU会被划分成为多个PU  
  209.         // 那么应该计算并合并它们的运动估计代价  
  210.         if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N )  
  211.         {  
  212.             // ---------删除无关代码  
  213. #if AMP_MRG  
  214.             // calculate ME cost  
  215.             // ---------删除无关代码  
  216.             if (bTestNormalMC)  
  217.             {  
  218.                 xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );  
  219.                 uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );  
  220.             }  
  221. #else  
  222.             // calculate ME cost  
  223.             // 计算运动估计的代价  
  224.             UInt uiMEError = MAX_UINT;  
  225.             xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );  
  226.             // ---------删除无关代码  
  227. #endif   
  228.             // save ME result.  
  229.             // ---------删除无关代码  
  230.   
  231.             // find Merge result  
  232.             UInt uiMRGCost = MAX_UINT;  
  233.             // 合并估计信息  
  234.             xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand);  
  235.               
  236.             // 设置运动估计的结果  
  237.             if ( uiMRGCost < uiMECost )  
  238.             {  
  239.                 // set Merge result  
  240.                 // ---------删除无关代码  
  241.             }  
  242.             else  
  243.             {  
  244.                 // set ME result  
  245.                 // ---------删除无关代码  
  246.             }  
  247.         }  
  248.   
  249.         //  MC  
  250.         // 运动补偿  
  251.         motionCompensation ( pcCU, rpcPredYuv, REF_PIC_LIST_X, iPartIdx );  
  252.   
  253.     } //  end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )  
  254.   
  255.     setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );  
  256.   
  257.     return;  
  258. }  
1 0
原创粉丝点击