shithub: openh264

Download patch

ref: b940e2cdf8937a59db9ef606b89134ebc2eb3fef
parent: 737548fe0689e27375459db9c05aaf350bc60806
parent: d4f979c495334291169f637355c2484c14ee7e69
author: HaiboZhu <haibozhu@cisco.com>
date: Mon Jan 11 09:05:55 EST 2016

Merge pull request #2325 from ruil2/trace1

separate each layer trace output

--- a/codec/encoder/core/inc/encoder_context.h
+++ b/codec/encoder/core/inc/encoder_context.h
@@ -225,12 +225,12 @@
 
   //related to Statistics
   int64_t            uiStartTimestamp;
-  SEncoderStatistics sEncoderStatistics;
+  SEncoderStatistics sEncoderStatistics[MAX_DEPENDENCY_LAYER];
   int32_t            iStatisticsLogInterval;
   int64_t            iLastStatisticsLogTs;
-  int64_t            iTotalEncodedBytes;
-  int64_t            iLastStatisticsBytes;
-  int64_t            iLastStatisticsFrameCount;
+  int64_t            iTotalEncodedBytes[MAX_DEPENDENCY_LAYER];
+  int64_t            iLastStatisticsBytes[MAX_DEPENDENCY_LAYER];
+  int64_t            iLastStatisticsFrameCount[MAX_DEPENDENCY_LAYER];
 
   int32_t iEncoderError;
   WELS_MUTEX mutexEncoderError;
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -3412,7 +3412,7 @@
   pCtx->bCheckWindowStatusRefreshFlag = false;
 
   WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR at InputFrameCount=%d\n",
-           pCtx->sEncoderStatistics.uiInputFrameCount);
+           pCtx->sEncoderStatistics[0].uiInputFrameCount);
   return 0;
 }
 
@@ -3435,7 +3435,7 @@
   pLayerBsInfo->uiQualityId   = 0;
   pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
   pLayerBsInfo->iNalCount     = iCountNal;
-
+  pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
   //pCtx->eLastNalPriority      = NRI_PRI_HIGHEST;
   pFbi->iLayerNum             = 1;
   pFbi->eFrameType            = videoFrameTypeInvalid;
@@ -3473,7 +3473,7 @@
   pLayerBsInfo->uiQualityId     = 0;
   pLayerBsInfo->uiLayerType     = NON_VIDEO_CODING_LAYER;
   pLayerBsInfo->iNalCount       = iCountNal;
-
+  pLayerBsInfo->eFrameType      = videoFrameTypeIDR;
   //point to next pLayerBsInfo
   ++ pLayerBsInfo;
   ++ pCtx->pOut->iLayerBsIndex;
@@ -3514,7 +3514,7 @@
     pLayerBsInfo->uiQualityId   = 0;
     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
     pLayerBsInfo->iNalCount     = iCountNal;
-
+    pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
     //point to next pLayerBsInfo
     ++ pLayerBsInfo;
     ++ pCtx->pOut->iLayerBsIndex;
@@ -3547,7 +3547,7 @@
     pLayerBsInfo->uiQualityId   = 0;
     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
     pLayerBsInfo->iNalCount     = iCountNal;
-
+    pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
     //point to next pLayerBsInfo
     ++ pLayerBsInfo;
     ++ pCtx->pOut->iLayerBsIndex;
@@ -3595,7 +3595,7 @@
     pLayerBsInfo->uiQualityId   = 0;
     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
     pLayerBsInfo->iNalCount     = iCountNal;
-
+    pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
     //point to next pLayerBsInfo
     ++ pLayerBsInfo;
     ++ pCtx->pOut->iLayerBsIndex;
@@ -3630,7 +3630,7 @@
     pLayerBsInfo->uiQualityId   = 0;
     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
     pLayerBsInfo->iNalCount     = iCountNal;
