作者:66

(转载请注明出处)

从我自身的学习历程来看,建议大家先把理论扎实了再去理解代码,代码里也有注释,与理论的地方一对应加上一点C编程基础很容易就能理解。

我们先了解相关理论,此处可参考这一篇博文,基本和他推荐的书上大同小异,链接:http://blog.csdn.net/linpengbin/article/details/44158331,个别图片不好理解,但配文字足够了。

按从内到外的顺序,能够更清晰地理解代码实现。

1. HEVC帧内Planar模式预测-预测像素计算

图一、参考像素和预测像素分布

预测像素可以看成水平、垂直方向的平均值,计算如下:

(不支持公式编辑,只能截图上传)

其实通过公式可以知道,在planar模式下,HEVC是将右面那行和下面那行的参考像素分别用右上和左下那一点填充全部,然后按像素渐变处理。

对于4x4的TU,参考像素不滤波。

xPredIntraPlanar函数处理细节:

代码部分:

/** Function for deriving planar intra prediction.* \param pSrc pointer to reconstructed sample array* \param srcStride the stride of the reconstructed sample array* \param rpDst reference to pointer for the prediction sample array* \param dstStride the stride of the prediction sample array* \param width the width of the block* \param height the height of the block** This function derives the prediction samples for planar mode (intra coding).*///planar模式下计算预测像素Void TComPrediction::xPredIntraPlanar( Int* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height ){assert(width == height);Int k, l, bottomLeft, topRight;Int horPred;Int leftColumn[MAX_CU_SIZE+1], topRow[MAX_CU_SIZE+1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];UInt blkSize = width;//像素块宽度UInt offset2D = width;//NUInt shift1D = g_aucConvertToBit[ width ] + 2;//LOG2(N)UInt shift2D = shift1D + 1;//LOG2(N) + 1// Get left and above reference column and rowfor(k=0;k<blkSize+1;k++)//不需要左上顶点{topRow[k] = pSrc[k-srcStride];//当前PU上方一行零一个leftColumn[k] = pSrc[k*srcStride-1];//当前PU左面一列零一个}// Prepare intermediate variables used in interpolationbottomLeft = leftColumn[blkSize];//左下那一个topRight   = topRow[blkSize];//右上那一个//计算公式//Ph(x,y) = (width - x)leftColumn(y) + x*topRight,这样写能看出距离越远,权值不同//Pv(x,y) = (width - y)topRow(x)     + y*bottomleft//P(x,y)  = (Ph(x,y) + Pv(x,y) + offset2D)>>(shift2D),明明就一个width,它偏叫个offset2D。//代码里做了调整如下//Ph(x,y) = width*leftColumn(y) + x*(topRight - leftColumn(y))//Pv(x,y) = width*topRow(x) + y*(bottomleft - topRow(x))for (k=0;k<blkSize;k++){bottomRow[k]   = bottomLeft - topRow[k];//rightColumn[k] = topRight   - leftColumn[k];//topRow[k]      <<= shift1D;//等同于topRow[k] *= widthleftColumn[k]  <<= shift1D;//等同于leftColumn[k] *= width}// Generate prediction signalfor (k=0;k<blkSize;k++)//k代表y向,I代表x向{horPred = leftColumn[k] + offset2D;//每次出循环更新一次for (l=0;l<blkSize;l++)//这里用加减替掉了乘,虽然简单,但自己以前没想到过,学习了。{horPred += rightColumn[k];topRow[l] += bottomRow[l];rpDst[k*dstStride+l] = ( (horPred + topRow[l]) >> shift2D );}}}

2. HEVC帧内角度模式预测-预测像素计算

HEVC亮度分量帧内预测支持5中大小的PU:4X4 ~ 64X64,都对应35中预测模式。

其中编号2~34为角度模式,在下面解析的函数xPredIntraAng中,也包含了编号为1的DC模式预测像素计算。

图二、角度模式的方向

每个角度模式都有相应的偏移编号,通过偏移可以计算角度。

图三、角度模式下的偏移编号。

上面数格子可以看到偏移量的绝对值有[0,    2,    5,   9,  13,  17,  21,  26,  32]。

