Affine模式是JEM中新加的,属于帧间预测,与FRUC,merge,inter形成竞争关系。

#if COM16_C1016_AFFINEVoid TEncCu::xCheckRDCostAffineMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU )
{assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE );if ( getFastDeltaQp() ){return;}TComMvField cAffineMvField[2][3];UChar uhInterDirNeighbours[1] = {0};Int numValidMergeCand = 0;const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0);UChar uhDepth = rpcTempCU->getDepth( 0 );
#if JVET_C0024_QTBTif (rpcBestCU->getWidth(0) * rpcBestCU->getHeight(0) < 64)//只对大于等于8*8的块执行affine merge;{return;}UInt uiWIdx = g_aucConvertToBit[rpcBestCU->getWidth(0)];UInt uiHIdx = g_aucConvertToBit[rpcBestCU->getHeight(0)];
#elserpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth );
#endif//得到仿射Merge候选;rpcTempCU->getAffineMergeCandidates( 0, 0, cAffineMvField, uhInterDirNeighbours, numValidMergeCand );if ( numValidMergeCand == -1 )//如果merge候选个数为-1,则退出,不执行Affine merge{return;}Int mergeCandBuffer[1] = {0};UInt iteration;if ( rpcTempCU->isLosslessCoded(0))//无损编码迭代次数为1,否则为2;{iteration = 1;}else{iteration = 2;}///至少迭代一次,如果没有残差,则不会进行第二次迭代//for ( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ){//遍历所有有效的Merge候选;for ( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand )//numValidMergeCand=1;{//第一次迭代uiNoResidual=0,if条件一定成立,会执行里面的内容;//第二次迭代中,如果在第一次迭代时,没有残差,则mergeCandBuffer[uiMergeCand]=1 ,此时不满足if条件,不进入下面的步骤;if ( !( uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1 ) ){// set MC parameters,设置运动补偿参数;rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth );//设置预测模式为帧间;rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth );//设置TransquantBypassFlag;rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );//设置色度QP调整
#if !JVET_C0024_QTBTrpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth );
#endifrpcTempCU->setAffineFlagSubParts( true, 0, 0, uhDepth );//设置Affine flag为true;rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth );//设置merge flag为true;rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth );//设置mergeidx 设置为0;rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth );//将帧间模式设置为uhInterDirNeighbours[uiMergeCand]rpcTempCU->setAllAffineMvField( 0, 0, cAffineMvField[0 + 2*uiMergeCand], REF_PIC_LIST_0, 0 );//设置affine mvf;rpcTempCU->setAllAffineMvField( 0, 0, cAffineMvField[1 + 2*uiMergeCand], REF_PIC_LIST_1, 0 );#if COM16_C806_OBMCrpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );//设置OBMC Flag为true
#endif// do MC,做运动补偿
#if JVET_C0024_QTBTm_pcPredSearch->motionCompensation ( rpcTempCU, m_pppcPredYuvTemp[uiWIdx][uiHIdx] );#if COM16_C806_OBMC//进行重叠块运动补偿;m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif// estimate residual and encode everything,估计残差和编码所有数据m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,m_pppcOrigYuv    [uiWIdx][uiHIdx],m_pppcPredYuvTemp[uiWIdx][uiHIdx],m_pppcResiYuvTemp[uiWIdx][uiHIdx],m_pppcResiYuvBest[uiWIdx][uiHIdx],m_pppcRecoYuvTemp[uiWIdx][uiHIdx],(uiNoResidual != 0)
#if COM16_C806_EMT, rpcBestCU->getTotalCost()
#endif);
#elsem_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] );#if COM16_C806_OBMCm_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_ppcPredYuvTemp[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#endif// estimate residual and encode everythingm_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,m_ppcOrigYuv    [uhDepth],m_ppcPredYuvTemp[uhDepth],m_ppcResiYuvTemp[uhDepth],m_ppcResiYuvBest[uhDepth],m_ppcRecoYuvTemp[uhDepth],(uiNoResidual != 0)
#if COM16_C806_EMT, rpcBestCU->getTotalCost()
#endif);
#endifif ( uiNoResidual == 0 && rpcTempCU->getQtRootCbf(0) == 0 ){ //如果是第一次迭代,且cbf为0时(即无残差时),令mergeCandBuffer[uiMergeCnad]=1;// If no residual when allowing for one, then set mark to not try case where residual is forced to 0mergeCandBuffer[uiMergeCand] = 1;}rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth );//如果当前CU的cbf为0时,设置Skip Flag为true,否则为falseInt orgQP = rpcTempCU->getQP( 0 );xCheckDQP( rpcTempCU );xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth);rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag );//比较完TempCU和BestCU,就将TempCU重新初始化}}//遍历merge候选结束/}///迭代结束///
}
#endif
//得到Affine的merge候选预测模式
Void TComDataCU::getAffineMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField (*pcMvFieldNeighbours)[3], UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{TComMvField affineMvField[2][3];//2是表示有两个双向预测,3是表示3种运动矢量场???UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;TComDataCU *pcTempCU = NULL;Bool bAvailable = false;UInt uiPartIdx = 0;//初始化运动场for ( Int mvNum = 0; mvNum < 3; mvNum++ ){pcMvFieldNeighbours[0][mvNum].setMvField( TComMv(0,0), -1 );pcMvFieldNeighbours[1][mvNum].setMvField( TComMv(0,0), -1 );}// Get Part Index in LCU,得到CU在LCU的索引UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );//推导左上part和右上part的索引deriveLeftBottomIdxGeneral  ( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );//推导左下part的索引//当一个CU应用AF_MERGE模式时,从有效的相邻重建块中得到第一个用仿射模式的编码块。候选块的选择顺序是从左,上,右上,左下到左上// leftpcTempCU = getPULeft( uiPartIdx, uiPartIdxLB );bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );//左边CU是否是Affine模式// aboveif ( !bAvailable )//如果左边不是,则查看上边的CU{pcTempCU = getPUAbove( uiPartIdx, uiPartIdxRT );bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );}// aboveRightif ( !bAvailable )//上边不是,则查看右上CU{pcTempCU = getPUAboveRight( uiPartIdx, uiPartIdxRT );bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );}// leftBottomif ( !bAvailable )//右上不是,则查看左下CU{pcTempCU = getPUBelowLeft( uiPartIdx, uiPartIdxLB );bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );}// aboveLeftif ( !bAvailable )//左下不是,则查看左上CU{pcTempCU = getPUAboveLeft( uiPartIdx, uiAbsPartAddr );bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );}if ( !bAvailable )//如果5个相邻块都不是仿射模式,则有效的merge候选个数为0,退出;{numValidMergeCand = -1;return;}else//否则,有效的merge候选个数为1;{assert( pcTempCU );numValidMergeCand = 1;}Int width = pcTempCU->getWidth(uiPartIdx);Int height = pcTempCU->getHeight(uiPartIdx);
#if !JVET_C0024_QTBTInt depth  = pcTempCU->getDepth(uiPartIdx);Int numPart = pcTempCU->getPic()->getNumPartitionsInCtu() >> ( depth << 1 );
#endifInt iPartW = width / getPic()->getMinCUWidth();Int iPartH = height / getPic()->getMinCUHeight();#if JVET_C0024_QTBTInt iBlkY = g_auiZscanToRaster[uiPartIdx]/(getPic()->getNumPartInCtuWidth()*iPartH);Int iBlkX = (g_auiZscanToRaster[uiPartIdx]%getPic()->getNumPartInCtuWidth())/iPartW;Int aboveLeftIdx = g_auiRasterToZscan[iBlkY * getPic()->getNumPartInCtuWidth() * iPartH + iBlkX * iPartW];
#elseInt aboveLeftIdx = uiPartIdx - ( uiPartIdx % numPart );
#endifInt aboveRightIdx = g_auiRasterToZscan[ g_auiZscanToRaster[aboveLeftIdx] + iPartW - 1 ];Int bottomLeftIdx = g_auiRasterToZscan[ g_auiZscanToRaster[aboveLeftIdx] + ( iPartH - 1 ) * getPic()->getNumPartInCtuWidth() ];// list0affineMvField[0][0].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( aboveLeftIdx ),  pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( aboveLeftIdx ) );affineMvField[0][1].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( aboveRightIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( aboveRightIdx ) );affineMvField[0][2].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( bottomLeftIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( bottomLeftIdx ) );// list1affineMvField[1][0].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( aboveLeftIdx ),  pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( aboveLeftIdx ) );affineMvField[1][1].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( aboveRightIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( aboveRightIdx ) );affineMvField[1][2].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( bottomLeftIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( bottomLeftIdx ) );Int pixelOrgX    = g_auiRasterToPelX[ g_auiZscanToRaster[ aboveLeftIdx ] ] + pcTempCU->getCUPelX();Int pixelCurrX   = getCUPelX();Int pixelOrgY    = g_auiRasterToPelY[ g_auiZscanToRaster[ aboveLeftIdx ] ] + pcTempCU->getCUPelY();Int pixelCurrY   = getCUPelY();//计算运动矢量场;//vx0,vx1,vx2,vy0,vy1,vy2表示G1001里等式15???Int vx0 = Int( affineMvField[0][0].getHor() + 1.0 * ( affineMvField[0][2].getHor() - affineMvField[0][0].getHor() ) * ( pixelCurrY - pixelOrgY ) / height+ 1.0 * ( affineMvField[0][1].getHor() - affineMvField[0][0].getHor() ) * ( pixelCurrX - pixelOrgX ) / width );Int vy0 = Int( affineMvField[0][0].getVer() + 1.0 * ( affineMvField[0][2].getVer() - affineMvField[0][0].getVer() ) * ( pixelCurrY - pixelOrgY ) / height+ 1.0 * ( affineMvField[0][1].getVer() - affineMvField[0][0].getVer() ) * ( pixelCurrX - pixelOrgX ) / width );pcMvFieldNeighbours[0][0].setMvField( TComMv(vx0, vy0), affineMvField[0][0].getRefIdx() );if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;{vx0 = Int( affineMvField[1][0].getHor() + 1.0 * ( affineMvField[1][2].getHor() - affineMvField[1][0].getHor() ) * ( pixelCurrY - pixelOrgY ) / height + 1.0 * ( affineMvField[1][1].getHor() - affineMvField[1][0].getHor() ) * ( pixelCurrX - pixelOrgX ) / width );vy0 = Int( affineMvField[1][0].getVer() + 1.0 * ( affineMvField[1][2].getVer() - affineMvField[1][0].getVer() ) * ( pixelCurrY - pixelOrgY ) / height + 1.0 * ( affineMvField[1][1].getVer() - affineMvField[1][0].getVer() ) * ( pixelCurrX - pixelOrgX ) / width );pcMvFieldNeighbours[1][0].setMvField( TComMv(vx0, vy0), affineMvField[1][0].getRefIdx() );}Int vx1 = Int( 1.0 * ( affineMvField[0][1].getHor() - affineMvField[0][0].getHor() ) * getWidth(0) / width + pcMvFieldNeighbours[0][0].getHor() );Int vy1 = Int( 1.0 * ( affineMvField[0][1].getVer() - affineMvField[0][0].getVer() ) * getWidth(0) / width + pcMvFieldNeighbours[0][0].getVer() );pcMvFieldNeighbours[0][1].setMvField( TComMv(vx1, vy1), affineMvField[0][0].getRefIdx() );if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;{vx1 = Int( 1.0 * ( affineMvField[1][1].getHor() - affineMvField[1][0].getHor() ) * getWidth(0) / width + pcMvFieldNeighbours[1][0].getHor() );vy1 = Int( 1.0 * ( affineMvField[1][1].getVer() - affineMvField[1][0].getVer() ) * getWidth(0) / width + pcMvFieldNeighbours[1][0].getVer() );pcMvFieldNeighbours[1][1].setMvField( TComMv(vx1, vy1), affineMvField[1][0].getRefIdx() );}Int vx2 = Int( 1.0 * ( affineMvField[0][2].getHor() - affineMvField[0][0].getHor() ) * getHeight(0) / height + pcMvFieldNeighbours[0][0].getHor() );Int vy2 = Int( 1.0 * ( affineMvField[0][2].getVer() - affineMvField[0][0].getVer() ) * getHeight(0) / height + pcMvFieldNeighbours[0][0].getVer() );pcMvFieldNeighbours[0][2].setMvField( TComMv(vx2, vy2), affineMvField[0][0].getRefIdx() );if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;{vx2 = Int( 1.0 * ( affineMvField[1][2].getHor() - affineMvField[1][0].getHor() ) * getHeight(0) / height + pcMvFieldNeighbours[1][0].getHor() );vy2 = Int( 1.0 * ( affineMvField[1][2].getVer() - affineMvField[1][0].getVer() ) * getHeight(0) / height + pcMvFieldNeighbours[1][0].getVer() );pcMvFieldNeighbours[1][2].setMvField( TComMv(vx2, vy2), affineMvField[1][0].getRefIdx() );}puhInterDirNeighbours[0] = pcTempCU->getInterDir( uiPartIdx );return;
}