-
+    pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
     //point to next pLayerBsInfo
     ++ pLayerBsInfo;
     ++ pCtx->pOut->iLayerBsIndex;
@@ -3745,6 +3745,9 @@
   pCtx->bCurFrameMarkedAsSceneLtr = false;
   pFbi->iLayerNum = 0; // for initialization
   pFbi->uiTimeStamp = pSrcPic->uiTimeStamp;
+  for (int32_t iNalIdx = 0; iNalIdx < MAX_LAYER_NUM_OF_FRAME; iNalIdx++) {
+    pFbi->sLayerInfo[iNalIdx].eFrameType = videoFrameTypeSkip;
+  }
   // perform csc/denoise/downsample/padding, generate spatial layers
   iSpatialNum = pCtx->pVpp->BuildSpatialPicList (pCtx, pSrcPic);
   if (pCtx->pFuncList->pfRc.pfWelsUpdateMaxBrWindowStatus) {
@@ -3953,6 +3956,7 @@
       pLayerBsInfo->uiTemporalId        = iCurTid;
       pLayerBsInfo->uiQualityId         = 0;
       pLayerBsInfo->iNalCount           = ++ iNalIdxInLayer;
+      pLayerBsInfo->eFrameType          = eFrameType;
     }
     // for dynamic slicing single threading..
     else if ((SM_SIZELIMITED_SLICE == pParam->sSliceArgument.uiSliceMode) && (pSvcParam->iMultipleThreadIdc <= 1)) {
@@ -3959,6 +3963,7 @@
       const int32_t kiLastMbInFrame = pCtx->pCurDqLayer->sSliceEncCtx.iMbNumInFrame;
       pCtx->iEncoderError = WelsCodeOnePicPartition (pCtx, pFbi, pLayerBsInfo, &iNalIdxInLayer, &iLayerSize, 0,
                             kiLastMbInFrame, 0);
+      pLayerBsInfo->eFrameType = eFrameType;
       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
     } else {
       //other multi-slice uiSliceMode
@@ -3984,7 +3989,7 @@
         pLayerBsInfo->uiTemporalId  = pCtx->uiTemporalId;
         pLayerBsInfo->uiQualityId   = 0;
         pLayerBsInfo->iNalCount     = 0;
-
+        pLayerBsInfo->eFrameType    = eFrameType;
         pCtx->pTaskManage->ExecuteTasks();
         if (pCtx->iEncoderError) {
           WelsLog (pLogCtx, WELS_LOG_ERROR,
@@ -4035,7 +4040,7 @@
         pLbi->uiTemporalId  = pCtx->uiTemporalId;
         pLbi->uiQualityId   = 0;
         pLbi->iNalCount     = 0;
-
+        pLbi->eFrameType = eFrameType;
         int32_t iIdx = 0;
         while (iIdx < kiPartitionCnt) {
           pCtx->pSliceThreading->pThreadPEncCtx[iIdx].pFrameBsInfo = pFbi;
@@ -4103,6 +4108,7 @@
         pLayerBsInfo->uiTemporalId      = iCurTid;
         pLayerBsInfo->uiQualityId       = 0;
         pLayerBsInfo->iNalCount         = iNalIdxInLayer;
+        pLayerBsInfo->eFrameType        = eFrameType;
       }
     }
 
@@ -4281,6 +4287,7 @@
       pLayerBsInfo->uiLayerType         = NON_VIDEO_CODING_LAYER;
       pLayerBsInfo->iNalCount           = 1;
       pLayerBsInfo->pNalLengthInByte[0] = iPaddingNalSize;
+      pLayerBsInfo->eFrameType          = eFrameType;
       ++ pLayerBsInfo;
       ++ pCtx->pOut->iLayerBsIndex;
       pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
@@ -4314,6 +4321,7 @@
                "WelsEncoderEncodeExt(), Logic Error Found in Preprocess updating. ForceCodingIDR!");
       //the above is to set the next frame IDR
       pFbi->eFrameType = eFrameType;
+      pLayerBsInfo->eFrameType = eFrameType;
       return ENC_RETURN_CORRECTED;
     }
 
