代码版本: VTHEVCDec

函数: fillMvpCand()

时间: 2015/8/26

作者: lb

高级运动向量预测技术(AMVP)利用空间、时间上运动向量的相关性,分别建立空域候选列表以及时域候选列表,再从候选列表中选取最终的MVP。

1、空域候选列表的建立

空域候选列表需要从上图5个参考块中选出两个候选MV。分别是a0,a1中选出一个候选MV。b0,b1,b2中选出一个候选MV。

其中左侧候选块的选择顺序为a0->a1->scaled a0->scaled a1,scaled为比例伸缩模式。一旦前一个块的MV可用,即选择其为候选MV,停止左侧后续块的判断。

上侧块的选择顺序为(scaled b0->scaled b1->scaled b2)b0->b1->b2,同理,一旦有一个块可用,停止后续块的判断。 上侧块的比例伸缩模式之所以用括号括起来,因为它跟普通非比例伸缩模式是一个二选一的过程,当它满足以下条件时:左侧的a0,a1块均满足 参考块不存在或者存在时其预测模式不是帧内预测,则采用比例伸缩模式。反之,则采用普通模式。

比例伸缩模式(scaled)是当参考块存在,当前Pu的参考图像跟参考块的参考图像不一致时才选用的方式。具体计算方法如下公式所示,curMV为当前Pu的候选MV,td与tb分别为当前块与参考块到他们的参考图像间的距离,colMV 为参考块的mv。

2、时域候选列表的建立

时域候选列表最多提供一个候选MV,时域候选列表的建立过程利用了邻近已编码图像中对应参考块位置的Pu的运动信息。它用的技术方式即为上述的比例伸缩模式(scaled),只是参考块的 位置不一样。参考块的位置如下图所示:

从上图可以看出参考块位置分别为H,。若H位置的同位Pu(邻近已编码图像对应位置Pu)不可用,则用位置的同位Pu代替。

3、AMVP候选列表的建立流程

整个函数的流程可用下图表示:

   

附上该函数代码:

