HEVC学习(六) —— 帧内预测系列之四
本文主要把实现亮度分量帧内预测的主函数的大体框架通过代码注释的方式介绍一下。
- 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;
- }
(转载请注明出处。)
HEVC学习(六) —— 帧内预测系列之四相关推荐
- [HEVC] HEVC学习(五) —— 帧内预测系列之三
[HEVC] HEVC学习(五) -- 帧内预测系列之三 今天主要介绍帧内预测一个很重要的函数initAdiPattern,它的主要功能有三个,(1)检测当前PU的相邻样点包括左上.上.右上.左.左下 ...
- H.266/VVC代码学习:帧内预测之角度预测函数(predIntraAng、xPredIntraAng)
predIntraAng函数 VTM中,帧内预测的角度预测的入口函数为predIntraAng函数,该函数主要是用于进行传统的帧内预测(Planar.DC.角度预测),然后对Planar和DC模式使用 ...
- HEVC亮度分量帧内预测模式代码详解
作者:66 (转载请注明出处) 从我自身的学习历程来看,建议大家先把理论扎实了再去理解代码,代码里也有注释,与理论的地方一对应加上一点C编程基础很容易就能理解. 我们先了解相关理论,此处可参考这一篇博 ...
- HEVC学习(五) —— 帧内预测系列之三
由于研究的需要,现将一晨不变大神的关于HEVC帧内预测的相关博客进行转载,方便自己查阅.一直都看一晨不变大神的帖子,受益匪浅.原著博客地址:http://blog.csdn.net/HEVC_CJL/ ...
- Overview of HEVC之4 帧内预测
帧内预测是根据传输块的尺寸进行操作的,并且空间上相邻传输块的先前解码的边界像素被用来形成预测信号,对4*4到32*32的传输块定义了33种不同的方向预测.图6显示了可能的预测方向.另外也用到了平面预测 ...
- ISP(图像信号处理)学习笔记-帧内预测组合(视频编码入门)
转载小柴柴博主的博文 本文链接:https://blog.csdn.net/cxy19931018/article/details/80635898 PDPC(Position Dependent I ...
- H.266/VVC技术学习:帧内预测之PDPC技术
1.PDPC介绍 为了补偿以上较简单帧内预测模式在利用空间冗余度方面的不足,VVC 中引入了一种根据当前样本的位置及帧内预测模式的角度自适应选取反方向角度上的参考样本信息作为新的一个相对互补性的帧内预 ...
- 从HEVC到VVC:帧内预测技术的演进(2) – 多划分及多参考行帧内预测
当前主流的视频编码标准(如H.264/AVC,VP9,AVS1,HEVC等)均使用当前预测单元最邻近的已重构像素对当前预测单元进行帧内预测.因为当前预测单元与其临近的像素之间有很强的相关性,该帧内预测 ...
- HEVC算法和体系结构:预测编码之帧内预测
预测编码之帧内预测(Intra-Picture Prediction) 预测编码(Prediction Coding)是视频编码的核心技术之一,指利用已编码的一个或几个样本值,根据某种模型或方法,对当 ...
最新文章
- MySQL如何从开源中获利
- linux下find命令用法
- 07_创建tensor,从numpy创建,从List创建,设置默认类型,rand/rand_like,randint,full,arange,linspace/logspace,linspace等等
- 假如给Go语言加上注解,程序会变怎样?
- 专注是最好的修行,一个80后IT从业者14年的成长与感悟
- Android--多选自动搜索提示
- 多线程之 NSOperation
- (转)《麻省理工科技评论》发布2017年全球十大突破性技术榜单
- 线性代数矩阵秩的8大性质、重要定理以及关系
- 基于ESP32CAM实现WebSocket服务器实时点灯
- html转换为pdf c#,HTML转PDF(C# itextsharp)
- SEO过程中外链的误区
- python抓取京东商品评价总数_python爬虫抓取和分析京东商城评价
- 浅谈互联网流量种类的划分,及其价值所在!做到精准引流定向吸粉。
- Python 机器人学习手册:1~5
- Mock 模拟测试简介及 Mockito 使用入门
- 2 理解网络协议的工作模式
- 虚拟机 Ubuntu16.04开机蓝屏问题
- 如何从前端入门到放弃
- 阿里巴巴2019财年Q1财报:连续六季度高速增长,加码投资未来