@@ -4326,9 +4334,10 @@
   if (ENC_RETURN_CORRECTED == pCtx->iEncoderError) {
     pCtx->pVpp->UpdateSpatialPictures (pCtx, pSvcParam, iCurTid, (pSpatialIndexMap + iSpatialIdx)->iDid);
     ForceCodingIDR (pCtx);
-    WelsLog (pLogCtx, WELS_LOG_WARNING, "WelsEncoderEncodeExt(), Logic Error Found in temporal level. ForceCodingIDR!");
+    WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), Logic Error Found in temporal level. ForceCodingIDR!");
     //the above is to set the next frame IDR
     pFbi->eFrameType = eFrameType;
+    pLayerBsInfo->eFrameType = eFrameType;
     return ENC_RETURN_CORRECTED;
   }
 
@@ -4509,7 +4518,8 @@
     int32_t  iTmpPpsIdList[MAX_DQ_LAYER_NUM * MAX_PPS_COUNT];
     uint16_t uiTmpIdrPicId = (*ppCtx)->uiIdrPicId;//this is for LTR!
 
-    SEncoderStatistics sTempEncoderStatistics = (*ppCtx)->sEncoderStatistics;
+    SEncoderStatistics sTempEncoderStatistics[MAX_DEPENDENCY_LAYER];
+    memcpy (sTempEncoderStatistics, (*ppCtx)->sEncoderStatistics, sizeof (sTempEncoderStatistics));
 
     SExistingParasetList sExistingParasetList;
     SExistingParasetList* pExistingParasetList = NULL;
@@ -4568,8 +4578,7 @@
     (*ppCtx)->uiIdrPicId = uiTmpIdrPicId;
 
     //for sEncoderStatistics
-    (*ppCtx)->sEncoderStatistics = sTempEncoderStatistics;
-
+    memcpy ((*ppCtx)->sEncoderStatistics, sTempEncoderStatistics, sizeof (sTempEncoderStatistics));
     //load back the needed structure for eSpsPpsIdStrategy
     if ((CONSTANT_ID != iOldSpsPpsIdStrategy) && (CONSTANT_ID != pNewParam->eSpsPpsIdStrategy)) {
       memcpy ((*ppCtx)->sPSOVector.sParaSetOffsetVariable, sTmpPsoVariable,
@@ -4934,7 +4943,6 @@
   pLayerBsInfo->uiTemporalId    = pCtx->uiTemporalId;
   pLayerBsInfo->uiQualityId     = 0;
   pLayerBsInfo->iNalCount       = iNalIdxInLayer;
-
   return ENC_RETURN_SUCCESS;
 }
 } // namespace WelsEnc
--- a/codec/encoder/plus/inc/welsEncoderExt.h
+++ b/codec/encoder/plus/inc/welsEncoderExt.h
@@ -99,8 +99,8 @@
  private:
   int InitializeInternal (SWelsSvcCodingParam* argv);
   void TraceParamInfo(SEncParamExt *pParam);
-  void LogStatistics (const int64_t kiCurrentFrameTs);
-  void UpdateStatistics(const int64_t kiCurrentFrameTs, EVideoFrameType eFrameType,  const int32_t kiCurrentFrameSize, const int64_t kiCurrentFrameMs);
+  void LogStatistics (const int64_t kiCurrentFrameTs,int32_t iMaxDid);
+  void UpdateStatistics(const int64_t kiCurrentFrameTs, SFrameBSInfo* pBsInfo, const int64_t kiCurrentFrameMs);
 
   sWelsEncCtx*      m_pEncContext;
 
--- a/codec/encoder/plus/src/welsEncoderExt.cpp
+++ b/codec/encoder/plus/src/welsEncoderExt.cpp
@@ -412,7 +412,7 @@
     return cmUnknownReason;
   }
 