/*============================================
**函数名:   fillMvpCand
**功能描述: 获取当前PU的候选MV列表
**创建人:   lmx
**时间    :  20150601
**输入参数:pCu                           --- 当前CU结构体
iPartIdx                    --- PU索引
uiPartAddr                  --- PU左上角索引值(以最小TU为单位,相对所在CU的左上角位置)
eRefPicList                 --- 参考帧链表
iRefIdx                     --- 当前PU所使用的参考帧索引
**输出参数:
**返回值:
**版本号:
**修改记录:
**==========================================*/
void fillMvpCand (DataCu *pCu,UInt32 iPartIdx, UInt32 uiPartAddr, RefPicList eRefPicList, Int32 iRefIdx, AMVPINFO* pSrcfo )
{UInt8 bAddedSmvp = false;   //!< 左侧两个参考块任意一个可用且模式为帧间预测时,为真//-- Get Spatial MV, 空域(2个)UInt32 uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;UInt8 bAdded = false;/*    __        _____|B2|______|B1|B0||         | |          |    |curent PU|__|         ||A1|_________||A0|*/DataCu *tmpCU_BL = NULL;    //!< A0DataCu *tmpCU_L  = NULL;    //!< A1DataCu *tmpCU_AR = NULL;    //!< B0DataCu *tmpCU_A  = NULL;    //!< B1DataCu *tmpCU_AL = NULL;    //!< B2UInt32 idx;  //!< Z扫描:当前预测PU左下角参考TU的索引(相对它所在的Cu)UInt32 idxTmp;Slice *pSlice = pCu->pSlice;pSrcfo->N = 0;if (iRefIdx < 0){return;}//获取当前PU本身的左上角、右上角、左下角TU坐标(以最小TU为单位,相对Pu所在CTU的左上角位置)deriveLeftRightTopIdx(pCu,iPartIdx, &uiPartIdxLT, &uiPartIdxRT);deriveLeftBottomIdx(pCu,iPartIdx,&uiPartIdxLB);//!< A0,返回当前Pu左下角参考块(非Pu本身)所在Cu//!< 左侧产生一个候选MV, 选择顺序为 BELOW_LEFT -> LEFTtmpCU_BL = getPuBelowLeft(pCu,&idx,uiPartIdxLB,true); bAddedSmvp    = (tmpCU_BL != NULL) && (tmpCU_BL->pPePredMode[idx] == MODE_INTER); // 参考块为帧内预测//!< A1,返回当前Pu左侧参考块所在CutmpCU_L = getPuLeft(pCu,&idxTmp,uiPartIdxLB,true,true);if (!bAddedSmvp){bAddedSmvp = (tmpCU_L != NULL) && (tmpCU_L->pPePredMode[idxTmp] == MODE_INTER);}if (tmpCU_BL){bAdded = xAddMVPCand(pCu,tmpCU_BL,pSrcfo,eRefPicList,iRefIdx, idx);}if (!bAdded && tmpCU_L){bAdded = xAddMVPCand(pCu,tmpCU_L, pSrcfo, eRefPicList,iRefIdx, idxTmp);}//!<  若左侧的两个MV不可用,则通过MV的比例伸缩查找,选择顺序为BELOW_LEFT -> LEFTif(!bAdded){if (tmpCU_BL){bAdded = xAddMVPCandOrder(pCu,tmpCU_BL, pSrcfo, eRefPicList, iRefIdx, idx);}if (!bAdded  && tmpCU_L){xAddMVPCandOrder(pCu, tmpCU_L,pSrcfo, eRefPicList, iRefIdx, idxTmp );}}//!< 左侧的两个参考块均满足--不可用或预测模式不是帧间预测,才采用MV的比例缩放if(!bAddedSmvp){tmpCU_AR = getPuAboveRight(pCu,&idx, uiPartIdxRT,true);if (tmpCU_AR){bAdded = xAddMVPCandOrder(pCu,tmpCU_AR, pSrcfo, eRefPicList, iRefIdx, idx);}if (!bAdded){tmpCU_A = getPuAbove(pCu,&idx, uiPartIdxRT,true,false,true);if (tmpCU_A){bAdded = xAddMVPCandOrder(pCu, tmpCU_A,pSrcfo, eRefPicList, iRefIdx, idx);}}if(!bAdded){tmpCU_AL = getPuAboveLeft(pCu,&idx, uiPartIdxLT,true);if (tmpCU_AL){xAddMVPCandOrder(pCu,tmpCU_AL, pSrcfo, eRefPicList, iRefIdx, idx);}}}else{bAdded = false;//!< B0, 上方预测块产生一个候选MV,选择顺序为 ABOVE_RIGHT -> ABOVE -> ABOVE_LEFTtmpCU_AR = getPuAboveRight(pCu,&idx, uiPartIdxRT,true);if (tmpCU_AR){bAdded   = xAddMVPCand(pCu,tmpCU_AR,pSrcfo, eRefPicList,iRefIdx, idx);}if (!bAdded){   //!< B1tmpCU_A = getPuAbove(pCu,&idx, uiPartIdxRT,true,false,true);if (tmpCU_A){bAdded = xAddMVPCand(pCu,tmpCU_A,pSrcfo, eRefPicList, iRefIdx, idx);}}if(!bAdded){ //!< B2tmpCU_AL = getPuAboveLeft(pCu,&idx, uiPartIdxLT,true);if (tmpCU_AL){xAddMVPCand(pCu,tmpCU_AL,pSrcfo, eRefPicList,iRefIdx, idx);}}}if ( pSrcfo->N == 2 ){  //!< 合并空域相同候选MVif ( (pSrcfo->mvCand[ 0 ].hor == pSrcfo->mvCand[ 1 ].hor) && (pSrcfo->mvCand[ 0 ].ver == pSrcfo->mvCand[ 1 ].ver) )  {pSrcfo->N = 1;}}if (pSlice->enableTMVPFlag)  //!< TMVP ,时域候选MV{PicSym *pPicSym = pCu->pPic->pPicSym;const UInt32 numPartInCtuWidth  = pPicSym->numPartInCtuWidth;const UInt32 numPartInCtuHeight = pPicSym->numPartInCtuHeight;const DataCu *tmpCtu = pPicSym->pPicCtuArray[pCu->ctuRsAddr];const Sps    *tmpSps = pCu->pSlice->pSps;Int32 iRefIdx_Col = iRefIdx;  //!< 当前PU的参考帧索引MvInfo cColMv;UInt32 uiPartIdxRB;UInt32 uiAbsPartIdx;UInt32 uiAbsPartAddr;            //!< 参考块在所在CTU的Z扫描位置UInt32 uiTmpResi, uiTmpQuo;     //!< 余数, 商Int32 ctuRsAddr = -1;           //!< 参考块所在CTU在图像中的光栅扫描位置//!< 获取右下角参考Tu的位置deriveRightBottomIdx(pCu, iPartIdx, &uiPartIdxRB );uiAbsPartAddr = pCu->absZIdxInCtu + uiPartAddr;  //!< z扫描:当前PU相对CTU的位置uiAbsPartIdx = g_auiZscanToRaster[uiPartIdxRB];  //!< uiPartIdxRB 是相对CTU的位置uiTmpResi = uiAbsPartIdx % numPartInCtuWidth;uiTmpQuo  = uiAbsPartIdx / numPartInCtuWidth;//----  co-located RightBottom Temporal Predictor (H) ---//if (  ( ( tmpCtu->uiCUPelX + g_auiRasterToPelX[uiAbsPartIdx] + pPicSym->minCUWidth ) < tmpSps->picWidthInLumaSamples )  // image boundary check, 判断当前Pu所在的CTU是不是处于图像的右边界&& ( ( tmpCtu->uiCUPelY + g_auiRasterToPelY[uiAbsPartIdx] + pPicSym->minCUHeight ) < tmpSps->picHeightInLumaSamples ) )//!< 判断当前Pu所在的CTU是不是处于图像的下边界{if ( ( uiTmpResi < numPartInCtuWidth - 1 ) &&  // is not at the last column of CTU( uiTmpQuo < numPartInCtuHeight - 1 ) )  // is not at the last row    of CTU{    //!< 右下角Tu不在CTU的最后一列最后一行,说明右下角TU的右下角参考块也在当前CTUuiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + numPartInCtuWidth + 1 ];ctuRsAddr = pCu->ctuRsAddr;}else if ( uiTmpResi < numPartInCtuWidth - 1 )  // is not at the last column of CTU But is last row of CTU{uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdx + numPartInCtuWidth + 1) % pPicSym->tuNumCtu ];}else if ( uiTmpQuo < numPartInCtuHeight - 1 ) // is not at the last row of CTU But is last column of CTU{uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + 1 ];ctuRsAddr = pCu->ctuRsAddr + 1;}else //is the right bottom corner of CTU{uiAbsPartAddr = 0;}}if ( ctuRsAddr >= 0 && xGetColMVP(pCu, eRefPicList, ctuRsAddr, uiAbsPartAddr, &cColMv, iRefIdx_Col ) ){pSrcfo->mvCand[pSrcfo->N++] = cColMv;}else  //!< 若Current Pu 的右下角参考块的同位PU不存在,则取Current PU 的中间Tu块作为同位参考块{UInt32 uiPartIdxCenter;xDeriveCenterIdx(pCu, iPartIdx, &uiPartIdxCenter );if (xGetColMVP(pCu, eRefPicList, pCu->ctuRsAddr, uiPartIdxCenter,  &cColMv, iRefIdx_Col )){pSrcfo->mvCand[pSrcfo->N++] = cColMv;}}//----  co-located RightBottom Temporal Predictor  ---//}if (pSrcfo->N > AMVP_MAX_NUM_CANDS)         //!< 保留候选列表中的前两个作为最终的候选MV{pSrcfo->N = AMVP_MAX_NUM_CANDS;}while (pSrcfo->N < AMVP_MAX_NUM_CANDS)       //!< 若候选MV长度不足,用(0,0) 补充{pSrcfo->mvCand[pSrcfo->N].hor = 0;pSrcfo->mvCand[pSrcfo->N].ver = 0;pSrcfo->N++;}return ;
}

