예제 #1
0
void RcTraceVGopBitrate (sWelsEncCtx* pEncCtx) {
  const int32_t kiDid				= pEncCtx->uiDependencyId;
  SWelsSvcRc* pWelsSvcRc			= &pEncCtx->pWelsSvcRc[kiDid];

  if (pWelsSvcRc->iFrameCodedInVGop) {
    const int32_t kiHighestTid	= pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId;
    SRCTemporal* pTOverRc			= pWelsSvcRc->pTemporalOverRc;
    int32_t iVGopBitrate = 0;
    int32_t	iTotalBits = pWelsSvcRc->iPaddingBitrateStat;
    int32_t iTid = 0;
    while (iTid <= kiHighestTid) {
      iTotalBits += pTOverRc[iTid].iGopBitsDq;
      ++ iTid;
    }
    int32_t iFrameInVGop = pWelsSvcRc->iFrameCodedInVGop + pWelsSvcRc->iSkipFrameInVGop;
    if (0 != iFrameInVGop)
      iVGopBitrate = WELS_ROUND(iTotalBits / iFrameInVGop * pWelsSvcRc->fFrameRate);
#ifdef _TEST_TEMP_Rc_
    fprintf (fp_vgop, "%d\n", WELS_ROUND((double)iTotalBits / iFrameInVGop));
#endif
    WelsLog (pEncCtx, WELS_LOG_INFO, "[Rc] VGOPbitrate%d: %d \n", kiDid, iVGopBitrate);
    if (iTotalBits > 0) {
      iTid = 0;
      while (iTid <= kiHighestTid) {
        WelsLog (pEncCtx, WELS_LOG_INFO, "T%d=%8.3f \n", iTid, (double) (pTOverRc[iTid].iGopBitsDq / iTotalBits));
        ++ iTid;
      }
    }
  }
}
예제 #2
0
void   RcVBufferCalculationSkip (sWelsEncCtx* pEncCtx) {
  SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCTemporal* pTOverRc		= pWelsSvcRc->pTemporalOverRc;
  const int32_t kiOutputBits = WELS_ROUND(pWelsSvcRc->dBitsPerFrame);
  //condition 1: whole pBuffer fullness
  pWelsSvcRc->iBufferFullnessSkip += (pWelsSvcRc->iFrameDqBits - kiOutputBits);
  //condition 2: VGOP bits constraint
  const int32_t kiVGopBits = WELS_ROUND(pWelsSvcRc->dBitsPerFrame * VGOP_SIZE);
  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_ROUND(pWelsSvcRc->dBitsPerFrame);
    pWelsSvcRc->iSkipFrameNum++;
    pWelsSvcRc->iSkipFrameInVGop++;
  }
}
예제 #3
0
void RcVBufferCalculationPadding (sWelsEncCtx* pEncCtx) {
  SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  const int32_t kiOutputBits = WELS_ROUND(pWelsSvcRc->dBitsPerFrame);
  const int32_t kiBufferThreshold = WELS_ROUND(PADDING_THRESHOLD * (-pWelsSvcRc->iBufferSizePadding));

  pWelsSvcRc->iBufferFullnessPadding += (pWelsSvcRc->iFrameDqBits - kiOutputBits);

  if (pWelsSvcRc->iBufferFullnessPadding < kiBufferThreshold) {
    pWelsSvcRc->iPaddingSize = -pWelsSvcRc->iBufferFullnessPadding;
    pWelsSvcRc->iPaddingSize >>= 3;	// /8
    pWelsSvcRc->iBufferFullnessPadding = 0;
  } else
예제 #4
0
void RcCalculateIdrQp (sWelsEncCtx* pEncCtx) {
  SWelsSvcRc* pWelsSvcRc			= &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  //obtain the idr qp using previous idr complexity
  if (pWelsSvcRc->iNumberMbFrame != pWelsSvcRc->iIntraMbCount) {
    pWelsSvcRc->iIntraComplexity = WELS_ROUND((double)pWelsSvcRc->iIntraComplexity * pWelsSvcRc->iNumberMbFrame /
                                   pWelsSvcRc->iIntraMbCount);
  }
  pWelsSvcRc->iInitialQp = WELS_ROUND(RcConvertQStep2Qp ((double)pWelsSvcRc->iIntraComplexity / pWelsSvcRc->iTargetBits));
  pWelsSvcRc->iInitialQp = WELS_ROUND(WELS_CLIP3 (pWelsSvcRc->iInitialQp, MIN_IDR_QP, MAX_IDR_QP));
  pEncCtx->iGlobalQp = pWelsSvcRc->iInitialQp;
  pWelsSvcRc->dQStep = RcConvertQp2QStep (pEncCtx->iGlobalQp);
  pWelsSvcRc->iLastCalculatedQScale = pEncCtx->iGlobalQp;
}
예제 #5
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_ROUND(pWelsSvcRc->dBitsPerFrame * IDR_BITRATE_RATIO);
  } else {
    pWelsSvcRc->iTargetBits = WELS_ROUND(pWelsSvcRc->iRemainingBits * pTOverRc->dTlayerWeight /
                                         pWelsSvcRc->dRemainingWeights);
    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->dRemainingWeights -= pTOverRc->dTlayerWeight;
}
예제 #6
0
void RcUpdateBitrateFps (sWelsEncCtx* pEncCtx) {
  SWelsSvcRc* pWelsSvcRc	= &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCTemporal* pTOverRc		= pWelsSvcRc->pTemporalOverRc;
  SDLayerParam* pDLayerParam     = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
  const int32_t kiGopSize	= (1 << pDLayerParam->iDecompositionStages);
  const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId;
  double input_dBitsPerFrame = pDLayerParam->iSpatialBitrate / pDLayerParam->fInputFrameRate;
  const int32_t kiGopBits	= WELS_ROUND (input_dBitsPerFrame * kiGopSize);
  int32_t i;

  pWelsSvcRc->iBitRate   = pDLayerParam->iSpatialBitrate;
  pWelsSvcRc->fFrameRate = pDLayerParam->fInputFrameRate;

  double dTargetVaryRange = FRAME_iTargetBits_VARY_RANGE * (1.0 - pWelsSvcRc->dRcVaryRatio);
  double dMinBitsRatio = 1.0 - dTargetVaryRange;
  double dMaxBitsRatio = 1.0 + FRAME_iTargetBits_VARY_RANGE;//dTargetVaryRange;

  for (i = 0; i <= kiHighestTid; i++) {
    const double kdConstraitBits = kiGopBits * pTOverRc[i].dTlayerWeight;
    pTOverRc[i].iMinBitsTl = WELS_ROUND(kdConstraitBits * dMinBitsRatio);
    pTOverRc[i].iMaxBitsTl = WELS_ROUND(kdConstraitBits * dMaxBitsRatio);
  }
  //When bitrate is changed, pBuffer size should be updated
  pWelsSvcRc->iBufferSizeSkip = WELS_ROUND(pWelsSvcRc->iBitRate * pWelsSvcRc->dSkipBufferRatio);
  pWelsSvcRc->iBufferSizePadding = WELS_ROUND(pWelsSvcRc->iBitRate * PADDING_BUFFER_RATIO);

  //change remaining bits
  if (pWelsSvcRc->dBitsPerFrame > 0.1)
    pWelsSvcRc->iRemainingBits = WELS_ROUND(pWelsSvcRc->iRemainingBits * input_dBitsPerFrame / pWelsSvcRc->dBitsPerFrame);
  pWelsSvcRc->dBitsPerFrame = input_dBitsPerFrame;
}
예제 #7
0
void WelsRcFrameDelayJudge (void* pCtx) {
  sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
  SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SSpatialLayerConfig* pDLayerParam     = &pEncCtx->pSvcParam->sSpatialLayers[pEncCtx->uiDependencyId];
  SSpatialLayerInternal* pDLayerParamInternal     = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];

  int32_t iSentBits = WELS_ROUND (pDLayerParam->iSpatialBitrate / pDLayerParamInternal->fOutputFrameRate);

  pWelsSvcRc->bSkipFlag = false;
  if (pWelsSvcRc->iBufferFullnessSkip > pWelsSvcRc->iBufferSizeSkip) {
    pWelsSvcRc->bSkipFlag = true;
    pWelsSvcRc->iBufferFullnessSkip -= iSentBits;
    pWelsSvcRc->iBufferFullnessSkip = WELS_MAX (pWelsSvcRc->iBufferFullnessSkip, 0);
  }
}
예제 #8
0
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_ROUND(VGOP_SIZE * pWelsSvcRc->dBitsPerFrame);
  pWelsSvcRc->dRemainingWeights = pWelsSvcRc->iGopNumberInVGop;

  pWelsSvcRc->iFrameCodedInVGop = 0;
  pWelsSvcRc->iGopIndexInVGop = 0;

  for (int32_t i = 0; i <= kiHighestTid; ++ i)
    pTOverRc[i].iGopBitsDq = 0;
  pWelsSvcRc->iSkipFrameInVGop = 0;
}
예제 #9
0
void RcInitSliceInformation (sWelsEncCtx* pEncCtx) {
  SSliceCtx* pCurSliceCtx	= pEncCtx->pCurDqLayer->pSliceEncCtx;
  SWelsSvcRc* pWelsSvcRc			= &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCSlicing* pSOverRc				= &pWelsSvcRc->pSlicingOverRc[0];
  const int32_t kiSliceNum			= pCurSliceCtx->iSliceNumInFrame;
  const double kdBitsPerMb		= (double)pWelsSvcRc->iTargetBits / 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_ROUND(kdBitsPerMb * pCurSliceCtx->pCountMbNumInSlice[i]);
    pSOverRc->iFrameBitsSlice	= 0;
    pSOverRc->iGomBitsSlice	= 0;
    ++ pSOverRc;
  }
}
예제 #10
0
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;
}
예제 #11
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->dQStep = RcConvertQp2QStep (iLumaQp);
    pWelsSvcRc->iLastCalculatedQScale = iLumaQp;

    if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) {
      iLumaQp = WELS_ROUND(iLumaQp - pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp);
    }

    pEncCtx->iGlobalQp = iLumaQp;

    return;
  } else {
    double dCmplxRatio = (double)pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity / pTOverRc->iFrameCmplxMean;
    dCmplxRatio = WELS_CLIP3 (dCmplxRatio, 1.0 - FRAME_CMPLX_RATIO_RANGE, 1.0 + FRAME_CMPLX_RATIO_RANGE);

    pWelsSvcRc->dQStep = pTOverRc->dLinearCmplx * dCmplxRatio / pWelsSvcRc->iTargetBits;
    iLumaQp = WELS_ROUND(RcConvertQStep2Qp (pWelsSvcRc->dQStep));

    //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->dQStep = RcConvertQp2QStep (iLumaQp);
  pWelsSvcRc->iLastCalculatedQScale = iLumaQp;
#ifndef _NOT_USE_AQ_FOR_TEST_
  if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) {

    iLumaQp = WELS_ROUND(iLumaQp - pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp);

    if (pEncCtx->pSvcParam->iRCMode != RC_LOW_BW_MODE)
      iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp);

  }
#endif
  pEncCtx->iGlobalQp = iLumaQp;
}
예제 #12
0
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
  float* pSliceComplexRatio	= (float*)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, WELS_LOG_ERROR,
               "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d\n", 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\n", iCurDid, kiCountNumMb);

  iSliceIdx	= 0;
  while (iSliceIdx + 1 < kiCountSliceNum) {
    int32_t iNumMbAssigning = WELS_ROUND(kiCountNumMb * pSliceComplexRatio[iSliceIdx]);

    // GOM boundary aligned
    if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) {
      iNumMbAssigning = WELS_ROUND (1.0f * 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\n",
                  iSliceIdx, pSliceComplexRatio[iSliceIdx], 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\n",
                iSliceIdx, pSliceComplexRatio[iSliceIdx], 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]);
  }
}