H.265之三 -帧内预测(4)

来源:互联网 发布:软件售后维护合同 编辑:程序博客网 时间:2024/04/29 21:22

本文主要把实现亮度分量帧内预测的主函数的大体框架通过代码注释的方式介绍一下。

Void TEncSearch::estIntraPredQT( TComDataCU* pcCU,                            TComYuv*    pcOrgYuv,                            TComYuv*    pcPredYuv,                            TComYuv*    pcResiYuv,                            TComYuv*    pcRecoYuv,                           UInt&       ruiDistC,                           Bool        bLumaOnly ){  UInt    uiDepth        = pcCU->getDepth(0); //!< 当前CU的深度  UInt    uiNumPU        = pcCU->getNumPartInter(); //!< 当前CU的分割模式,(SIZE_2Nx2N:1, SIZE_2NxN:2, SIZE_Nx2N:2, SIZE_NxN:4 ... )  UInt    uiInitTrDepth  = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1; //!< 用于计算变换的深度,实际深度为该值+uiDepth  UInt    uiWidth        = pcCU->getWidth (0) >> uiInitTrDepth; //!< 当前PU的宽度,如果又分成4个子块,则宽度除以2  UInt    uiHeight       = pcCU->getHeight(0) >> uiInitTrDepth; //!< 当前PU的高度,如果又分成4个子块,则高度除以2  UInt    uiQNumParts    = pcCU->getTotalNumPart() >> 2; // 最小的分区是4x4大小的块,这里计算出以该4x4块为单位的分割数,这么做便于计算当前CU的Zorder坐标  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 ) //!< 对当前CU中的每个PU进行遍历  {    //===== init pattern for luma prediction =====    Bool bAboveAvail = false;    Bool bLeftAvail  = false;    pcCU->getPattern()->initPattern   ( pcCU, uiInitTrDepth, uiPartOffset ); // set parameters from CU data for accessing neighbouring pixels // set luma parameters from CU data for accessing ADI data //!< 主要获取当前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) =====    Int numModesAvailable     = 35; //total number of Intra modes    Pel* 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, 128x128    Bool doFastSearch = (numModesForFullRD != numModesAvailable); //!< 此处doFastSearch恒为真    if (doFastSearch)    {      assert(numModesForFullRD < numModesAvailable);      for( Int i=0; i < numModesForFullRD; i++ )       {        CandCostList[ i ] = MAX_DOUBLE;      }      CandNum = 0;            for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) //!< 遍历35种帧内预测模式      {        UInt uiMode = modeIdx;  //! 调用亮度帧内预测函数        predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, pcCU, bAboveAvail, bLeftAvail );                // use hadamard transform here        UInt uiSad = m_pcRdCost->calcHAD( 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_MPM // UDI---Unified Directional Intra      Int uiPreds[3] = {-1, -1, -1};      Int iMode = -1;  //!< 如果三个MPMs的前两个相同,则iMode=1,否则iMode=2      Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode ); //!< 获取亮度帧内预测模式的三个MPMs      if( iMode >= 0 ) //!< iMode = 1 or 2,因此,numCand会被重新赋值为iMode      {        numCand = iMode;      }            for( Int j=0; j < numCand; j++)      {        Bool mostProbableModeIncluded = false;        Int mostProbableMode = uiPreds[j]; //!< 取出MPM                for( Int i=0; i < numModesForFullRD; i++)        {          mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]); //!< 检查MPMs是否被uiRdModeList所包含        }        if (!mostProbableModeIncluded)  //!< 如果没被包含,则将该MPM包含到uiRdModeList里        {          uiRdModeList[numModesForFullRD++] = mostProbableMode;        }      }#endif // FAST_UDI_USE_MPM    } //!< if (doFastSearch)    else    {      for( Int i=0; i < numModesForFullRD; i++)      {        uiRdModeList[i] = i;      }    }        //===== check modes (using r-d costs) ===== //! 帧内预测模式最佳值的确定主要有以下几个步骤:1. 对numModesForFullRD种预测模式进行遍历,即对每种模式计算出 //! 对应的RD costs,但该步骤中,并不会把一个CU的所有分割都算一遍,而仅仅对于至多深度为1的分割进行遍历,这么做 //! 大大减少了运算量,提高速度;2. 在第1个步骤中,会粗略得到最佳预测模式(在HM9.0中会得到包括次优解在内的两个 //! 预测模式),存储下来,以供第3步使用;3. 在第2步的基础上,对最佳(及次优)预测模式的所有分割模式遍历一遍, //! 得到最终的最佳结果#if HHI_RQT_INTRA_SPEEDUP_MOD    UInt   uiSecondBestMode  = MAX_UINT;    Double dSecondBestPUCost = MAX_DOUBLE;#endif        UInt    uiBestPUMode  = 0; //!< 存放最佳预测模式    UInt    uiBestPUDistY = 0; //!< 存放最佳预测模式对应的亮度失真值    UInt    uiBestPUDistC = 0; //!< 存放最佳预测模式对应的色度失真值    Double  dBestPUCost   = MAX_DOUBLE;  //!< 存放最佳预测模式对应的总代价    for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ ) //!< 遍历存储在uiRdModeList里的模式    {      // set luma prediction mode      UInt uiOrgMode = uiRdModeList[uiMode];            pcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );            // set context models      if( m_bUseSBACRD )      {        m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );      }            // determine residual for partition      UInt   uiPUDistY = 0;  //!< 存放当前预测模式对应的亮度失真值      UInt   uiPUDistC = 0;  //!< 存放当前预测模式对应的色度失真值      Double dPUCost   = 0.0; //!< 存放当前预测模式对应的代价#if HHI_RQT_INTRA_SPEEDUP //! 注意这个函数倒数第二个参数,此时为true      xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, true, dPUCost );#else      xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, dPUCost );#endif            // check r-d cost      if( dPUCost < dBestPUCost ) //!< 更新最佳预测模式相关参数      {#if HHI_RQT_INTRA_SPEEDUP_MOD        uiSecondBestMode  = uiBestPUMode;        dSecondBestPUCost = dBestPUCost;#endif        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 ) );      }#if HHI_RQT_INTRA_SPEEDUP_MOD      else if( dPUCost < dSecondBestPUCost )      {        uiSecondBestMode  = uiOrgMode;        dSecondBestPUCost = dPUCost;      }#endif    } // Mode loop    #if HHI_RQT_INTRA_SPEEDUP#if HHI_RQT_INTRA_SPEEDUP_MOD    for( UInt ui =0; ui < 2; ++ui )#endif    {#if HHI_RQT_INTRA_SPEEDUP_MOD      UInt uiOrgMode   = ui ? uiSecondBestMode  : uiBestPUMode;      if( uiOrgMode == MAX_UINT )      {        break;      }#else      UInt uiOrgMode = uiBestPUMode; //!< 设置模式为最佳预测模式#endif            pcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );            // set context models      if( m_bUseSBACRD )      {        m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );      }            // determine residual for partition      UInt   uiPUDistY = 0;      UInt   uiPUDistC = 0;      Double dPUCost   = 0.0;   //! 注意该函数倒数第二个参数,此时为false      xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, false, dPUCost );            // check r-d cost      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      if( uiNumPU > 1 )  { // set Cbf for all blocks    UInt 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 =====  if(m_bUseSBACRD)  {    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;}
转自(http://blog.csdn.net/hevc_cjl/article/details/8200793)

原创粉丝点击