HEVC 高级运动向量预测技术(AMVP)相关推荐

  1. H.266/VVC帧间预测技术学习:高级运动矢量预测(Advanced Motion Vector Prediction, AMVP)

    高级运动矢量预测模式(Advanced Motion Vector Prediction,AMVP) AMVP模式是H.265/HEVC中提出的新的MV预测技术,H.266/VVC仍采用了该技术,并在 ...

  2. 从HEVC到VVC:帧内预测技术的演进(2) – 多划分及多参考行帧内预测

    当前主流的视频编码标准(如H.264/AVC,VP9,AVS1,HEVC等)均使用当前预测单元最邻近的已重构像素对当前预测单元进行帧内预测.因为当前预测单元与其临近的像素之间有很强的相关性,该帧内预测 ...

  3. HEVC代码学习15:AMVP相关函数

    在HEVC中,使用了AMVP技术,利用空域和时域上的运动向量的相关性,为当前PU建立候选预测MV(MVP)列表.编码器从中选出最优的预测MV,并对MV进行差分编码:解码端会构造相同的列表,仅需要运动向 ...

  4. HEVC帧间预测原理

    一.帧间预测基本原理 主要原理是为当前图像的每个像素块在之前已编码图像中寻找一个最佳匹配块,该过程称为运动估计( Motion Estimation,ME).其中用于预测的图像称为参考图(Refere ...

  5. 【十六】 H.266/VVC | VVC中帧间预测技术详细总结 | 所有帧间预测技术代码汇总

    前言 ​ 帧间预测是影响视频编码性能的关键环节之一,H.266/VVC帧间预测在传统只能应对简单的平移运动的基础上,采用了仿射运动模型,可以描述更加复杂的缩放.旋转等运动.为了更好的发挥合并模式(Me ...

  6. HEVC帧间预测流程梳理

    HEVC帧间预测流程 前言:最近在琢磨hevc理论知识,看着那本书绕过去绕过来咋也没把流程想通,去找了师兄说耽误他一分钟,结果叭叭叭了六小时哈哈哈哈. 最后还是感谢师兄给我解答问题,我写这篇文章主要是 ...

  7. 《游戏机制——高级游戏设计技术》一1.1 规则定义游戏

    本节书摘来异步社区<游戏机制--高级游戏设计技术>一书中的第1章,第1.1节,作者: [美]Ernest Adams 译者: 石曦 责编: 陈冀康,更多章节内容可以访问云栖社区" ...

  8. HEVC中低复杂度量化技术

    本文提出了一种HEVC中的低复杂度量化技术,并希望对新一代视频编码标准VVC有一定的启发. 文章目录 摘要 一.引言 二.HEVC中采用的量化技术 三.FAST RDOQ 1.STATISTICS-B ...

  9. 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术

    本文引用了"拍乐云Pano"的"深入浅出理解视频编解码技术"和"揭秘视频千倍压缩背后的技术原理之本文引用了"拍乐云Pano"的&q ...

最新文章

  1. 路由器虚拟服务器功能(广域网服务端口和局域网服务端口的映射关系)
  2. 程序员吐槽:非常后悔3年前选择加入互联网行业,因为短期的高工资断送了自己长期的职业生涯发展...
  3. php 一行代码解决二维数组去重
  4. linux 下mysql等php的安装 lnmp
  5. 如何使用iToolab FixGo for mac修复iPhone/iPad的系统问题
  6. php删除文件代码指定,PHP删除指定文件夹所有文件代码
  7. 个人技术博客--团队Git规范(参考西瓜学长)
  8. 中国糖化酶行业市场供需与战略研究报告
  9. 键值 keyCode事件属性
  10. poj2186【利用强连通分量】
  11. LeetCode简单题目(#53 #58 #66 #67 #69 #70 #83 #88)-8道
  12. java selenium (十一) 操作弹出对话框
  13. 数据库,万能密码与密码解析
  14. 252个核心词根——词缀(前缀-后缀)总结大全【最全-一文看懂!!!】
  15. linux 权限不够命令
  16. android休眠状态,【Android休眠】之Android休眠机制
  17. 100ml干胶能带上地铁吗_100ml发胶能带上地铁吗 不易燃易爆可带上地铁
  18. js,javascript中判断一个数是否是素数
  19. html5表格在线生成,专业的Web报表工具——表格在线生成制作工具
  20. 涵数计算机怎么玩游戏,科学计算器

热门文章

  1. c语言比较函数memcmp,c语言函数memcmp()如何比较内存前n个字节实例源码介绍
  2. 图表横坐标怎么改倾斜_Excel 图表横轴文字太长,不想让它倾斜,如何分行显示?...
  3. 贵大计算机专业高考分数线,2020贵州大学录取分数线一览表
  4. 前端怎么画三角形_用CSS画一个三角形
  5. 关于汇编语言中的转移指令原理——offset
  6. [RL 9] Trust Region Policy Optimization (ICML, 2015)
  7. table表格自动换行
  8. Leetcode 14.最长公共前缀(Longest Common Prefix)
  9. 饥荒海难创建显示专用服务器,饥荒海难控制台使用教程及小技巧_快吧单机游戏...
  10. 按键精灵获取服务器信息,按键精灵获取窗口信息脚本源码