VVC/JEM代码学习15:xCheckRDCostAffineMerge2Nx2N相关推荐

  1. VVC/JEM代码学习26:m_pcTrQuant-transformN*N

    在H.266中,做完主变换后,还要进行二次变换,然后才进行量化: Void TComTrQuant::transformNxN( TComTU & rTu,const ComponentID ...

  2. VVC/JEM代码学习12:transformNxN

    对残差次数进行量化编码的函数,相比于HEVC,JEM中加入了二次变换,即在第一次主变换又进行第二次变换:此外,还加入了EMT,和DCT2是并列关系,根据相关索引进行选择; Void TComTrQua ...

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

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

  4. HEVC代码学习——帧间预测:预测MV获取(xEstimateMvPredAMVP、fillMVPCand)

    HEVC帧间预测在AMVP模式下是依靠xEstimateMvPredAMVP函数获取预测MV(MVP)的. 这部分内容的学习还可以参考这两篇博客: HEVC代码学习15:AMVP相关函数 HM编码器代 ...

  5. H.266/VVC代码学习20:角度预测入口 / 特殊模式的PDPC技术(predIntraAng)

    1.predIntraAng函数 predIntraAng是帧内0~66这67种预测的入口.其中可细分为: 模式0:PLANAR模式 模式1:DC模式 模式2~66:角度模式 此函数在亮度预测和色度预 ...

  6. H.266/VVC代码学习21:帧内角度预测的实现 / 近对角模式的PDPC(xPredIntraAng)

    xPredIntraAng函数的作用是对任意大小的块和任意模式,如何将参考像素的值根据其模式的角度填充进每一个像素. 下图是basketball drill的一个16*16的块,其预测模式为10(偏斜 ...

  7. H.266代码学习:JEM使用方法

    之前在HEVC代码学习0:HM使用+码流分析教程中详细介绍了HM使用方法,而H.266参考代码JEM已经成型,因此这里简单介绍下JEM的使用方法. 阅读建议: JEM使用方法与HM类似,使用中改动在于 ...

  8. H.266/VVC代码学习17:帧内亮度预测的编解码(intra_luma_pred_modes)

    引--亮度预测:H.266/VVC代码学习5:VTM4.0帧内亮度预测代码(estIntraPredLumaQT) 一.结论: 亮度编解码根据MPM列表的值分为两个阶段: 1 亮度模式在MPM列表中: ...

  9. H.266/VVC-VTM代码学习25-VTM中RDcost的计算与λ的设定(一)

    H.266/VVC专栏传送 上一篇:H.266/VVC-VTM代码学习24-根据当前块位置与尺寸确定隐藏划分模式getImplicitSplit() 下一篇: 目录 H.266/VVC专栏传送 前言 ...

  10. H.266代码学习:xIntraCodingTUBlock函数

    今天来继续学习帧内编码的重要函数xIntraCodingTUBlock,上次 H.266代码学习:xRecurIntraCodingLumaQT函数 学习中提到,xIntraCodingTUBlock ...

最新文章

  1. H.264 Video Codec速度和质量
  2. 举个栗子看如何做MySQL 内核深度优化
  3. 使用AWSTATS自动分析Nginx日志
  4. 样条之连分式插值函数
  5. [摘]全文检索引擎Solr系列—–全文检索基本原理
  6. 显示当前行号、文件名和函数名(二)
  7. 04 理解SQL与T-SQL的概念测试分析 1214
  8. open source Swift, Objective-C and the next 20 years of development
  9. Android 自动扫描歌曲,Android扫描本地音乐文件开发案例分享
  10. [转] Sublime Text3 配置 NodeJs 环境
  11. 新牛牛盲盒微信小程序源码_支持流量变现,带完整素材图片
  12. 文件后缀名怎么修改?文件不显示后缀名怎么办
  13. 六大场景,看懂声纹识别技术怎样“抗疫防疫” 小快
  14. 【链块技术10期】区块链基础语言(二)——GO语言开发环境搭建
  15. 【统计分析系统--SAS介绍】
  16. Python采集--小说一键保存txt文本
  17. 【PDF密码删除软件】Enolsoft PDF Password Remover for Mac
  18. 亚马逊asin关键词排名追踪_图文实操:手把手教你优化亚马逊关键词的自然排名!...
  19. Tex数学公式及字符
  20. 技术所带来的生产率提升,将会大大提高资本要素回报率

热门文章

  1. 林锐的《高质量编程》学习笔记——内存分配方式
  2. VISIO画图软件安装
  3. 系统集成项目管理工程师考试英语吗?
  4. Python全栈开发【基础-11】基本数据类型内置方法
  5. BIM族库下载——塔吊等垂直运输设备族库
  6. 计算机考试系统客户端网址,[中学]计算机基础测评系统考试客户端操作步骤.doc...
  7. DenseNet算法详解
  8. STM32 SPI 读取12位RM08 SSI 编码器信号
  9. 一信通短信接口对接_吉信通:短信接口是什么?
  10. Shiro框架(一)-Shiro概述