-  UpdateStatistics (pSrcPic->uiTimeStamp, pBsInfo->eFrameType, pBsInfo->iFrameSizeInBytes, kiCurrentFrameMs);
+  UpdateStatistics (pSrcPic->uiTimeStamp, pBsInfo, kiCurrentFrameMs);
 
   ///////////////////for test
 #ifdef OUTPUT_BIT_STREAM
@@ -481,7 +481,7 @@
 
   ForceCodingIDR (m_pEncContext);
 
-  m_pEncContext->sEncoderStatistics.uiIDRReqNum++;
+  m_pEncContext->sEncoderStatistics[0].uiIDRReqNum++;
 
   return 0;
 }
@@ -545,102 +545,125 @@
   }
 }
 
-void CWelsH264SVCEncoder::LogStatistics (const int64_t kiCurrentFrameTs) {
-  SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics);
-  WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
-           "EncoderStatistics: %dx%d, SpeedInMs: %f, fAverageFrameRate=%f, "
-           "LastFrameRate=%f, LatestBitRate=%d, LastFrameQP=%d, uiInputFrameCount=%d, uiSkippedFrameCount=%d, "
-           "uiResolutionChangeTimes=%d, uIDRReqNum=%d, uIDRSentNum=%d, uLTRSentNum=NA, iTotalEncodedBytes=%" PRId64
-           " at Ts = %" PRId64,
-           pStatistics->uiWidth, pStatistics->uiHeight,
-           pStatistics->fAverageFrameSpeedInMs, pStatistics->fAverageFrameRate,
-           pStatistics->fLatestFrameRate, pStatistics->uiBitRate, pStatistics->uiAverageFrameQP,
-           pStatistics->uiInputFrameCount, pStatistics->uiSkippedFrameCount,
-           pStatistics->uiResolutionChangeTimes, pStatistics->uiIDRReqNum, pStatistics->uiIDRSentNum,
-           m_pEncContext->iTotalEncodedBytes, kiCurrentFrameTs);
+void CWelsH264SVCEncoder::LogStatistics (const int64_t kiCurrentFrameTs, int32_t iMaxDid) {
+  for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) {
+    SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]);
+    WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
+             "EncoderStatistics: SpatialId = %d,%dx%d, SpeedInMs: %f, fAverageFrameRate=%f, "
+             "LastFrameRate=%f, LatestBitRate=%d, LastFrameQP=%d, uiInputFrameCount=%d, uiSkippedFrameCount=%d, "
+             "uiResolutionChangeTimes=%d, uIDRReqNum=%d, uIDRSentNum=%d, uLTRSentNum=NA, iTotalEncodedBytes=%" PRId64
+             " at Ts = %" PRId64,
+             iDid, pStatistics->uiWidth, pStatistics->uiHeight,
+             pStatistics->fAverageFrameSpeedInMs, pStatistics->fAverageFrameRate,
+             pStatistics->fLatestFrameRate, pStatistics->uiBitRate, pStatistics->uiAverageFrameQP,
+             pStatistics->uiInputFrameCount, pStatistics->uiSkippedFrameCount,
+             pStatistics->uiResolutionChangeTimes, pStatistics->uiIDRReqNum, pStatistics->uiIDRSentNum,
+             m_pEncContext->iTotalEncodedBytes[iDid], kiCurrentFrameTs);
+  }
 }
 
