void RcGomTargetBits (sWelsEncCtx* pEncCtx, const int32_t kiSliceId) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SWelsSvcRc* pWelsSvcRc_Base = NULL; SRCSlicing* pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId]; int32_t iAllocateBits = 0; int32_t iSumSad = 0; int32_t iLastGomIndex = 0; int32_t iLeftBits = 0; const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice; int32_t i; iLastGomIndex = pSOverRc->iEndMbSlice / pWelsSvcRc->iNumberMbGom; iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice; if (iLeftBits <= 0) { pSOverRc->iGomTargetBits = 0; return; } else if (kiComplexityIndex >= iLastGomIndex) { iAllocateBits = iLeftBits; } else { pWelsSvcRc_Base = RcJudgeBaseUsability (pEncCtx); pWelsSvcRc_Base = (pWelsSvcRc_Base) ? pWelsSvcRc_Base : pWelsSvcRc; for (i = kiComplexityIndex; i <= iLastGomIndex; i++) { iSumSad += pWelsSvcRc_Base->pCurrentFrameGomSad[i]; } if (0 == iSumSad) iAllocateBits = WELS_DIV_ROUND (iLeftBits, (iLastGomIndex - kiComplexityIndex)); else iAllocateBits = WELS_DIV_ROUND ((int64_t)iLeftBits * pWelsSvcRc_Base->pCurrentFrameGomSad[kiComplexityIndex + 1], iSumSad); } pSOverRc->iGomTargetBits = iAllocateBits; }
void RcVBufferCalculationSkip (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SRCTemporal* pTOverRc = pWelsSvcRc->pTemporalOverRc; const int32_t kiOutputBits = WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame, INT_MULTIPLY); //condition 1: whole pBuffer fullness pWelsSvcRc->iBufferFullnessSkip += (pWelsSvcRc->iFrameDqBits - kiOutputBits); //condition 2: VGOP bits constraint const int32_t kiVGopBits = WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame * VGOP_SIZE, INT_MULTIPLY); int32_t iVGopBitsPred = 0; for (int32_t i = pWelsSvcRc->iFrameCodedInVGop + 1; i < VGOP_SIZE; i++) iVGopBitsPred += pTOverRc[pWelsSvcRc->iTlOfFrames[i]].iMinBitsTl; iVGopBitsPred -= pWelsSvcRc->iRemainingBits; double dIncPercent = iVGopBitsPred * 100.0 / kiVGopBits - (double)VGOP_BITS_PERCENTAGE_DIFF; if ((pWelsSvcRc->iBufferFullnessSkip > pWelsSvcRc->iBufferSizeSkip && pWelsSvcRc->iAverageFrameQp > pWelsSvcRc->iSkipQpValue) || (dIncPercent > pWelsSvcRc->iRcVaryPercentage)) { pEncCtx->iSkipFrameFlag = 1; pWelsSvcRc->iBufferFullnessSkip = pWelsSvcRc->iBufferFullnessSkip - kiOutputBits; #ifdef FRAME_INFO_OUTPUT fprintf (stderr, "skip one frame\n"); #endif } if (pWelsSvcRc->iBufferFullnessSkip < 0) pWelsSvcRc->iBufferFullnessSkip = 0; if (pEncCtx->iSkipFrameFlag == 1) { pWelsSvcRc->iRemainingBits += WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame, INT_MULTIPLY); pWelsSvcRc->iSkipFrameNum++; pWelsSvcRc->iSkipFrameInVGop++; } }
void CalcSliceComplexRatio (void* pRatio, SDqLayer* pCurDq, uint32_t* pSliceConsume) { SSliceCtx* pSliceCtx = &pCurDq->sSliceEncCtx; int32_t* pRatioList = (int32_t*)pRatio; int32_t iAvI[MAX_SLICES_NUM]; int32_t iSumAv = 0; uint32_t* pSliceTime = (uint32_t*)pSliceConsume; int32_t* pCountMbInSlice = (int32_t*)pSliceCtx->pCountMbNumInSlice; const int32_t kiSliceCount = pSliceCtx->iSliceNumInFrame; int32_t iSliceIdx = 0; WelsEmms(); while (iSliceIdx < kiSliceCount) { iAvI[iSliceIdx] = WELS_DIV_ROUND (INT_MULTIPLY * pCountMbInSlice[iSliceIdx], pSliceTime[iSliceIdx]); MT_TRACE_LOG (NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), pSliceConsumeTime[%d]= %d us, slice_run= %d", iSliceIdx, pSliceTime[iSliceIdx], pCountMbInSlice[iSliceIdx]); iSumAv += iAvI[iSliceIdx]; ++ iSliceIdx; } while (-- iSliceIdx >= 0) { pRatioList[iSliceIdx] = WELS_DIV_ROUND (INT_MULTIPLY * iAvI[iSliceIdx], iSumAv); } }
void RcVBufferCalculationPadding (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; const int32_t kiOutputBits = WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame, INT_MULTIPLY); const int32_t kiBufferThreshold = WELS_DIV_ROUND (PADDING_THRESHOLD * (-pWelsSvcRc->iBufferSizePadding), INT_MULTIPLY); pWelsSvcRc->iBufferFullnessPadding += (pWelsSvcRc->iFrameDqBits - kiOutputBits); if (pWelsSvcRc->iBufferFullnessPadding < kiBufferThreshold) { pWelsSvcRc->iPaddingSize = -pWelsSvcRc->iBufferFullnessPadding; pWelsSvcRc->iPaddingSize >>= 3; // /8 pWelsSvcRc->iBufferFullnessPadding = 0; } else
// GOM based RC related for uiSliceMbNum decision, only used at SM_FIXEDSLCNUM_SLICE bool GomValidCheckSliceMbNum (const int32_t kiMbWidth, const int32_t kiMbHeight, SSliceArgument* pSliceArg) { uint32_t* pSlicesAssignList = & (pSliceArg->uiSliceMbNum[0]); const uint32_t kuiSliceNum = pSliceArg->uiSliceNum; const int32_t kiMbNumInFrame = kiMbWidth * kiMbHeight; const int32_t kiMbNumPerSlice = kiMbNumInFrame / kuiSliceNum; int32_t iNumMbLeft = kiMbNumInFrame; int32_t iMinimalMbNum = kiMbWidth; // in theory we need only 1 SMB, here let it as one SMB row required int32_t iMaximalMbNum = 0; // dynamically assign later int32_t iGomSize; uint32_t uiSliceIdx = 0; // for test // The default RC is Bit-rate mode [Yi], but need consider as below: // Tuned to use max of mode0 and mode1 due can not refresh on this from rc mode changed outside, 8/16/2011 // NOTE: GOM_ROW_MODE0_?P is integer multipler of GOM_ROW_MODE1_?P, which predefined at rc.h there, so GOM_ROM take MODE0 as the initial if (kiMbWidth <= MB_WIDTH_THRESHOLD_90P) iGomSize = kiMbWidth * GOM_ROW_MODE0_90P; else if (kiMbWidth <= MB_WIDTH_THRESHOLD_180P) iGomSize = kiMbWidth * GOM_ROW_MODE0_180P; else if (kiMbWidth <= MB_WIDTH_THRESHOLD_360P) iGomSize = kiMbWidth * GOM_ROW_MODE0_360P; else iGomSize = kiMbWidth * GOM_ROW_MODE0_720P; // GOM boundary aligned int32_t iNumMbAssigning = WELS_DIV_ROUND (INT_MULTIPLY * kiMbNumPerSlice, iGomSize * INT_MULTIPLY) * iGomSize; int32_t iCurNumMbAssigning = 0; iMinimalMbNum = iGomSize; while (uiSliceIdx + 1 < kuiSliceNum) { iMaximalMbNum = iNumMbLeft - (kuiSliceNum - uiSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts // make sure one GOM at least in each slice for safe if (iNumMbAssigning < iMinimalMbNum) iCurNumMbAssigning = iMinimalMbNum; else if (iNumMbAssigning > iMaximalMbNum) iCurNumMbAssigning = ( iMaximalMbNum / iGomSize ) * iGomSize; else iCurNumMbAssigning = iNumMbAssigning; if (iCurNumMbAssigning <= 0) { return false; } iNumMbLeft -= iCurNumMbAssigning; if (iNumMbLeft <= 0) { return false; } pSlicesAssignList[uiSliceIdx] = iCurNumMbAssigning; ++ uiSliceIdx; } pSlicesAssignList[uiSliceIdx] = iNumMbLeft; if ( iNumMbLeft < iMinimalMbNum ) { return false; } return true; }
void RcInitSliceInformation (sWelsEncCtx* pEncCtx) { SSliceCtx* pCurSliceCtx = pEncCtx->pCurDqLayer->pSliceEncCtx; SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SRCSlicing* pSOverRc = &pWelsSvcRc->pSlicingOverRc[0]; const int32_t kiSliceNum = pWelsSvcRc->iSliceNum; const int32_t kiBitsPerMb = WELS_DIV_ROUND (pWelsSvcRc->iTargetBits * INT_MULTIPLY, pWelsSvcRc->iNumberMbFrame); for (int32_t i = 0; i < kiSliceNum; i++) { pSOverRc->iStartMbSlice = pSOverRc->iEndMbSlice = pCurSliceCtx->pFirstMbInSlice[i]; pSOverRc->iEndMbSlice += (pCurSliceCtx->pCountMbNumInSlice[i] - 1); pSOverRc->iTotalQpSlice = 0; pSOverRc->iTotalMbSlice = 0; pSOverRc->iTargetBitsSlice = WELS_DIV_ROUND (kiBitsPerMb * pCurSliceCtx->pCountMbNumInSlice[i], INT_MULTIPLY); pSOverRc->iFrameBitsSlice = 0; pSOverRc->iGomBitsSlice = 0; ++ pSOverRc; } }
void RcUpdateBitrateFps (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SRCTemporal* pTOverRc = pWelsSvcRc->pTemporalOverRc; SSpatialLayerConfig* pDLayerParam = &pEncCtx->pSvcParam->sSpatialLayers[pEncCtx->uiDependencyId]; SSpatialLayerInternal* pDLayerParamInternal = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; const int32_t kiGopSize = (1 << pDLayerParamInternal->iDecompositionStages); const int32_t kiHighestTid = pDLayerParamInternal->iHighestTemporalId; int32_t input_iBitsPerFrame = WELS_ROUND (pDLayerParam->iSpatialBitrate * INT_MULTIPLY / pDLayerParamInternal->fInputFrameRate); const int32_t kiGopBits = WELS_DIV_ROUND (input_iBitsPerFrame * kiGopSize, INT_MULTIPLY); int32_t i; pWelsSvcRc->iBitRate = pDLayerParam->iSpatialBitrate; pWelsSvcRc->fFrameRate = pDLayerParamInternal->fInputFrameRate; int32_t iTargetVaryRange = FRAME_iTargetBits_VARY_RANGE * (MAX_BITS_VARY_PERCENTAGE - pWelsSvcRc->iRcVaryRatio); int32_t iMinBitsRatio = (MAX_BITS_VARY_PERCENTAGE) * INT_MULTIPLY - iTargetVaryRange; int32_t iMaxBitsRatio = (MAX_BITS_VARY_PERCENTAGE) * (INT_MULTIPLY + FRAME_iTargetBits_VARY_RANGE); for (i = 0; i <= kiHighestTid; i++) { const int64_t kdConstraitBits = kiGopBits * pTOverRc[i].iTlayerWeight; pTOverRc[i].iMinBitsTl = WELS_DIV_ROUND (kdConstraitBits * iMinBitsRatio, INT_MULTIPLY * MAX_BITS_VARY_PERCENTAGE * WEIGHT_MULTIPLY); pTOverRc[i].iMaxBitsTl = WELS_DIV_ROUND (kdConstraitBits * iMaxBitsRatio, INT_MULTIPLY * MAX_BITS_VARY_PERCENTAGE * WEIGHT_MULTIPLY); } //When bitrate is changed, pBuffer size should be updated pWelsSvcRc->iBufferSizeSkip = WELS_DIV_ROUND (pWelsSvcRc->iBitRate * pWelsSvcRc->iSkipBufferRatio, INT_MULTIPLY); pWelsSvcRc->iBufferSizePadding = WELS_DIV_ROUND (pWelsSvcRc->iBitRate * PADDING_BUFFER_RATIO, INT_MULTIPLY); //change remaining bits if (pWelsSvcRc->iBitsPerFrame > REMAIN_BITS_TH) pWelsSvcRc->iRemainingBits = pWelsSvcRc->iRemainingBits * input_iBitsPerFrame / pWelsSvcRc->iBitsPerFrame; pWelsSvcRc->iBitsPerFrame = input_iBitsPerFrame; }
void CalcSliceComplexRatio (SDqLayer* pCurDq) { SSliceCtx* pSliceCtx = &pCurDq->sSliceEncCtx; SSlice* pSliceInLayer = pCurDq->sLayerInfo.pSliceInLayer; int32_t iSumAv = 0; const int32_t kiSliceCount = pSliceCtx->iSliceNumInFrame; int32_t iSliceIdx = 0; int32_t iAvI[MAX_SLICES_NUM]; WelsEmms(); while (iSliceIdx < kiSliceCount) { iAvI[iSliceIdx] = WELS_DIV_ROUND (INT_MULTIPLY * pSliceInLayer[iSliceIdx].iCountMbNumInSlice, pSliceInLayer[iSliceIdx].uiSliceConsumeTime); MT_TRACE_LOG (NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), uiSliceConsumeTime[%d]= %d us, slice_run= %d", iSliceIdx, pSliceInLayer[iSliceIdx].uiSliceConsumeTime, pSliceInLayer[iSliceIdx].iCountMbNumInSlice); iSumAv += iAvI[iSliceIdx]; ++ iSliceIdx; } while (-- iSliceIdx >= 0) { pSliceInLayer[iSliceIdx].iSliceComplexRatio = WELS_DIV_ROUND (INT_MULTIPLY * iAvI[iSliceIdx], iSumAv); } }
void RcInitVGop (sWelsEncCtx* pEncCtx) { const int32_t kiDid = pEncCtx->uiDependencyId; SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid]; SRCTemporal* pTOverRc = pWelsSvcRc->pTemporalOverRc; const int32_t kiHighestTid = pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId; pWelsSvcRc->iRemainingBits = WELS_DIV_ROUND (VGOP_SIZE * pWelsSvcRc->iBitsPerFrame, INT_MULTIPLY); pWelsSvcRc->iRemainingWeights = pWelsSvcRc->iGopNumberInVGop * WEIGHT_MULTIPLY; pWelsSvcRc->iFrameCodedInVGop = 0; pWelsSvcRc->iGopIndexInVGop = 0; for (int32_t i = 0; i <= kiHighestTid; ++ i) pTOverRc[i].iGopBitsDq = 0; pWelsSvcRc->iSkipFrameInVGop = 0; }
void RcDecideTargetBits (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SRCTemporal* pTOverRc = &pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId]; pWelsSvcRc->iCurrentBitsLevel = BITS_NORMAL; //allocate bits if (pEncCtx->eSliceType == I_SLICE) { pWelsSvcRc->iTargetBits = WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame * IDR_BITRATE_RATIO, INT_MULTIPLY); } else { pWelsSvcRc->iTargetBits = (int32_t) ((int64_t)pWelsSvcRc->iRemainingBits * pTOverRc->iTlayerWeight / pWelsSvcRc->iRemainingWeights); if ((pWelsSvcRc->iTargetBits <= 0) && (pEncCtx->pSvcParam->iRCMode == RC_LOW_BW_MODE)) { pWelsSvcRc->iCurrentBitsLevel = BITS_EXCEEDED; } else if ((pWelsSvcRc->iTargetBits <= pTOverRc->iMinBitsTl) && (pEncCtx->pSvcParam->iRCMode == RC_LOW_BW_MODE)) { pWelsSvcRc->iCurrentBitsLevel = BITS_LIMITED; } pWelsSvcRc->iTargetBits = WELS_CLIP3 (pWelsSvcRc->iTargetBits, pTOverRc->iMinBitsTl, pTOverRc->iMaxBitsTl); } pWelsSvcRc->iRemainingWeights -= pTOverRc->iTlayerWeight; }
void RcDecideTargetBits (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; SRCTemporal* pTOverRc = &pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId]; pWelsSvcRc->iCurrentBitsLevel = BITS_NORMAL; //allocate bits if (pEncCtx->eSliceType == I_SLICE) { pWelsSvcRc->iTargetBits = WELS_DIV_ROUND (pWelsSvcRc->iBitsPerFrame * IDR_BITRATE_RATIO, INT_MULTIPLY); } else { if (pWelsSvcRc->iRemainingWeights > pTOverRc->iTlayerWeight) pWelsSvcRc->iTargetBits = (int32_t) ((int64_t)pWelsSvcRc->iRemainingBits * pTOverRc->iTlayerWeight / pWelsSvcRc->iRemainingWeights); else //this case should be not hit. needs to more test case to verify this pWelsSvcRc->iTargetBits = pWelsSvcRc->iRemainingBits; if ((pWelsSvcRc->iTargetBits <= 0) && ((pEncCtx->pSvcParam->iRCMode == RC_BITRATE_MODE) && (pEncCtx->pSvcParam->bEnableFrameSkip == false))) { pWelsSvcRc->iCurrentBitsLevel = BITS_EXCEEDED; } pWelsSvcRc->iTargetBits = WELS_CLIP3 (pWelsSvcRc->iTargetBits, pTOverRc->iMinBitsTl, pTOverRc->iMaxBitsTl); } pWelsSvcRc->iRemainingWeights -= pTOverRc->iTlayerWeight; }
void DynamicAdjustSlicing (sWelsEncCtx* pCtx, SDqLayer* pCurDqLayer, void* pComplexRatio, int32_t iCurDid) { SSliceCtx* pSliceCtx = pCurDqLayer->pSliceEncCtx; const int32_t kiCountSliceNum = pSliceCtx->iSliceNumInFrame; const int32_t kiCountNumMb = pSliceCtx->iMbNumInFrame; int32_t iMinimalMbNum = pSliceCtx->iMbWidth; // in theory we need only 1 SMB, here let it as one SMB row required int32_t iMaximalMbNum = 0; // dynamically assign later int32_t* pSliceComplexRatio = (int32_t*)pComplexRatio; int32_t iMbNumLeft = kiCountNumMb; int32_t iRunLen[MAX_THREADS_NUM] = {0}; int32_t iSliceIdx = 0; int32_t iNumMbInEachGom = 0; SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[iCurDid]; if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) { iNumMbInEachGom = pWelsSvcRc->iNumberMbGom; if (iNumMbInEachGom <= 0) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d", iNumMbInEachGom, iCurDid, kiCountNumMb); return; } // do not adjust in case no extra iNumMbInEachGom based left for slicing adjustment, // extra MB of non integrated GOM assigned at the last pSlice in default, keep up on early initial result. if (iNumMbInEachGom * kiCountSliceNum >= kiCountNumMb) { return; } iMinimalMbNum = iNumMbInEachGom; } if (kiCountSliceNum < 2 || (kiCountSliceNum & 0x01)) // we need suppose uiSliceNum is even for multiple threading return; iMaximalMbNum = kiCountNumMb - (kiCountSliceNum - 1) * iMinimalMbNum; WelsEmms(); MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iDid= %d, iCountNumMb= %d", iCurDid, kiCountNumMb); iSliceIdx = 0; while (iSliceIdx + 1 < kiCountSliceNum) { int32_t iNumMbAssigning = WELS_DIV_ROUND (kiCountNumMb * pSliceComplexRatio[iSliceIdx], INT_MULTIPLY); // GOM boundary aligned if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) { iNumMbAssigning = iNumMbAssigning / iNumMbInEachGom * iNumMbInEachGom; } // make sure one GOM at least in each pSlice for safe if (iNumMbAssigning < iMinimalMbNum) iNumMbAssigning = iMinimalMbNum; else if (iNumMbAssigning > iMaximalMbNum) iNumMbAssigning = iMaximalMbNum; assert (iNumMbAssigning > 0); iMbNumLeft -= iNumMbAssigning; if (iMbNumLeft <= 0) { // error due to we can not support slice_skip now yet, do not adjust this time assert (0); return; } iRunLen[iSliceIdx] = iNumMbAssigning; MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), uiSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d", iSliceIdx, pSliceComplexRatio[iSliceIdx] * 1.0f / INT_MULTIPLY, pSliceCtx->pCountMbNumInSlice[iSliceIdx], iNumMbAssigning); ++ iSliceIdx; iMaximalMbNum = iMbNumLeft - (kiCountSliceNum - iSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts } iRunLen[iSliceIdx] = iMbNumLeft; MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d", iSliceIdx, pSliceComplexRatio[iSliceIdx] * 1.0f / INT_MULTIPLY, pSliceCtx->pCountMbNumInSlice[iSliceIdx], iMbNumLeft); if (DynamicAdjustSlicePEncCtxAll (pSliceCtx, iRunLen) == 0) { const int32_t kiThreadNum = pCtx->pSvcParam->iCountThreadsNum; int32_t iThreadIdx = 0; do { WelsEventSignal (&pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx]); WelsEventSignal (&pCtx->pSliceThreading->pThreadMasterEvent[iThreadIdx]); ++ iThreadIdx; } while (iThreadIdx < kiThreadNum); WelsMultipleEventsWaitAllBlocking (kiThreadNum, &pCtx->pSliceThreading->pFinUpdateMbListEvent[0]); } }
void RcCalculatePictureQp (sWelsEncCtx* pEncCtx) { SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; int32_t iTl = pEncCtx->uiTemporalId; SRCTemporal* pTOverRc = &pWelsSvcRc->pTemporalOverRc[iTl]; int32_t iLumaQp = 0; if (0 == pTOverRc->iPFrameNum) { iLumaQp = pWelsSvcRc->iInitialQp; } else if (pWelsSvcRc->iCurrentBitsLevel == BITS_EXCEEDED) { iLumaQp = MAX_LOW_BR_QP; //limit QP int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1; if (iLastIdxCodecInVGop < 0) iLastIdxCodecInVGop += VGOP_SIZE; int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop]; int32_t iDeltaQpTemporal = iTl - iTlLast; if (0 == iTlLast && iTl > 0) iDeltaQpTemporal += 3; else if (0 == iTl && iTlLast > 0) iDeltaQpTemporal -= 3; iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iLastCalculatedQScale - pWelsSvcRc->iFrameDeltaQpLower + iDeltaQpTemporal, pWelsSvcRc->iLastCalculatedQScale + pWelsSvcRc->iFrameDeltaQpUpper + iDeltaQpTemporal); iLumaQp = WELS_CLIP3 (iLumaQp, GOM_MIN_QP_MODE, MAX_LOW_BR_QP); pWelsSvcRc->iQStep = RcConvertQp2QStep (iLumaQp); pWelsSvcRc->iLastCalculatedQScale = iLumaQp; if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) { iLumaQp = WELS_CLIP3 ((iLumaQp * INT_MULTIPLY - pEncCtx->pVaa->sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp) / INT_MULTIPLY, GOM_MIN_QP_MODE, MAX_LOW_BR_QP); } pEncCtx->iGlobalQp = iLumaQp; return; } else { int64_t iCmplxRatio = WELS_DIV_ROUND64 (pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity * INT_MULTIPLY, pTOverRc->iFrameCmplxMean); iCmplxRatio = WELS_CLIP3 (iCmplxRatio, INT_MULTIPLY - FRAME_CMPLX_RATIO_RANGE, INT_MULTIPLY + FRAME_CMPLX_RATIO_RANGE); pWelsSvcRc->iQStep = WELS_DIV_ROUND ((pTOverRc->iLinearCmplx * iCmplxRatio), (pWelsSvcRc->iTargetBits * INT_MULTIPLY)); iLumaQp = RcConvertQStep2Qp (pWelsSvcRc->iQStep); //limit QP int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1; if (iLastIdxCodecInVGop < 0) iLastIdxCodecInVGop += VGOP_SIZE; int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop]; int32_t iDeltaQpTemporal = iTl - iTlLast; if (0 == iTlLast && iTl > 0) iDeltaQpTemporal += 3; else if (0 == iTl && iTlLast > 0) iDeltaQpTemporal -= 3; iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iLastCalculatedQScale - pWelsSvcRc->iFrameDeltaQpLower + iDeltaQpTemporal, pWelsSvcRc->iLastCalculatedQScale + pWelsSvcRc->iFrameDeltaQpUpper + iDeltaQpTemporal); } iLumaQp = WELS_CLIP3 (iLumaQp, GOM_MIN_QP_MODE, GOM_MAX_QP_MODE); pWelsSvcRc->iQStep = RcConvertQp2QStep (iLumaQp); pWelsSvcRc->iLastCalculatedQScale = iLumaQp; #ifndef _NOT_USE_AQ_FOR_TEST_ if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) { iLumaQp = WELS_DIV_ROUND (iLumaQp * INT_MULTIPLY - pEncCtx->pVaa->sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp, INT_MULTIPLY); if (pEncCtx->pSvcParam->iRCMode != RC_LOW_BW_MODE) iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp); } #endif pEncCtx->iGlobalQp = iLumaQp; }