HM编码器代码阅读(35)——帧内预测(二)帧内预测总流程
来源:互联网 发布:linux书籍 编辑:程序博客网 时间:2024/05/18 02:46
亮度块的帧内预测
帧内预测的流程
注意:如果没有特别说明,操作的对象都是亮度块(Luma)
1、遍历所有的预测模式,得到每种模式下的残差信号,再对残差信号进行Hadamard变换计算SATD值
2、利用SATD值计算每种预测模式的率失真代价,选取率失真代价最小的几种模式(与PU大小相关)为预测模式集3、将已编码相邻块的预测模式补充到预测模式集中
4、遍历模式集合中的所有模式,并对残差信号进行正常编码(熵编码),计算率失真代价
5、选取最优的预测模式作为该PU的最优模式
6、当亮度块的模式确定之后,把该模式以及DC、planar、水平方向模式、垂直方向模式作为色度块的候选模式,选取最优的模式即可
亮度块的帧内预测的入口函数
入口函数是estIntraPredQT,流程如下:1、遍历CU下面的每一个PU,对于每一个PU,进行下面的操作
2、先初始化访问相邻像素块的工具类
3、调用initAdiPattern,对参考像素值进行预处理和滤波
4、首先计算需要进行完整RD率失真优化操作的模式的数量numModesForFullRD,可以根据PU的宽度来得到
5、检测快速搜索标识doFastSearch,通过比较numModesForFullRD和帧内预测模式的总数量(35种)是否相等得到
,如果不相等,那么使用快速搜索模式,否则使用普通模式;(一般来说doFastSearch都是true)
6、如果doFastSearch是true,那么进行下面的操作:
(1)遍历帧内预测的35种模式,对于每一种模式进行帧内预测,然后使用Hadamard变换计算SATD值,
利用SATD的值计算每种模式的率失真代价
(2)从35个模式中选取numModesForFullRD个代价比较优的模式,组成模式候选列表
(3)调用getIntraDirLumaPredictor,根据相邻块的预测模式来对当前块的模式进行预测,若干预测模式
(4)遍历预测模式,如果它不在候选模式列表中,那么把它添加到候选模式列表中
7、如果doFastSearch是false,那么表示numModesForFullRD的数量是35,那么所有的帧内预测模式都被添加到候选模式列表中
8、用一句话表述步骤6和7,那就是,快速搜索模式下,只选取几种最优可能的模式作为候选模式,普通模式下,所有的帧内预测模式都是候选模式
9、遍历候选模式列表,对于其中的每一模式,进行下面的操作:
(1)调用xRecurIntraCodingQT,进行预测变换量化,注意该函数倒数第二个参数是true,表示会按照四叉树的方式继续向下划分
(2)根据率失真代价选取最优的模式
10、经过步骤8,我们已经选取了最优的模式,但是该模式下的编码块是继续向下划分的,因此,我们还要计算该模式下,编码块不向下划分的时候的代价(调用xRecurIntraCodingQT,倒数第二个参数设置为false),通过比较编码块划分和不划分两种情况,得到最优的参数和模式
12、经过了上面的步骤之后,我们已经得到最优模式和变换系数了,此时我们应该重建当前块,因为后面的PU需要使用该重建块作为预测块。
/*** 亮度块的帧内预测的入口函数*/Void TEncSearch::estIntraPredQT( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv,UInt& ruiDistC,Bool bLumaOnly ){// 删除无关代码*****// 候选的cost列表Double CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];//===== set QP and clear Cbf =====// 设置QP参数,清理Cbfif ( pcCU->getSlice()->getPPS()->getUseDQP() == true){pcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth );}else{// 进入此处pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth );}//===== loop over partitions =====UInt uiPartOffset = 0;// 循环处理CU下的每一个预测块PUfor( UInt uiPU = 0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts ){//===== init pattern for luma prediction =====Bool bAboveAvail = false; // 上面的块是否有效Bool bLeftAvail = false;// 左边的块是否有效// 初始化访问相邻块的工具类pcCU->getPattern()->initPattern ( pcCU, uiInitTrDepth, uiPartOffset );// 这个函数很重要:主要是在着帧内预测之前,使用重建后的YUV图像对当前PU的相邻样点进行滤波,为接下来的进行的角度预测// 提供参考样点值pcCU->getPattern()->initAdiPattern( pcCU, uiPartOffset, uiInitTrDepth, m_piYuvExt, m_iYuvExtStride, m_iYuvExtHeight, bAboveAvail, bLeftAvail );//===== determine set of modes to be tested (using prediction signal only) =====// 35种帧内预测模式Int numModesAvailable = 35; //total number of Intra modes// 在原始的YUV中获取获亮度的地址Pel* piOrg = pcOrgYuv ->getLumaAddr( uiPU, uiWidth );// 在预测的YUV中获取亮度的地址Pel* piPred = pcPredYuv->getLumaAddr( uiPU, uiWidth );// 偏移UInt uiStride = pcPredYuv->getStride(); // 8UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ];//8Bool doFastSearch = (numModesForFullRD != numModesAvailable);//true// 使用快速搜索模式if (doFastSearch){assert(numModesForFullRD < numModesAvailable);for( Int i=0; i < numModesForFullRD; i++ ) {// 用于存储每一种模式的消耗CandCostList[ i ] = MAX_DOUBLE;}CandNum = 0;// 遍历35种帧内预测模式,选取若干个代价比较小的模式作为后续处理的模式for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) // 总共有35种模式,numModesAvailable = 35{UInt uiMode = modeIdx;// 对亮度块进行预测predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );// use hadamard transform here// 使用hadamard变换,计算SATD的值UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );UInt iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );// 计算此种模式的代价Double cost = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();// 更新候选列表CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );}#if FAST_UDI_USE_MPMInt uiPreds[3] = {-1, -1, -1};Int iMode = -1;// 根据相邻块的预测模式来对当前块的模式进行预测,得到若干模式(称为预测模式),存放在uiPreds中Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode );if( iMode >= 0 ){// 将候选列表的索引设置为此模式numCand = iMode;}// 遍历预测的模式,如果它不在模式候选列表中,那么把它添加到模式候选列表中for( Int j=0; j < numCand; j++){Bool mostProbableModeIncluded = false;Int mostProbableMode = uiPreds[j];for( Int i=0; i < numModesForFullRD; i++){mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);}if (!mostProbableModeIncluded){uiRdModeList[numModesForFullRD++] = mostProbableMode;}}#endif // FAST_UDI_USE_MPM}else{for( Int i=0; i < numModesForFullRD; i++){uiRdModeList[i] = i;}}//===== check modes (using r-d costs) =====#if HHI_RQT_INTRA_SPEEDUP_MODUInt uiSecondBestMode = MAX_UINT;Double dSecondBestPUCost = MAX_DOUBLE;#endifUInt uiBestPUMode = 0;UInt uiBestPUDistY = 0;UInt uiBestPUDistC = 0;Double dBestPUCost = MAX_DOUBLE;// 遍历候选集中的模式for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ ){// set luma prediction modeUInt uiOrgMode = uiRdModeList[uiMode];pcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );// set context models// 设置上下文模型m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );// determine residual for partitionUInt uiPUDistY = 0;UInt uiPUDistC = 0;Double dPUCost = 0.0;#if HHI_RQT_INTRA_SPEEDUP// 通过多候选模式进行预测、变换、量化等操作来计算代价// 注意倒数第二个参数bCheckFirst是true,表示会继续按照四叉树的方式向下划分xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, true, dPUCost );// 重要函数end#elsexRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, dPUCost );#endif// check r-d cost// 从候选列表中选取最优的模式if( dPUCost < dBestPUCost ){#if HHI_RQT_INTRA_SPEEDUP_MODuiSecondBestMode = uiBestPUMode;dSecondBestPUCost = dBestPUCost;#endifuiBestPUMode = uiOrgMode;uiBestPUDistY = uiPUDistY;uiBestPUDistC = uiPUDistC;dBestPUCost = dPUCost;xSetIntraResultQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcRecoYuv );UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[0], pcCU->getCbf( TEXT_LUMA ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[1], pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[2], pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[0], pcCU->getTransformSkip(TEXT_LUMA) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[1], pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[2], pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, uiQPartNum * sizeof( UChar ) );}#if HHI_RQT_INTRA_SPEEDUP_MODelse if( dPUCost < dSecondBestPUCost ){uiSecondBestMode = uiOrgMode;dSecondBestPUCost = dPUCost;}#endif} // Mode loop#if HHI_RQT_INTRA_SPEEDUP#if HHI_RQT_INTRA_SPEEDUP_MODfor( UInt ui =0; ui < 2; ++ui )#endif{#if HHI_RQT_INTRA_SPEEDUP_MODUInt uiOrgMode = ui ? uiSecondBestMode : uiBestPUMode;if( uiOrgMode == MAX_UINT ){break;}#elseUInt uiOrgMode = uiBestPUMode;#endifpcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );// set context modelsm_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );// determine residual for partitionUInt uiPUDistY = 0;UInt uiPUDistC = 0;Double dPUCost = 0.0;// 现在已经知道最优模式了,使用最优模式对PU进行预测,然后变换量化等,计算代价// 注意倒数第二个参数bCheckFirst是false,表示当前PU不再进行划分,即只处理当前深度的PUxRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, false, dPUCost );// 检测同一种模式下,bCheckFirst为true和false的情况下,那个的代价更优if( dPUCost < dBestPUCost ){uiBestPUMode = uiOrgMode;uiBestPUDistY = uiPUDistY;uiBestPUDistC = uiPUDistC;dBestPUCost = dPUCost;xSetIntraResultQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcRecoYuv );UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[0], pcCU->getCbf( TEXT_LUMA ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[1], pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempCbf[2], pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[0], pcCU->getTransformSkip(TEXT_LUMA) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[1], pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempTransformSkipFlag[2], pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, uiQPartNum * sizeof( UChar ) );}} // Mode loop#endif//--- update overall distortion ---uiOverallDistY += uiBestPUDistY;uiOverallDistC += uiBestPUDistC;//--- update transform index and cbf ---UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );::memcpy( pcCU->getTransformIdx() + uiPartOffset, m_puhQTTempTrIdx, uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getCbf( TEXT_LUMA ) + uiPartOffset, m_puhQTTempCbf[0], uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, m_puhQTTempCbf[1], uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, m_puhQTTempCbf[2], uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getTransformSkip(TEXT_LUMA) + uiPartOffset, m_puhQTTempTransformSkipFlag[0], uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, m_puhQTTempTransformSkipFlag[1], uiQPartNum * sizeof( UChar ) );::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, m_puhQTTempTransformSkipFlag[2], uiQPartNum * sizeof( UChar ) );//--- set reconstruction for next intra prediction blocks ---// 变换量化/反变换反量化都已经处理完成了,那么设置重建块if( uiPU != uiNumPU - 1 ){Bool bSkipChroma = false;Bool bChromaSame = false;UInt uiLog2TrSize = g_aucConvertToBit[ pcCU->getSlice()->getSPS()->getMaxCUWidth() >> ( pcCU->getDepth(0) + uiInitTrDepth ) ] + 2;if( !bLumaOnly && uiLog2TrSize == 2 ){assert( uiInitTrDepth > 0 );bSkipChroma = ( uiPU != 0 );bChromaSame = true;}UInt uiCompWidth = pcCU->getWidth ( 0 ) >> uiInitTrDepth;UInt uiCompHeight = pcCU->getHeight( 0 ) >> uiInitTrDepth;UInt uiZOrder = pcCU->getZorderIdxInCU() + uiPartOffset;Pel* piDes = pcCU->getPic()->getPicYuvRec()->getLumaAddr( pcCU->getAddr(), uiZOrder );UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride();Pel* piSrc = pcRecoYuv->getLumaAddr( uiPartOffset );UInt uiSrcStride = pcRecoYuv->getStride();for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ){for( UInt uiX = 0; uiX < uiCompWidth; uiX++ ){piDes[ uiX ] = piSrc[ uiX ];}}if( !bLumaOnly && !bSkipChroma ){if( !bChromaSame ){uiCompWidth >>= 1;uiCompHeight >>= 1;}piDes = pcCU->getPic()->getPicYuvRec()->getCbAddr( pcCU->getAddr(), uiZOrder );uiDesStride = pcCU->getPic()->getPicYuvRec()->getCStride();piSrc = pcRecoYuv->getCbAddr( uiPartOffset );uiSrcStride = pcRecoYuv->getCStride();for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ){for( UInt uiX = 0; uiX < uiCompWidth; uiX++ ){piDes[ uiX ] = piSrc[ uiX ];}}piDes = pcCU->getPic()->getPicYuvRec()->getCrAddr( pcCU->getAddr(), uiZOrder );piSrc = pcRecoYuv->getCrAddr( uiPartOffset );for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride ){for( UInt uiX = 0; uiX < uiCompWidth; uiX++ ){piDes[ uiX ] = piSrc[ uiX ];}}}}//=== update PU data ====pcCU->setLumaIntraDirSubParts ( uiBestPUMode, uiPartOffset, uiDepth + uiInitTrDepth );pcCU->copyToPic ( uiDepth, uiPU, uiInitTrDepth );} // PU loop// 设置一些Cbf、重置熵编码上下文之类的操作// 删除无关代码*****}
1 0
- HM编码器代码阅读(35)——帧内预测(二)帧内预测总流程
- HM编码器代码阅读(38)——帧内预测(五)帧内预测之正式的预测操作
- HM编码器代码阅读(39)——帧内预测(六)帧内预测之色度色度的操作
- HM编码器代码阅读(34)——帧内预测(一)
- HM编码器代码阅读(40)——帧内预测的总结
- HM编码器代码阅读(36)——帧内预测(三)帧内预测之参考像素块的预处理和滤波
- HM编码器代码阅读(37)——帧内预测(四)帧内预测之候选模式列表的建立
- HM代码阅读:帧内预测(一)
- HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程
- HM编码器代码阅读(14)——帧间预测之AMVP模式(二)predInterSearch函数
- HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取
- HM编码器代码阅读(33)——帧间预测的总结
- homerHEVC代码阅读(41)——帧内预测
- HM编码器代码阅读(15)——帧间预测之AMVP模式(三)xGetBlkBits函数
- HM编码器代码阅读(30)——帧间预测之AMVP模式(五)运动估计
- HM编码器代码阅读(31)——帧间预测之AMVP/Merge模式(六)运动补偿
- HEVC参考软件(HM)代码阅读之帧内预测:Void TComPrediction::xPredIntraAng
- HM编码器代码阅读(17)——帧间预测之merge模式(一)Merge模式的介绍以及相关函数
- iOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
- 136. Single Number异或
- NVIDIA GameWorks and UE4
- NGUI3.11 离线Document文档
- css图片等比列放大
- HM编码器代码阅读(35)——帧内预测(二)帧内预测总流程
- 求排列的逆序数
- windows和linux进程间与线程间通信
- leetcode 113. Path Sum II
- 数据单向绑定
- Ubuntu16.4 安装 redis
- 集中日志服务器Rsyslog
- poj3304Segments(线段与直线相交)
- 《JS高程(3)》DOM2和DOM3-样式、视口尺寸问题-第12章笔记(23)