-void CWelsH264SVCEncoder::UpdateStatistics (const int64_t kiCurrentFrameTs, EVideoFrameType eFrameType,
-    const int32_t kiCurrentFrameSize, const int64_t kiCurrentFrameMs) {
-  SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics);
+void CWelsH264SVCEncoder::UpdateStatistics (const int64_t kiCurrentFrameTs, SFrameBSInfo* pBsInfo,
+    const int64_t kiCurrentFrameMs) {
 
   int32_t iMaxDid = m_pEncContext->pSvcParam->iSpatialLayerNum - 1;
-  if ((0 != pStatistics->uiWidth && 0 != pStatistics->uiHeight)
-      && (pStatistics->uiWidth != (unsigned int) m_pEncContext->pSvcParam->sDependencyLayers[iMaxDid].iActualWidth
-          || pStatistics->uiHeight != (unsigned int) m_pEncContext->pSvcParam->sDependencyLayers[iMaxDid].iActualHeight)) {
-    pStatistics->uiResolutionChangeTimes ++;
-  }
-  pStatistics->uiWidth = m_pEncContext->pSvcParam->sDependencyLayers[iMaxDid].iActualWidth;
-  pStatistics->uiHeight = m_pEncContext->pSvcParam->sDependencyLayers[iMaxDid].iActualHeight;
+  SLayerBSInfo*  pLayerInfo = &pBsInfo->sLayerInfo[0];
+  for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) {
+    EVideoFrameType eFrameType = videoFrameTypeInvalid;
+    int32_t kiCurrentFrameSize = 0;
+    if (pBsInfo->eFrameType == videoFrameTypeSkip) {
+      eFrameType = videoFrameTypeSkip;
+    } else {
+      for (int32_t iLayerNum = 0; iLayerNum < pBsInfo->iLayerNum; iLayerNum++) {
+        pLayerInfo = &pBsInfo->sLayerInfo[iLayerNum];
+        if ((pLayerInfo->uiLayerType == VIDEO_CODING_LAYER) && (pLayerInfo->uiSpatialId == iDid)) {
+          eFrameType = pLayerInfo->eFrameType;
+          for (int32_t iNalIdx = 0; iNalIdx < pLayerInfo->iNalCount; iNalIdx++) {
+             kiCurrentFrameSize += pLayerInfo->pNalLengthInByte[iNalIdx];
+          }
+        }
+      }
 
-  const bool kbCurrentFrameSkipped = (videoFrameTypeSkip == eFrameType);
-  pStatistics->uiInputFrameCount ++;
-  pStatistics->uiSkippedFrameCount += (kbCurrentFrameSkipped ? 1 : 0);
-  int32_t iProcessedFrameCount = pStatistics->uiInputFrameCount - pStatistics->uiSkippedFrameCount;
-  if (!kbCurrentFrameSkipped && iProcessedFrameCount != 0) {
-    pStatistics->fAverageFrameSpeedInMs += (kiCurrentFrameMs - pStatistics->fAverageFrameSpeedInMs) / iProcessedFrameCount;
-  }
+    }
+    SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]);
 
