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

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

 

[cpp]  view plain copy
  1. Void   
  2. TEncSearch::estIntraPredQT( TComDataCU* pcCU,   
  3.                            TComYuv*    pcOrgYuv,   
  4.                            TComYuv*    pcPredYuv,   
  5.                            TComYuv*    pcResiYuv,   
  6.                            TComYuv*    pcRecoYuv,  
  7.                            UInt&       ruiDistC,  
  8.                            Bool        bLumaOnly )  
  9. {  
  10.   UInt    uiDepth        = pcCU->getDepth(0); //!< 当前CU的深度  
  11.   UInt    uiNumPU        = pcCU->getNumPartInter(); //!< 当前CU的分割模式,(SIZE_2Nx2N:1, SIZE_2NxN:2, SIZE_Nx2N:2, SIZE_NxN:4 ... )  
  12.   UInt    uiInitTrDepth  = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1; //!< 用于计算变换的深度,实际深度为该值+uiDepth  
  13.   UInt    uiWidth        = pcCU->getWidth (0) >> uiInitTrDepth; //!< 当前PU的宽度,如果又分成4个子块,则宽度除以2  
  14.   UInt    uiHeight       = pcCU->getHeight(0) >> uiInitTrDepth; //!< 当前PU的高度,如果又分成4个子块,则高度除以2  
  15.   UInt    uiQNumParts    = pcCU->getTotalNumPart() >> 2; // 最小的分区是4x4大小的块,这里计算出以该4x4块为单位的分割数,这么做便于计算当前CU的Zorder坐标  
  16.   UInt    uiWidthBit     = pcCU->getIntraSizeIdx(0);  
  17.   UInt    uiOverallDistY = 0;  
  18.   UInt    uiOverallDistC = 0;  
  19.   UInt    CandNum;  
  20.   Double  CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];  
  21.     
  22.   //===== set QP and clear Cbf =====  
  23.   if ( pcCU->getSlice()->getPPS()->getUseDQP() == true)  
  24.   {  
  25.     pcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth );  
  26.   }  
  27.   else  
  28.   {  
  29.     pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth );  
  30.   }  
  31.     
  32.   //===== loop over partitions =====  
  33.   UInt uiPartOffset = 0; //!< 用于记录当前PU的Zorder坐标  
  34.   for( UInt uiPU = 0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts ) //!< 对当前CU中的每个PU进行遍历  
  35.   {  
  36.     //===== init pattern for luma prediction =====  
  37.     Bool bAboveAvail = false;  
  38.     Bool bLeftAvail  = false;  
  39.     pcCU->getPattern()->initPattern   ( pcCU, uiInitTrDepth, uiPartOffset ); // set parameters from CU data for accessing neighbouring pixels  
  40.  // set luma parameters from CU data for accessing ADI data //!< 主要获取当前PU的邻域可用性,对参考样点进行设置及滤波  
  41.     pcCU->getPattern()->initAdiPattern( pcCU, uiPartOffset, uiInitTrDepth, m_piYuvExt, m_iYuvExtStride, m_iYuvExtHeight, bAboveAvail, bLeftAvail );  
  42.       
  43.     //===== determine set of modes to be tested (using prediction signal only) =====  
  44.     Int numModesAvailable     = 35; //total number of Intra modes  
  45.     Pel* piOrg         = pcOrgYuv ->getLumaAddr( uiPU, uiWidth );  
  46.     Pel* piPred        = pcPredYuv->getLumaAddr( uiPU, uiWidth );  
  47.     UInt uiStride      = pcPredYuv->getStride();  
  48.     UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];  
  49.     Int numModesForFullRD = g_aucIntraModeNumFast[ uiWidthBit ]; //!< MPM数目  
  50.     //!< g_aucIntraModeNumFast[] = {3, 8, 8, 3, 3, 3, 3}; 2x2, 4x4, 8x8, 16x16, 32x32, 64x64, 128x128  
  51.     Bool doFastSearch = (numModesForFullRD != numModesAvailable); //!< 此处doFastSearch恒为真  
  52.     if (doFastSearch)  
  53.     {  
  54.       assert(numModesForFullRD < numModesAvailable);  
  55.   
  56.       for( Int i=0; i < numModesForFullRD; i++ )   
  57.       {  
  58.         CandCostList[ i ] = MAX_DOUBLE;  
  59.       }  
  60.       CandNum = 0;  
  61.         
  62.       for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ ) //!< 遍历35种帧内预测模式  
  63.       {  
  64.         UInt uiMode = modeIdx;  
  65.   //! 调用亮度帧内预测函数  
  66.         predIntraLumaAng( pcCU->getPattern(), uiMode, piPred, uiStride, uiWidth, uiHeight, pcCU, bAboveAvail, bLeftAvail );  
  67.           
  68.         // use hadamard transform here  
  69.         UInt uiSad = m_pcRdCost->calcHAD( piOrg, uiStride, piPred, uiStride, uiWidth, uiHeight );  
  70.           
  71.         UInt   iModeBits = xModeBitsIntra( pcCU, uiMode, uiPU, uiPartOffset, uiDepth, uiInitTrDepth );  
  72.         Double cost      = (Double)uiSad + (Double)iModeBits * m_pcRdCost->getSqrtLambda();  
  73.           
  74.         CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );  
  75.       }  
  76.       
  77. #if FAST_UDI_USE_MPM // UDI---Unified Directional Intra  
  78.       Int uiPreds[3] = {-1, -1, -1};  
  79.       Int iMode = -1;  //!< 如果三个MPMs的前两个相同,则iMode=1,否则iMode=2  
  80.       Int numCand = pcCU->getIntraDirLumaPredictor( uiPartOffset, uiPreds, &iMode ); //!< 获取亮度帧内预测模式的三个MPMs  
  81.       if( iMode >= 0 ) //!< iMode = 1 or 2,因此,numCand会被重新赋值为iMode  
  82.       {  
  83.         numCand = iMode;  
  84.       }  
  85.         
  86.       for( Int j=0; j < numCand; j++)  
  87.   
  88.       {  
  89.         Bool mostProbableModeIncluded = false;  
  90.         Int mostProbableMode = uiPreds[j]; //!< 取出MPM  
  91.           
  92.         for( Int i=0; i < numModesForFullRD; i++)  
  93.         {  
  94.           mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]); //!< 检查MPMs是否被uiRdModeList所包含  
  95.         }  
  96.         if (!mostProbableModeIncluded)  //!< 如果没被包含,则将该MPM包含到uiRdModeList里  
  97.         {  
  98.           uiRdModeList[numModesForFullRD++] = mostProbableMode;  
  99.         }  
  100.       }  
  101. #endif // FAST_UDI_USE_MPM  
  102.     } //!< if (doFastSearch)  
  103.     else  
  104.     {  
  105.       for( Int i=0; i < numModesForFullRD; i++)  
  106.       {  
  107.         uiRdModeList[i] = i;  
  108.       }  
  109.     }  
  110.       
  111.     //===== check modes (using r-d costs) =====  
  112.  //! 帧内预测模式最佳值的确定主要有以下几个步骤:1. 对numModesForFullRD种预测模式进行遍历,即对每种模式计算出  
  113.  //! 对应的RD costs,但该步骤中,并不会把一个CU的所有分割都算一遍,而仅仅对于至多深度为1的分割进行遍历,这么做  
  114.  //! 大大减少了运算量,提高速度;2. 在第1个步骤中,会粗略得到最佳预测模式(在HM9.0中会得到包括次优解在内的两个  
  115.  //! 预测模式),存储下来,以供第3步使用;3. 在第2步的基础上,对最佳(及次优)预测模式的所有分割模式遍历一遍,  
  116.  //! 得到最终的最佳结果  
  117. #if HHI_RQT_INTRA_SPEEDUP_MOD  
  118.     UInt   uiSecondBestMode  = MAX_UINT;  
  119.     Double dSecondBestPUCost = MAX_DOUBLE;  
  120. #endif  
  121.       
  122.     UInt    uiBestPUMode  = 0; //!< 存放最佳预测模式  
  123.     UInt    uiBestPUDistY = 0; //!< 存放最佳预测模式对应的亮度失真值  
  124.     UInt    uiBestPUDistC = 0; //!< 存放最佳预测模式对应的色度失真值  
  125.     Double  dBestPUCost   = MAX_DOUBLE;  //!< 存放最佳预测模式对应的总代价  
  126.     for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ ) //!< 遍历存储在uiRdModeList里的模式  
  127.     {  
  128.       // set luma prediction mode  
  129.       UInt uiOrgMode = uiRdModeList[uiMode];  
  130.         
  131.       pcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );  
  132.         
  133.       // set context models  
  134.       if( m_bUseSBACRD )  
  135.       {  
  136.         m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );  
  137.       }  
  138.         
  139.       // determine residual for partition  
  140.       UInt   uiPUDistY = 0;  //!< 存放当前预测模式对应的亮度失真值  
  141.       UInt   uiPUDistC = 0;  //!< 存放当前预测模式对应的色度失真值  
  142.       Double dPUCost   = 0.0; //!< 存放当前预测模式对应的代价  
  143. #if HHI_RQT_INTRA_SPEEDUP //! 注意这个函数倒数第二个参数,此时为true  
  144.       xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, true, dPUCost );  
  145. #else  
  146.       xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, dPUCost );  
  147. #endif  
  148.         
  149.       // check r-d cost  
  150.       if( dPUCost < dBestPUCost ) //!< 更新最佳预测模式相关参数  
  151.       {  
  152. #if HHI_RQT_INTRA_SPEEDUP_MOD  
  153.         uiSecondBestMode  = uiBestPUMode;  
  154.         dSecondBestPUCost = dBestPUCost;  
  155. #endif  
  156.         uiBestPUMode  = uiOrgMode;  
  157.         uiBestPUDistY = uiPUDistY;  
  158.         uiBestPUDistC = uiPUDistC;  
  159.         dBestPUCost   = dPUCost;  
  160.           
  161.         xSetIntraResultQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcRecoYuv );  
  162.           
  163.         UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );  
  164.         ::memcpy( m_puhQTTempTrIdx,  pcCU->getTransformIdx()       + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  165.         ::memcpy( m_puhQTTempCbf[0], pcCU->getCbf( TEXT_LUMA     ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  166.         ::memcpy( m_puhQTTempCbf[1], pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  167.         ::memcpy( m_puhQTTempCbf[2], pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  168.         ::memcpy( m_puhQTTempTransformSkipFlag[0], pcCU->getTransformSkip(TEXT_LUMA)     + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  169.         ::memcpy( m_puhQTTempTransformSkipFlag[1], pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  170.         ::memcpy( m_puhQTTempTransformSkipFlag[2], pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  171.       }  
  172. #if HHI_RQT_INTRA_SPEEDUP_MOD  
  173.       else if( dPUCost < dSecondBestPUCost )  
  174.       {  
  175.         uiSecondBestMode  = uiOrgMode;  
  176.         dSecondBestPUCost = dPUCost;  
  177.       }  
  178. #endif  
  179.     } // Mode loop  
  180.       
  181. #if HHI_RQT_INTRA_SPEEDUP  
  182. #if HHI_RQT_INTRA_SPEEDUP_MOD  
  183.     for( UInt ui =0; ui < 2; ++ui )  
  184. #endif  
  185.     {  
  186. #if HHI_RQT_INTRA_SPEEDUP_MOD  
  187.       UInt uiOrgMode   = ui ? uiSecondBestMode  : uiBestPUMode;  
  188.       if( uiOrgMode == MAX_UINT )  
  189.       {  
  190.         break;  
  191.       }  
  192. #else  
  193.       UInt uiOrgMode = uiBestPUMode; //!< 设置模式为最佳预测模式  
  194. #endif  
  195.         
  196.       pcCU->setLumaIntraDirSubParts ( uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );  
  197.         
  198.       // set context models  
  199.       if( m_bUseSBACRD )  
  200.       {  
  201.         m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );  
  202.       }  
  203.         
  204.       // determine residual for partition  
  205.       UInt   uiPUDistY = 0;  
  206.       UInt   uiPUDistC = 0;  
  207.       Double dPUCost   = 0.0;  
  208.    //! 注意该函数倒数第二个参数,此时为false  
  209.       xRecurIntraCodingQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcOrgYuv, pcPredYuv, pcResiYuv, uiPUDistY, uiPUDistC, false, dPUCost );  
  210.         
  211.       // check r-d cost  
  212.       if( dPUCost < dBestPUCost )  
  213.       {  
  214.         uiBestPUMode  = uiOrgMode;  
  215.         uiBestPUDistY = uiPUDistY;  
  216.         uiBestPUDistC = uiPUDistC;  
  217.         dBestPUCost   = dPUCost;  
  218.           
  219.         xSetIntraResultQT( pcCU, uiInitTrDepth, uiPartOffset, bLumaOnly, pcRecoYuv );  
  220.           
  221.         UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );  
  222.         ::memcpy( m_puhQTTempTrIdx,  pcCU->getTransformIdx()       + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  223.         ::memcpy( m_puhQTTempCbf[0], pcCU->getCbf( TEXT_LUMA     ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  224.         ::memcpy( m_puhQTTempCbf[1], pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  225.         ::memcpy( m_puhQTTempCbf[2], pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  226.         ::memcpy( m_puhQTTempTransformSkipFlag[0], pcCU->getTransformSkip(TEXT_LUMA)     + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  227.         ::memcpy( m_puhQTTempTransformSkipFlag[1], pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  228.         ::memcpy( m_puhQTTempTransformSkipFlag[2], pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, uiQPartNum * sizeof( UChar ) );  
  229.       }  
  230.     } // Mode loop  
  231. #endif  
  232.       
  233.     //--- update overall distortion ---  
  234.     uiOverallDistY += uiBestPUDistY;  
  235.     uiOverallDistC += uiBestPUDistC;  
  236.       
  237.     //--- update transform index and cbf ---  
  238.     UInt uiQPartNum = pcCU->getPic()->getNumPartInCU() >> ( ( pcCU->getDepth(0) + uiInitTrDepth ) << 1 );  
  239.     ::memcpy( pcCU->getTransformIdx()       + uiPartOffset, m_puhQTTempTrIdx,  uiQPartNum * sizeof( UChar ) );  
  240.     ::memcpy( pcCU->getCbf( TEXT_LUMA     ) + uiPartOffset, m_puhQTTempCbf[0], uiQPartNum * sizeof( UChar ) );  
  241.     ::memcpy( pcCU->getCbf( TEXT_CHROMA_U ) + uiPartOffset, m_puhQTTempCbf[1], uiQPartNum * sizeof( UChar ) );  
  242.     ::memcpy( pcCU->getCbf( TEXT_CHROMA_V ) + uiPartOffset, m_puhQTTempCbf[2], uiQPartNum * sizeof( UChar ) );  
  243.     ::memcpy( pcCU->getTransformSkip(TEXT_LUMA)     + uiPartOffset, m_puhQTTempTransformSkipFlag[0], uiQPartNum * sizeof( UChar ) );  
  244.     ::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_U) + uiPartOffset, m_puhQTTempTransformSkipFlag[1], uiQPartNum * sizeof( UChar ) );  
  245.     ::memcpy( pcCU->getTransformSkip(TEXT_CHROMA_V) + uiPartOffset, m_puhQTTempTransformSkipFlag[2], uiQPartNum * sizeof( UChar ) );  
  246.     //--- set reconstruction for next intra prediction blocks ---  
  247.     if( uiPU != uiNumPU - 1 )  
  248.     {  
  249.       Bool bSkipChroma  = false;  
  250.       Bool bChromaSame  = false;  
  251.       UInt uiLog2TrSize = g_aucConvertToBit[ pcCU->getSlice()->getSPS()->getMaxCUWidth() >> ( pcCU->getDepth(0) + uiInitTrDepth ) ] + 2;  
  252.       if( !bLumaOnly && uiLog2TrSize == 2 )  
  253.       {  
  254.         assert( uiInitTrDepth  > 0 );  
  255.         bSkipChroma  = ( uiPU != 0 );  
  256.         bChromaSame  = true;  
  257.       }  
  258.         
  259.       UInt    uiCompWidth   = pcCU->getWidth ( 0 ) >> uiInitTrDepth;  
  260.       UInt    uiCompHeight  = pcCU->getHeight( 0 ) >> uiInitTrDepth;  
  261.       UInt    uiZOrder      = pcCU->getZorderIdxInCU() + uiPartOffset;  
  262.       Pel*    piDes         = pcCU->getPic()->getPicYuvRec()->getLumaAddr( pcCU->getAddr(), uiZOrder );  
  263.       UInt    uiDesStride   = pcCU->getPic()->getPicYuvRec()->getStride();  
  264.       Pel*    piSrc         = pcRecoYuv->getLumaAddr( uiPartOffset );  
  265.       UInt    uiSrcStride   = pcRecoYuv->getStride();  
  266.       for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )  
  267.       {  
  268.         for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )  
  269.         {  
  270.           piDes[ uiX ] = piSrc[ uiX ];  
  271.         }  
  272.       }  
  273.       if( !bLumaOnly && !bSkipChroma )  
  274.       {  
  275.         if( !bChromaSame )  
  276.         {  
  277.           uiCompWidth   >>= 1;  
  278.           uiCompHeight  >>= 1;  
  279.         }  
  280.         piDes         = pcCU->getPic()->getPicYuvRec()->getCbAddr( pcCU->getAddr(), uiZOrder );  
  281.         uiDesStride   = pcCU->getPic()->getPicYuvRec()->getCStride();  
  282.         piSrc         = pcRecoYuv->getCbAddr( uiPartOffset );  
  283.         uiSrcStride   = pcRecoYuv->getCStride();  
  284.         for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )  
  285.         {  
  286.           for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )  
  287.           {  
  288.             piDes[ uiX ] = piSrc[ uiX ];  
  289.           }  
  290.         }  
  291.         piDes         = pcCU->getPic()->getPicYuvRec()->getCrAddr( pcCU->getAddr(), uiZOrder );  
  292.         piSrc         = pcRecoYuv->getCrAddr( uiPartOffset );  
  293.         for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )  
  294.         {  
  295.           for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )  
  296.           {  
  297.             piDes[ uiX ] = piSrc[ uiX ];  
  298.           }  
  299.         }  
  300.       }  
  301.     }  
  302.       
  303.     //=== update PU data ====  
  304.     pcCU->setLumaIntraDirSubParts     ( uiBestPUMode, uiPartOffset, uiDepth + uiInitTrDepth );  
  305.     pcCU->copyToPic                   ( uiDepth, uiPU, uiInitTrDepth );  
  306.   } // PU loop  
  307.     
  308.     
  309.   if( uiNumPU > 1 )  
  310.   { // set Cbf for all blocks  
  311.     UInt uiCombCbfY = 0;  
  312.     UInt uiCombCbfU = 0;  
  313.     UInt uiCombCbfV = 0;  
  314.     UInt uiPartIdx  = 0;  
  315.     for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts )  
  316.     {  
  317.       uiCombCbfY |= pcCU->getCbf( uiPartIdx, TEXT_LUMA,     1 );  
  318.       uiCombCbfU |= pcCU->getCbf( uiPartIdx, TEXT_CHROMA_U, 1 );  
  319.       uiCombCbfV |= pcCU->getCbf( uiPartIdx, TEXT_CHROMA_V, 1 );  
  320.     }  
  321.     for( UInt uiOffs = 0; uiOffs < 4 * uiQNumParts; uiOffs++ )  
  322.     {  
  323.       pcCU->getCbf( TEXT_LUMA     )[ uiOffs ] |= uiCombCbfY;  
  324.       pcCU->getCbf( TEXT_CHROMA_U )[ uiOffs ] |= uiCombCbfU;  
  325.       pcCU->getCbf( TEXT_CHROMA_V )[ uiOffs ] |= uiCombCbfV;  
  326.     }  
  327.   }  
  328.     
  329.   //===== reset context models =====  
  330.   if(m_bUseSBACRD)  
  331.   {  
  332.     m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);  
  333.   }  
  334.     
  335.   //===== set distortion (rate and r-d costs are determined later) =====  
  336.   ruiDistC                   = uiOverallDistC;  
  337.   pcCU->getTotalDistortion() = uiOverallDistY + uiOverallDistC;  
  338. }  

(转载请注明出处。)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值