对于水平模式11~17、垂直模式18~25即角度偏移量为负的角度模式,在计算重构像素前要进行投影。

具体投影方式以模式20(offset=-21)为例,左侧边界的参考像素按角度方向可以投影到上方参考像素的左侧。

图四、角度投影示意

Ref表示投影buf:

接着计算当前像素对应的参考像素在Ref中的位置:

加权因子ω:

最后是像素预测值:

具体的计算方式和最后像素预测值在代码中有详细解释,不作赘述。

代码中包含了DC模式下预测像素的初步填充:

Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter ){Int k,l;Int blkSize        = width;Pel* pDst          = rpDst;// Map the mode index to main prediction direction and angleassert( dirMode > 0 ); //no planarBool modeDC        = dirMode < 2;//DC是1Bool modeHor       = !modeDC && (dirMode < 18);//水平类角度2~17Bool modeVer       = !modeDC && !modeHor;//垂直类角度18~34Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX : modeHor ? -((Int)dirMode - HOR_IDX) : 0;//ver:(18到34-26=-8到8,hor:2至17-10 = -8至7.Int absAng         = abs(intraPredAngle);Int signAng        = intraPredAngle < 0 ? -1 : 1;//水平左半部分为-,右半部分为+;垂直下半部分为-,上半部分角度为+。// Set bitshifts and scale the angle parameter to block sizeInt angTable[9]    = {0,    2,    5,   9,  13,  17,  21,  26,  32};Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / AngleInt invAngle       = invAngTable[absAng];//选择偏移度absAng             = angTable[absAng];//映射时*32intraPredAngle     = signAng * absAng;//加上符号表示偏移方向// Do the DC predictionif (modeDC)//如果是DC模式,所有值设为dcval{Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, blkAboveAvailable, blkLeftAvailable);//dcbal取可用参考像素平均值,仅算上面和左面for (k=0;k<blkSize;k++){for (l=0;l<blkSize;l++){pDst[k*dstStride+l] = dcval;}}}// Do angular predictions角度预测部分else{Pel* refMain;Pel* refSide;Pel  refAbove[2*MAX_CU_SIZE+1];Pel  refLeft[2*MAX_CU_SIZE+1];// Initialise the Main and Left reference array.if (intraPredAngle < 0){for (k=0;k<blkSize+1;k++){refAbove[k+blkSize-1] = pSrc[k-srcStride-1];//上方复制参考像素}for (k=0;k<blkSize+1;k++){refLeft[k+blkSize-1] = pSrc[(k-1)*srcStride-1];//同上}refMain = (modeVer ? refAbove : refLeft) + (blkSize-1);//存放ref的bufrefSide = (modeVer ? refLeft : refAbove) + (blkSize-1);//需映射的像素的起点// Extend the Main reference to the left.Int invAngleSum    = 128;       // rounding for (shift by 8)for (k=-1; k>blkSize*intraPredAngle>>5; k--)//填充映射像素{invAngleSum += invAngle;refMain[k] = refSide[invAngleSum>>8];//一次一步将side映射到ref中}}else//intraPredAngle>0,不需要映射{for (k=0;k<2*blkSize+1;k++)//拷贝上和左参考像素{refAbove[k] = pSrc[k-srcStride-1];}for (k=0;k<2*blkSize+1;k++){refLeft[k] = pSrc[(k-1)*srcStride-1];}refMain = modeVer ? refAbove : refLeft;refSide = modeVer ? refLeft  : refAbove;}if (intraPredAngle == 0)//10水平或26垂直的模式,{for (k=0;k<blkSize;k++){for (l=0;l<blkSize;l++){pDst[k*dstStride+l] = refMain[l+1];}}if ( bFilter )//修正一行或一列的像素,refSide[k+1]-refSide[0]为预测方向上的像素变化{for (k=0;k<blkSize;k++){pDst[k*dstStride] = Clip3(0, (1<<bitDepth)-1, pDst[k*dstStride] + (( refSide[k+1] - refSide[0] ) >> 1) );}}}else{//开始计算预测像素值Int deltaPos=0;Int deltaInt;Int deltaFract;Int refMainIndex;//当前像素的预测值,P(x,y)= ( ((32-deltaFract) * refMain[refMainIndex] + deltaFract * refMain[refMainIndex + 1] + 16)  >> 5 )for (k=0;k<blkSize;k++){deltaPos += intraPredAngle;deltaInt   = deltaPos >> 5;deltaFract = deltaPos & (32 - 1);if (deltaFract){// Do linear filteringfor (l=0;l<blkSize;l++){refMainIndex        = l+deltaInt+1;pDst[k*dstStride+l] = (Pel) ( ((32-deltaFract)*refMain[refMainIndex]+deltaFract*refMain[refMainIndex+1]+16) >> 5 );}}else{// Just copy the integer samplesfor (l=0;l<blkSize;l++)//就是(((32-0) * refMain[refMainIndex] + 0 * refMain[refMainIndex+1] + 16)  >> 5 );{pDst[k*dstStride+l] = refMain[l+deltaInt+1];}}}}//上面没有refmain,refside避免区分上和左,但像素填充全按垂直的那几个模式,所以水平模式还要再翻转一下。// Flip the block if this is the horizontal modeif (modeHor){Pel  tmp;for (k=0;k<blkSize-1;k++){for (l=k+1;l<blkSize;l++){tmp                 = pDst[k*dstStride+l];pDst[k*dstStride+l] = pDst[l*dstStride+k];pDst[l*dstStride+k] = tmp;}}}}}

3.DC模式下预测像素计算

在角度预测中将DC模式下预测值设为dcval,再进一步修正:

左上角:

P(1,1)=(R(1,0)+R(0,1)+2*dcValue+2)>>2

第一行(除左上角):

P(x,1) = (R(x,0) + 3*dcValue + 2)>>2

第一列(除左上角):

P(1,y) = (R(0,y) + 3*dcValue + 2)>>2

这段代码很简单,如下:

/** Function for filtering intra DC predictor.* \param pSrc pointer to reconstructed sample array* \param iSrcStride the stride of the reconstructed sample array* \param rpDst reference to pointer for the prediction sample array* \param iDstStride the stride of the prediction sample array* \param iWidth the width of the block* \param iHeight the height of the block** This function performs filtering left and top edges of the prediction samples for DC mode (intra coding).*/Void TComPrediction::xDCPredFiltering( Int* pSrc, Int iSrcStride, Pel*& rpDst, Int iDstStride, Int iWidth, Int iHeight ){Pel* pDst = rpDst;Int x, y, iDstStride2, iSrcStride2;// boundary pixels processingpDst[0] = (Pel)((pSrc[-iSrcStride] + pSrc[-1] + 2 * pDst[0] + 2) >> 2);//左上角for ( x = 1; x < iWidth; x++ )//第一行{pDst[x] = (Pel)((pSrc[x - iSrcStride] +  3 * pDst[x] + 2) >> 2);}for ( y = 1, iDstStride2 = iDstStride, iSrcStride2 = iSrcStride-1; y < iHeight; y++, iDstStride2+=iDstStride, iSrcStride2+=iSrcStride )//第一列{pDst[iDstStride2] = (Pel)((pSrc[iSrcStride2] + 3 * pDst[iDstStride2] + 2) >> 2);}return;}

4.亮度分量预测像素的计算

调用上面三个函数,实现亮度预测像素计算的函数。

使用if~else判断来调用以上三个函数。

//亮度分量角度预测Void TComPrediction::predIntraLumaAng(TComPattern* pcTComPattern, UInt uiDirMode, Pel* piPred, UInt uiStride, Int iWidth, Int iHeight, Bool bAbove, Bool bLeft ){Pel *pDst = piPred;Int *ptrSrc;assert( g_aucConvertToBit[ iWidth ] >= 0 ); //   4x  4assert( g_aucConvertToBit[ iWidth ] <= 5 ); // 128x128assert( iWidth == iHeight  );//指向经滤波后的参考像素首地址ptrSrc = pcTComPattern->getPredictorPtr( uiDirMode, g_aucConvertToBit[ iWidth ] + 2, m_piYuvExt );// get starting pixel in blockInt sw = 2 * iWidth + 1;//当前PU首地址在ptrSrc中的偏移// Create the predictionif ( uiDirMode == PLANAR_IDX )//planar模式{xPredIntraPlanar( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight );//计算像素预测值}else{if ( (iWidth > 16) || (iHeight > 16) )//角度模式,计算像素预测值{xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, false );}else{xPredIntraAng(g_bitDepthY, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, uiDirMode, bAbove, bLeft, true );//注意,最后一个为trueif( (uiDirMode == DC_IDX ) && bAbove && bLeft )//DC模式{xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight);}}}}

5.estIntraPredQT亮度分量预测全过程

函数中主要完成对亮度分量的预测,遍历所有分割和最优预测模式,从中选出率失真最好的模式,因涉及到更多的内容,在之后的总结总进行分析。

图五、本文分析函数结构图

代码如下:

//亮度分量帧内预测全过程VoidTEncSearch::estIntraPredQT( TComDataCU* pcCU,TComYuv*    pcOrgYuv,TComYuv*    pcPredYuv,TComYuv*    pcResiYuv,TComYuv*    pcRecoYuv,UInt&       ruiDistC,Bool        bLumaOnly ){UInt    uiDepth        = pcCU->getDepth(0);//当前CU的深度//uiNumPU,划分后pu的个数,PU的划分模式,帧内有2种:2NX2N,NxN;帧间有8种:4种对称模式:2Nx2N,2NxN,Nx2N,NxN,四种非对称模式,2NxnU(上下1:3),2NxnD(上下3:1),nLx2N(左右1:3),nRx2N(左右3:1)。帧间还有一种skip模式,即不需要编码残差信息时。UInt    uiNumPU        = pcCU->getNumPartitions();//当前cu划分为pu的数目UInt    uiInitTrDepth  = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1;//计算变换深度,实际为uiDepthUInt    uiWidth        = pcCU->getWidth (0) >> uiInitTrDepth;//当前cu的宽度UInt    uiHeight       = pcCU->getHeight(0) >> uiInitTrDepth;//当前cu的长度UInt    uiQNumParts    = pcCU->getTotalNumPart() >> 2;//当前cu包含的最小分区4x4的数目。UInt    uiWidthBit     = pcCU->getIntraSizeIdx(0);UInt    uiOverallDistY = 0;UInt    uiOverallDistC = 0;UInt    CandNum;Double  CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];//===== set QP and clear Cbf =====if ( 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;//记录当前pu的Zorder坐标for( 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 );//获取当前PU邻域的可用性,对参考像素进行滤波,代码里的宽长都为当前cu的宽长,但是pu与tu的划分是以depth为基础的隐式划分,名字上仍以Cu表示,实际此Cu已经代表了PU或TU VpcCU->getPattern()->initAdiPattern( pcCU, uiPartOffset, uiInitTrDepth, m_piYuvExt, m_iYuvExtStride, m_iYuvExtHeight, bAboveAvail, bLeftAvail );//===== determine set of modes to be tested (using prediction signal only) =====Int numModesAvailable     = 35; //total number of Intra modesPel* piOrg         = pcOrgYuv ->getLumaAddr( uiPU, uiWidth );Pel* piPred        = pcPredYuv->getLumaAddr( uiPU, uiWidth );UInt uiStride      = pcPredYuv->getStride();UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ];//MPM的数目,像是候选预测模式数目//  g_aucIntraModeNumFast[]={3,8,8,3,3,3,3};2x2,4x4,8x8,16x16,32x32,64x64,128x128Bool doFastSearch = (numModesForFullRD != numModesAvailable);//这里doFastSearch恒为真if (doFastSearch)//此时是肯定会进入{assert(numModesForFullRD < numModesAvailable);//确定numModesForFullRD < numModesAvailablefor( Int i=0; i < numModesForFullRD; i++ ){CandCostList[ i ] = MAX_DOUBLE;//初始化率失真表,全部为最大值,方便后面比较。}CandNum = 0;for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )//遍历35种预测模式{UInt uiMode = modeIdx;//调用亮度帧内预测函数 VpredIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, bAboveAvail, bLeftAvail );// use hadamard transform here哈达玛矩阵计算率失真UInt uiSad = m_pcRdCost->calcHAD(g_bitDepthY, piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );//计算SATD(残差经HAD后的绝对值总和)UInt   iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );//计算编码当面所需的bitsDouble cost      = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();//率失真代价//iModeBits编码当前模式需要的bits,CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );//帧内预测模式候选列表}#if FAST_UDI_USE_MPMInt uiPreds[3] = {-1, -1, -1};Int iMode = -1;//分两种情况,如果前两个相同iMode=1,否则iMode=2Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode );//获取亮度预测的前三个MPMsif( iMode >= 0 ){numCand = iMode;}for( Int j=0; j < numCand; j++){Bool mostProbableModeIncluded = false;Int mostProbableMode = uiPreds[j];//取出预测的MPMfor( Int i=0; i < numModesForFullRD; i++){mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);//检查MPMs,是否被uiRdModeList包含}if (!mostProbableModeIncluded)//若没被包含,则将该MPM包含进uiRdModeList里{uiRdModeList[numModesForFullRD++] = mostProbableMode;//计算率失真的备选模式表}}#endif // FAST_UDI_USE_MPM}else{for( Int i=0; i < numModesForFullRD; i++){uiRdModeList[i] = i;}}//check modes 确定帧内预测模式的最佳值主要有以下几个步骤://1. 对numModesForFullRD中预测模式进行遍历,算出RDcosts,但至多对depth=1的CU进行遍历,提高了速度。//2.得到最优,有可能包括次优的两个。//3.最佳模式下的分割模式遍历,以得最优结果。//===== 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;//RDcostsfor( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ ){// set luma prediction modeUInt uiOrgMode = uiRdModeList[uiMode];pcCU->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;//当前预测RDcost#if HHI_RQT_INTRA_SPEEDUPxRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, true, dPUCost );#elsexRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, dPUCost );#endif// check r-d costif( dPUCost < dBestPUCost )//更新最佳预测模式相关参数{#if HHI_RQT_INTRA_SPEEDUP_MOD//次优模式uiSecondBestMode  = 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;xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, false, dPUCost );//此时倒数第二个参数为false// check r-d costif( 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 loopif( uiNumPU > 1 ){ // set Cbf for all blocksUInt uiCombCbfY = 0;UInt uiCombCbfU = 0;UInt uiCombCbfV = 0;UInt uiPartIdx  = 0;for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts ){uiCombCbfY |= pcCU->getCbf( uiPartIdx, TEXT_LUMA,     1 );uiCombCbfU |= pcCU->getCbf( uiPartIdx, TEXT_CHROMA_U, 1 );uiCombCbfV |= pcCU->getCbf( uiPartIdx, TEXT_CHROMA_V, 1 );}for( UInt uiOffs = 0; uiOffs < 4 * uiQNumParts; uiOffs++ ){pcCU->getCbf( TEXT_LUMA     )[ uiOffs ] |= uiCombCbfY;pcCU->getCbf( TEXT_CHROMA_U )[ uiOffs ] |= uiCombCbfU;pcCU->getCbf( TEXT_CHROMA_V )[ uiOffs ] |= uiCombCbfV;}}//===== reset context models =====m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);//===== set distortion (rate and r-d costs are determined later) =====ruiDistC                   = uiOverallDistC;pcCU->getTotalDistortion() = uiOverallDistY + uiOverallDistC;}

(转载请务必注明出处)

作者:66

HEVC亮度分量帧内预测模式代码详解相关推荐

  1. 关于帧内预测模式的视频隐写代码介绍

    关于帧内预测模式的视频隐写代码介绍 前言 一.H.265/HEVC的帧内预测过程 二.论文[1]的介绍以及如何复现 前言 在早期的基于帧内预测模式(IPM)的H.265/HEVC视频中,大多是基于自定 ...

  2. AVS 帧内预测模式的汇编优化

    王瑞* 基金项目:本课题得到国家自然科学基金资助项目基金(项目编号:60772101)的资助. 作者简介:王瑞(1986-), 男, 山东莱芜人, 硕士, 主要从事视频压缩方面的研究. E-mail: ...

  3. Overview of HEVC之4 帧内预测

    帧内预测是根据传输块的尺寸进行操作的,并且空间上相邻传输块的先前解码的边界像素被用来形成预测信号,对4*4到32*32的传输块定义了33种不同的方向预测.图6显示了可能的预测方向.另外也用到了平面预测 ...

  4. ICASSP2020:VVC基于线性模型的帧内预测模式

    本文来自ICASSP2020论文<LINEAR MODEL-BASED INTRA PREDICTION IN VVC TEST MODEL> 论文使用含3个参数的线性模型进行帧内预测 L ...

  5. H.266/VVC:色度帧内预测模式之CCLM技术

    一.色度模式编码 1.色度预测模式候选列表 VVC中色度分量的预测过程和亮度分量预测过程不同,其首先是构建色度预测模式候选列表如下表,有8种模式,由4种和亮度模式相同的模式.3种CCLM模式和1种DM ...

  6. HEVC算法和体系结构:预测编码之帧内预测

    预测编码之帧内预测(Intra-Picture Prediction) 预测编码(Prediction Coding)是视频编码的核心技术之一,指利用已编码的一个或几个样本值,根据某种模型或方法,对当 ...

  7. 2.H.265/HEVC —— 帧内预测

    在H.265/HEVC中,35种预测模式是在PU的基础上定义的,而具体帧内预测过程的实现则是以TU为单位的.编撰规定PU可以以四叉树的形式划分TU,且一个PU内所有TU共享同一种预测模式的形式划分TU ...

  8. HEVC帧内预测参考相邻帧代码解析

    作者:66 (转载请注明出处) 参考链接:http://blog.csdn.net/hevc_cjl/article/details/8200793 亮度分量的帧内预测涉及到的模块比较多,CU-> ...

  9. HEVC学习(六) —— 帧内预测系列之四

    本文主要把实现亮度分量帧内预测的主函数的大体框架通过代码注释的方式介绍一下. [cpp]  view plain copy Void TEncSearch::estIntraPredQT( TComD ...

最新文章

  1. 推荐 查公司信息的一个网站
  2. 设置 docker容器 禁用网络
  3. python使用lxml及request爬取-python+lxml 爬取网页信息及储存
  4. python 运算符 (算术运算符、比较(关系)运算符、赋值运算符、逻辑运算符、位运算符、成员运算符、身份运算符、运算符优先级)(与或非)(异或)
  5. 11 Python之初识函数
  6. Java 文件 IO 操作
  7. CSS属性值之百分数
  8. 用Java+Html+MySQL 实现注册、登录(servlet框架)-(一)
  9. 【目标检测-YOLO】YOLO v2总结
  10. python操作redis集群是连接池么_Python如何操作redis使用连接池
  11. 云e办学习笔记(四)SpringSecurity学习(二)
  12. 常见计算机主机内部硬件设备,计算机的硬件主要包括中央处理器、储存器、输出设备和...
  13. 什么是PCB加工中树脂塞孔工艺?
  14. 支持tcam的服务器,一种支持TCAM规则更新和压缩方法.doc
  15. 手机电影正式亮相,华为手机不断提高影像力让手机拍电影成为可能
  16. JPA 7. Spring 整合 JPA
  17. 利用Python计算两个地理位置之间的中点
  18. 电脑亮度突然无法调节,并且重置电脑也不能解决问题
  19. 2014年12月23日 平常心
  20. c语言字符串碱基互补配对,C++ 6.0 配对碱基链 自己编的程序输出总是有问题 求解...

热门文章

  1. python_pdf常规使用
  2. DOS的建文件夹,移动图片,多级文件夹建立
  3. svn commit 提示Aborting commit 失败问题解决办法
  4. Arduino + SmartAirFilter 制作智能感应的 PM 空气净化器
  5. 使用Lambda表达式对中文拼音排序(按中文字典排序)
  6. 综合布线系统工程中计算机插座的标识符号是,TD是综合布线系统工程中计算机插座的标识符号。...
  7. matlab画动物轮廓图,MATLAB一维插值的应用实例—画左右手的轮廓图
  8. ip.php是什么意思,有人频繁试探云主机的 ip_js. PHP 是什么操作?
  9. 双通道IPC如何RTSP取两个通道视频流?
  10. winform窗口的切换