-  // rate control related
-  if (0 != m_pEncContext->uiStartTimestamp) {
-    if (kiCurrentFrameTs > m_pEncContext->uiStartTimestamp + 800) {
-      pStatistics->fAverageFrameRate = (static_cast<float> (pStatistics->uiInputFrameCount) * 1000 /
-                                        (kiCurrentFrameTs - m_pEncContext->uiStartTimestamp));
+
+    if ((0 != pStatistics->uiWidth && 0 != pStatistics->uiHeight)
+        && (pStatistics->uiWidth != (unsigned int) m_pEncContext->pSvcParam->sDependencyLayers[iDid].iActualWidth
+            || pStatistics->uiHeight != (unsigned int) m_pEncContext->pSvcParam->sDependencyLayers[iDid].iActualHeight)) {
+      pStatistics->uiResolutionChangeTimes ++;
     }
-  } else {
-    m_pEncContext->uiStartTimestamp = kiCurrentFrameTs;
-  }
-  //pStatistics->fLatestFrameRate = m_pEncContext->pWelsSvcRc->fLatestFrameRate; //TODO: finish the calculation in RC
-  //pStatistics->uiBitRate = m_pEncContext->pWelsSvcRc->iActualBitRate; //TODO: finish the calculation in RC
-  pStatistics->uiAverageFrameQP = m_pEncContext->pWelsSvcRc->iAverageFrameQp;
+    pStatistics->uiWidth = m_pEncContext->pSvcParam->sDependencyLayers[iDid].iActualWidth;
+    pStatistics->uiHeight = m_pEncContext->pSvcParam->sDependencyLayers[iDid].iActualHeight;
 
-  if (videoFrameTypeIDR == eFrameType || videoFrameTypeI == eFrameType) {
-    pStatistics->uiIDRSentNum ++;
-  }
-  if (m_pEncContext->pLtr->bLTRMarkingFlag) {
-    pStatistics->uiLTRSentNum ++;
-  }
+    const bool kbCurrentFrameSkipped = (videoFrameTypeSkip == eFrameType);
+    pStatistics->uiInputFrameCount ++;
+    pStatistics->uiSkippedFrameCount += (kbCurrentFrameSkipped ? 1 : 0);
+    int32_t iProcessedFrameCount = pStatistics->uiInputFrameCount - pStatistics->uiSkippedFrameCount;
+    if (!kbCurrentFrameSkipped && iProcessedFrameCount != 0) {
+      pStatistics->fAverageFrameSpeedInMs += (kiCurrentFrameMs - pStatistics->fAverageFrameSpeedInMs) / iProcessedFrameCount;
+    }
+    // rate control related
+    if (0 != m_pEncContext->uiStartTimestamp) {
+      if (kiCurrentFrameTs > m_pEncContext->uiStartTimestamp + 800) {
+        pStatistics->fAverageFrameRate = (static_cast<float> (pStatistics->uiInputFrameCount) * 1000 /
+                                          (kiCurrentFrameTs - m_pEncContext->uiStartTimestamp));
+      }
+    } else {
+      m_pEncContext->uiStartTimestamp = kiCurrentFrameTs;
+    }
+    //pStatistics->fLatestFrameRate = m_pEncContext->pWelsSvcRc->fLatestFrameRate; //TODO: finish the calculation in RC
+    //pStatistics->uiBitRate = m_pEncContext->pWelsSvcRc->iActualBitRate; //TODO: finish the calculation in RC
+    pStatistics->uiAverageFrameQP = m_pEncContext->pWelsSvcRc->iAverageFrameQp;
 
-  m_pEncContext->iTotalEncodedBytes += kiCurrentFrameSize;
+    if (videoFrameTypeIDR == eFrameType || videoFrameTypeI == eFrameType) {
+      pStatistics->uiIDRSentNum ++;
+    }
+    if (m_pEncContext->pLtr->bLTRMarkingFlag) {
+      pStatistics->uiLTRSentNum ++;
+    }
 
-  const int32_t kiDeltaFrames = static_cast<int32_t> (pStatistics->uiInputFrameCount -
-                                m_pEncContext->iLastStatisticsFrameCount);
-  if (kiDeltaFrames > (m_pEncContext->pSvcParam->fMaxFrameRate * 2)) {
-    const int64_t kiTimeDiff = kiCurrentFrameTs - pStatistics->iStatisticsTs;
-    if (kiTimeDiff) {
-      pStatistics->fLatestFrameRate = static_cast<float> ((pStatistics->uiInputFrameCount -
-                                      m_pEncContext->iLastStatisticsFrameCount) * 1000 /
-                                      kiTimeDiff);
-      pStatistics->uiBitRate = static_cast<unsigned int> ((m_pEncContext->iTotalEncodedBytes -
-                               m_pEncContext->iLastStatisticsBytes) * 8 * 1000 / kiTimeDiff);
+    m_pEncContext->iTotalEncodedBytes[iDid] += kiCurrentFrameSize;
 
-      if (WELS_ABS (pStatistics->fLatestFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) {
-        WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING,
-                 "Actual input fLatestFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), cur_Ts = %"
-                 PRId64 " start_Ts = %" PRId64,
-                 pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, kiCurrentFrameTs,
-                 static_cast<int64_t> (pStatistics->iStatisticsTs));
-      }
+    const int32_t kiDeltaFrames = static_cast<int32_t> (pStatistics->uiInputFrameCount -
+                                  m_pEncContext->iLastStatisticsFrameCount[iDid]);
+    if (kiDeltaFrames > (m_pEncContext->pSvcParam->fMaxFrameRate * 2)) {
+      const int64_t kiTimeDiff = kiCurrentFrameTs - pStatistics->iStatisticsTs;
+      if (kiTimeDiff) {
+        pStatistics->fLatestFrameRate = static_cast<float> ((pStatistics->uiInputFrameCount -
+                                        m_pEncContext->iLastStatisticsFrameCount[iDid]) * 1000 /
+                                        kiTimeDiff);
+        pStatistics->uiBitRate = static_cast<unsigned int> ((m_pEncContext->iTotalEncodedBytes[iDid] -
+                                 m_pEncContext->iLastStatisticsBytes[iDid]) * 8 * 1000 / kiTimeDiff);
 
-      if (m_pEncContext->pSvcParam->iRCMode == RC_QUALITY_MODE || m_pEncContext->pSvcParam->iRCMode == RC_BITRATE_MODE) {
-        if ((pStatistics->fLatestFrameRate > 0)
-            && WELS_ABS (m_pEncContext->pSvcParam->fMaxFrameRate - pStatistics->fLatestFrameRate) > 5) {
+        if (WELS_ABS (pStatistics->fLatestFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) {
           WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING,
-                   "Actual input framerate %f is different from framerate in setting %f, suggest to use other rate control modes",
-                   pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate);
+                   "Actual input fLatestFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), cur_Ts = %"
+                   PRId64 " start_Ts = %" PRId64,
+                   pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, kiCurrentFrameTs,
+                   static_cast<int64_t> (pStatistics->iStatisticsTs));
         }
+
+        if (m_pEncContext->pSvcParam->iRCMode == RC_QUALITY_MODE || m_pEncContext->pSvcParam->iRCMode == RC_BITRATE_MODE) {
+          if ((pStatistics->fLatestFrameRate > 0)
+              && WELS_ABS (m_pEncContext->pSvcParam->fMaxFrameRate - pStatistics->fLatestFrameRate) > 5) {
+            WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING,
+                     "Actual input framerate %f is different from framerate in setting %f, suggest to use other rate control modes",
+                     pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate);
+          }
+        }
       }
-    }
 
-    // update variables
-    pStatistics->iStatisticsTs = kiCurrentFrameTs;
-    m_pEncContext->iLastStatisticsBytes = m_pEncContext->iTotalEncodedBytes;
-    m_pEncContext->iLastStatisticsFrameCount = pStatistics->uiInputFrameCount;
+      // update variables
+      pStatistics->iStatisticsTs = kiCurrentFrameTs;
+      m_pEncContext->iLastStatisticsBytes[iDid] = m_pEncContext->iTotalEncodedBytes[iDid];
+      m_pEncContext->iLastStatisticsFrameCount[iDid] = pStatistics->uiInputFrameCount;
 
-    //TODO: the following statistics will be calculated and added later
-    //pStatistics->uiLTRSentNum
+      //TODO: the following statistics will be calculated and added later
+      //pStatistics->uiLTRSentNum
+    }
   }
   if (m_pEncContext->iStatisticsLogInterval > 0) {
+    SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[0]);
     const int64_t kiTimeDiff = kiCurrentFrameTs - m_pEncContext->iLastStatisticsLogTs;
     if ((kiTimeDiff > m_pEncContext->iStatisticsLogInterval) || (0 == pStatistics->uiInputFrameCount % 300)) {
       if (WELS_ABS (pStatistics->fAverageFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) {
@@ -650,7 +673,7 @@
                  pStatistics->fAverageFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, m_pEncContext->uiStartTimestamp);
       }
 
-      LogStatistics (kiCurrentFrameTs);
+      LogStatistics (kiCurrentFrameTs, iMaxDid);
       m_pEncContext->iLastStatisticsLogTs = kiCurrentFrameTs;
     }
   }
