简单介绍

    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_MRG
Bool bTestNormalMC = true; if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 )
{
bTestNormalMC = false;
} if (bTestNormalMC)
{
#endif
// Uni-directional prediction
// 遍历两个參考图像列表(假设是P帧。仅仅參考一个列表;假设是B帧。会參考两个列表)
// 过这里就找到了应该使用哪个參考帧以及以及相应的MV
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++ )
{
// ---------删除无关代码 // 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帧技术GPB
if ( 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_UNI xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )
// 选择最优的MVP
xCheckBestMVP(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 iteration
if ( 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());
// 检查最好的MVP
xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); // 假设找到了一个代价更小的方式,那么更新
if ( uiCostTemp < uiCostBi )
{
// ---------删除无关代码
}
} // for loop-iRefIdxTemp if ( !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 result
UInt 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. x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()

    x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*() 帧间预測是指利用视频时间域相关性,使用临近已编码图像像素预測当前图像的像素,以达到有效去除视频时域冗 ...

  2. HM编码器代码阅读(1)——介绍以及相关知识

    HM是HEVC(H.265)的开源实现,可以从网上直接下载.HEVC(H.265)是新一代的视频编解码标准.本人目前研究的只是编码器部分,而且还是入门阶段!为了提高自己,边学边记,由于理解不够深入,难 ...

  3. H.264学习笔记3——帧间预测

    帧间预测主要包括运动估计(运动搜索方法.运动估计准则.亚像素插值和运动矢量估计)和运动补偿. 对于H.264,是对16x16的亮度块和8x8的色度块进行帧间预测编码. A.树状结构分块 H.264的宏 ...

  4. x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  5. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  6. 脚本病毒分析扫描专题1-VBA代码阅读扫盲、宏病毒分析

    1.Office Macor MS office宏的编程语言是Visual Basic For Applications(VBA). 微软在1994年发行的Excel5.0版本中,即具备了VBA的宏功 ...

  7. 图形化代码阅读工具——Scitools Understand

    Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java, ...

  8. MediaInfo代码阅读

      MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...

  9. py-faster-rcnn代码阅读1-train_net.py & train.py

    # train_net.py#!/usr/bin/env python # -------------------------------------------------------- # Fas ...

随机推荐

  1. Unity 碰撞检测

    武器与怪物的碰撞 目前来说有三种思路,其实前两种算变种了: 1.动画关键帧回调 + 范围检测.http://blog.csdn.net/u013700908/article/details/52888 ...

  2. js获取触发事件的元素

    //获取事件 var e = window.event; //获取元素 obj = e.target || e.srcElement; console.log(e); checkRepeat(e.ta ...

  3. 软件包管理rpm_yum

    和文本相关的命令cat 正向显示文本tac 反向显示文本more 可以一步一步显示文本文件less 还可以往上看.几个快捷键:j(往下看), k (往上看), g(定位最上), G(定位最下), ct ...

  4. HDU 5418 Victor and World(状压DP+Floyed预处理)

    Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Other ...

  5. mac 安装 maven 配置

    前面的话: 记录 在 Mac 下 安装配置 maven 1. 下载 Maven, 并解压到某个目录.例如/Users/robbie/apache-maven-3.3.3 2. 打开 Terminal, ...

  6. compiler related

    1. 词法分析 词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme).源程序中常见的记号可以归为几大类:关键字.标识符.字面量和特殊符号.词法分析器的输入 ...

  7. 介绍一款可以滚动加载的插件droploader

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. hdu 3518 Boring counting 后缀数组 height分组

    题目链接 题意 对于给定的字符串,求有多少个 不重叠的子串 出现次数 \(\geq 2\). 思路 枚举子串长度 \(len\),以此作为分界值来对 \(height\) 值进行划分. 显然,对于每一 ...

  9. awk 使用方法

    awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各 ...

  10. asp.net内置对象 Response对象使用介绍

    Response对象是HttpRespone类的一个实例.该类主要是封装来自ASP.NET操作的HTTP相应信息.Response对象将数据作为请求的结果从服务器发送到客户浏览器中,并提供有关响应的消 ...