@@ -788,7 +811,7 @@
     //LogStatistics
     WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
              "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, LogStatisticsBeforeNewEncoding");
-    LogStatistics (m_pEncContext->iLastStatisticsLogTs);
+    LogStatistics (m_pEncContext->iLastStatisticsLogTs, sEncodingParam.iSpatialLayerNum - 1);
   }
   break;
   case ENCODER_OPTION_FRAME_RATE: { // Maximal input frame rate
@@ -1214,22 +1237,23 @@
   break;
   case ENCODER_OPTION_GET_STATISTICS: {
     SEncoderStatistics* pStatistics = (static_cast<SEncoderStatistics*> (pOption));
-    pStatistics->uiWidth = m_pEncContext->sEncoderStatistics.uiWidth;
-    pStatistics->uiHeight = m_pEncContext->sEncoderStatistics.uiHeight;
-    pStatistics->fAverageFrameSpeedInMs = m_pEncContext->sEncoderStatistics.fAverageFrameSpeedInMs;
+    SEncoderStatistics* pEncStatistics = &m_pEncContext->sEncoderStatistics[m_pEncContext->pSvcParam->iSpatialLayerNum - 1];
+    pStatistics->uiWidth = pEncStatistics->uiWidth;
+    pStatistics->uiHeight = pEncStatistics->uiHeight;
+    pStatistics->fAverageFrameSpeedInMs = pEncStatistics->fAverageFrameSpeedInMs;
 
     // rate control related
-    pStatistics->fAverageFrameRate = m_pEncContext->sEncoderStatistics.fAverageFrameRate;
-    pStatistics->fLatestFrameRate = m_pEncContext->sEncoderStatistics.fLatestFrameRate;
-    pStatistics->uiBitRate = m_pEncContext->sEncoderStatistics.uiBitRate;
+    pStatistics->fAverageFrameRate = pEncStatistics->fAverageFrameRate;
+    pStatistics->fLatestFrameRate = pEncStatistics->fLatestFrameRate;
+    pStatistics->uiBitRate = pEncStatistics->uiBitRate;
 
-    pStatistics->uiInputFrameCount = m_pEncContext->sEncoderStatistics.uiInputFrameCount;
-    pStatistics->uiSkippedFrameCount = m_pEncContext->sEncoderStatistics.uiSkippedFrameCount;
+    pStatistics->uiInputFrameCount = pEncStatistics->uiInputFrameCount;
+    pStatistics->uiSkippedFrameCount = pEncStatistics->uiSkippedFrameCount;
 
-    pStatistics->uiResolutionChangeTimes = m_pEncContext->sEncoderStatistics.uiResolutionChangeTimes;
-    pStatistics->uiIDRReqNum = m_pEncContext->sEncoderStatistics.uiIDRReqNum;
-    pStatistics->uiIDRSentNum = m_pEncContext->sEncoderStatistics.uiIDRSentNum;
-    pStatistics->uiLTRSentNum = m_pEncContext->sEncoderStatistics.uiLTRSentNum;
+    pStatistics->uiResolutionChangeTimes = pEncStatistics->uiResolutionChangeTimes;
+    pStatistics->uiIDRReqNum = pEncStatistics->uiIDRReqNum;
+    pStatistics->uiIDRSentNum = pEncStatistics->uiIDRSentNum;
+    pStatistics->uiLTRSentNum = pEncStatistics->uiLTRSentNum;
   }
   break;
   case ENCODER_OPTION_STATISTICS_LOG_INTERVAL: {