shithub: openh264

Download patch

ref: ea06cbe06b18b059cf14dae97a9e32c68a380132
parent: 04cb9f3477b9d06d5b9133117f4b19db54cd91dc
author: Sijia Chen <[email protected]>
date: Mon Jan 12 05:39:51 EST 2015

enhance param checking with num-ref and related logging

--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -371,8 +371,9 @@
 * @brief Encoder usage type
 */
 typedef enum {
-  CAMERA_VIDEO_REAL_TIME,      ///< camera video signal
-  SCREEN_CONTENT_REAL_TIME     ///< screen content signal
+  CAMERA_VIDEO_REAL_TIME,      ///< camera video for real-time communication
+  SCREEN_CONTENT_REAL_TIME,    ///< screen content signal
+  CAMERA_VIDEO_NON_REAL_TIME
 } EUsageType;
 
 /**
--- a/codec/encoder/core/inc/au_set.h
+++ b/codec/encoder/core/inc/au_set.h
@@ -141,7 +141,8 @@
                      const bool kbDeblockingFilterPresentFlag,
                      const bool kbUsingSubsetSps,
                      const bool kbEntropyCodingModeFlag);
-int32_t WelsCheckRefFrameLimitation (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam);
+int32_t WelsCheckRefFrameLimitationNumRefFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam);
+int32_t WelsCheckRefFrameLimitationLevelIdcFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam);
 int32_t WelsAdjustLevel( SSpatialLayerConfig* pSpatialLayer);
 }
 #endif//WELS_ACCESS_UNIT_PARSER_H__
--- a/codec/encoder/core/inc/param_svc.h
+++ b/codec/encoder/core/inc/param_svc.h
@@ -135,7 +135,7 @@
     param.fMaxFrameRate		= MAX_FRAME_RATE;	// maximal frame rate [Hz / fps]
 
     param.iComplexityMode = MEDIUM_COMPLEXITY;
-    param.iTargetBitrate			= 0;	// overall target bitrate introduced in RC module
+    param.iTargetBitrate			= UNSPECIFIED_BIT_RATE;	// overall target bitrate introduced in RC module
     param.iMaxBitrate         = UNSPECIFIED_BIT_RATE;
     param.iMultipleThreadIdc		= 1;
 
@@ -190,7 +190,7 @@
   void FillDefault() {
     FillDefault (*this);
     uiGopSize			= 1;			// GOP size (at maximal frame rate: 16)
-    iMaxNumRefFrame = 1;
+    iMaxNumRefFrame = AUTO_REF_PIC_COUNT;
     SUsedPicRect.iLeft	=
       SUsedPicRect.iTop	=
         SUsedPicRect.iWidth	=
@@ -337,26 +337,15 @@
     else if (uiIntraPeriod & (uiGopSize - 1))	// none multiple of GOP size
       uiIntraPeriod = ((uiIntraPeriod + uiGopSize - 1) / uiGopSize) * uiGopSize;
 
-    if (iUsageType == SCREEN_CONTENT_REAL_TIME) {
-      if (bEnableLongTermReference) {
-        iLTRRefNum = LONG_TERM_REF_NUM_SCREEN;
-        if (iNumRefFrame == AUTO_REF_PIC_COUNT)
-          iNumRefFrame = WELS_MAX (1, WELS_LOG2 (uiGopSize)) + iLTRRefNum;
-      } else {
-        iLTRRefNum = 0;
-
-        if (iNumRefFrame == AUTO_REF_PIC_COUNT)
-          iNumRefFrame = WELS_MAX (1, uiGopSize >> 1);
-      }
-    } else {
-      iLTRRefNum = bEnableLongTermReference ? LONG_TERM_REF_NUM : 0;
-      if (iNumRefFrame == AUTO_REF_PIC_COUNT) {
-        iNumRefFrame		= ((uiGopSize >> 1) > 1) ? ((uiGopSize >> 1) + iLTRRefNum) : (MIN_REF_PIC_COUNT + iLTRRefNum);
-        iNumRefFrame		= WELS_CLIP3 (iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA);
-      }
+    if (((pCodingParam.iNumRefFrame != AUTO_REF_PIC_COUNT)
+         && ((pCodingParam.iNumRefFrame > MAX_REF_PIC_COUNT) || (pCodingParam.iNumRefFrame < MIN_REF_PIC_COUNT)))
+        || ((iNumRefFrame != AUTO_REF_PIC_COUNT) && (pCodingParam.iNumRefFrame == AUTO_REF_PIC_COUNT))) {
+      iNumRefFrame  = pCodingParam.iNumRefFrame;
     }
-    if (iNumRefFrame > iMaxNumRefFrame)
+    if ((iNumRefFrame != AUTO_REF_PIC_COUNT) && (iNumRefFrame > iMaxNumRefFrame)) {
       iMaxNumRefFrame = iNumRefFrame;
+    }
+    iLTRRefNum  = (pCodingParam.bEnableLongTermReference ? pCodingParam.iLTRRefNum : 0);
     iLtrMarkPeriod  = pCodingParam.iLtrMarkPeriod;
 
     bPrefixNalAddingCtrl	= pCodingParam.bPrefixNalAddingCtrl;
--- a/codec/encoder/core/src/au_set.cpp
+++ b/codec/encoder/core/src/au_set.cpp
@@ -65,7 +65,7 @@
     return 0;
   if (kpLevelLimit->uiMaxDPBMbs < uiNumRefFrames * uiPicInMBs)
     return 0;
-  if (iTargetBitRate
+  if ((iTargetBitRate != UNSPECIFIED_BIT_RATE)
       && ((int32_t) kpLevelLimit->uiMaxBR  * 1200) < iTargetBitRate)    //RC enabled, considering bitrate constraint
     return 0;
   //add more checks here if needed in future
@@ -86,32 +86,111 @@
   }
   return 1;
 }
-int32_t WelsCheckRefFrameLimitation (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam) {
+
+static int32_t WelsCheckNumRefSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, bool bStrictCheck) {
+  // validate LTR num
+  int32_t iCurrentSupportedLtrNum = (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME) ? LONG_TERM_REF_NUM :
+                                    LONG_TERM_REF_NUM_SCREEN;
+  if ((pParam->bEnableLongTermReference) && (iCurrentSupportedLtrNum != pParam->iLTRRefNum)) {
+    WelsLog (pLogCtx, WELS_LOG_WARNING, "iLTRRefNum(%d) does not equal to currently supported %d, will be reset",
+             pParam->iLTRRefNum, iCurrentSupportedLtrNum);
+    pParam->iLTRRefNum = iCurrentSupportedLtrNum;
+  }
+
+  //TODO: here is a fix needed here, the most reasonable value should be:
+  //        iCurrentStrNum = WELS_MAX (1, WELS_LOG2 (pParam->uiGopSize));
+  //      but reference list updating need to be changed
+  int32_t iCurrentStrNum = ((pParam->iUsageType == SCREEN_CONTENT_REAL_TIME && pParam->bEnableLongTermReference)
+                            ? (WELS_MAX (1, WELS_LOG2 (pParam->uiGopSize)))
+                            : (WELS_MAX (1, (pParam->uiGopSize >> 1))));
+  int32_t iNeededRefNum = (pParam->uiIntraPeriod != 1) ? (iCurrentStrNum + pParam->iLTRRefNum) : 0;
+  iNeededRefNum		= WELS_CLIP3 (iNeededRefNum,
+                                MIN_REF_PIC_COUNT,
+                                (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME) ? MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA :
+                                MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN);
+
+  // to adjust default or invalid input, in case pParam->iNumRefFrame do not have a valid value for the next step
+  if (pParam->iNumRefFrame == AUTO_REF_PIC_COUNT) {
+    pParam->iNumRefFrame = iNeededRefNum;
+  } else if (pParam->iNumRefFrame < iNeededRefNum) {
+    WelsLog (pLogCtx, WELS_LOG_WARNING,
+             "iNumRefFrame(%d) setting does not support the temporal and LTR setting, will be reset to %d",
+             pParam->iNumRefFrame, iNeededRefNum);
+    if (bStrictCheck) {
+      return ENC_RETURN_UNSUPPORTED_PARA;
+    }
+    pParam->iNumRefFrame = iNeededRefNum;
+  }
+
+  // after adjustment, do the following:
+  // if the setting is larger than needed, we will use the needed, and write the max into sps and for memory to wait for further expanding
+  if (pParam->iMaxNumRefFrame < pParam->iNumRefFrame) {
+    pParam->iMaxNumRefFrame = pParam->iNumRefFrame;
+  }
+  pParam->iNumRefFrame = iNeededRefNum;
+
+  return ENC_RETURN_SUCCESS;
+}
+
+int32_t WelsCheckRefFrameLimitationNumRefFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam) {
+
+  if (WelsCheckNumRefSetting (pLogCtx, pParam, true)) {
+    // we take num-ref as the honored setting but it conflicts with temporal and LTR
+    return ENC_RETURN_UNSUPPORTED_PARA;
+  }
+  for (int32_t i = 0; i < pParam->iSpatialLayerNum; ++ i) {
+    SSpatialLayerConfig* pSpatialLayer = &pParam->sSpatialLayers[i];
+    // when it is NumRefFirst and level is unknown, the level can be set to the lowest and be adjusted later
+    if (pSpatialLayer->uiLevelIdc == LEVEL_UNKNOWN) {
+      pSpatialLayer->uiLevelIdc = LEVEL_1_0;
+    }
+  }
+  return ENC_RETURN_SUCCESS;
+}
+int32_t WelsCheckRefFrameLimitationLevelIdcFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam) {
+  if ((pParam->iNumRefFrame == AUTO_REF_PIC_COUNT) || (pParam->iMaxNumRefFrame == AUTO_REF_PIC_COUNT)) {
+    //no need to do the checking
+    return ENC_RETURN_SUCCESS;
+  }
+
+  WelsCheckNumRefSetting (pLogCtx, pParam, false);
+
   int32_t i = 0;
-  int32_t iRefFrame = 1;
+  int32_t iRefFrame;
   //get the number of reference frame according to level limitation.
   for (i = 0; i < pParam->iSpatialLayerNum; ++ i) {
     SSpatialLayerConfig* pSpatialLayer = &pParam->sSpatialLayers[i];
-    uint32_t uiPicInMBs = ((pSpatialLayer->iVideoHeight + 15) >> 4) * ((pSpatialLayer->iVideoWidth + 15) >> 4);
     if (pSpatialLayer->uiLevelIdc == LEVEL_UNKNOWN) {
-      pSpatialLayer->uiLevelIdc = LEVEL_5_0;
-      WelsLog (pLogCtx, WELS_LOG_WARNING, "change level to level5.0");
+      continue;
     }
+
+    uint32_t uiPicInMBs = ((pSpatialLayer->iVideoHeight + 15) >> 4) * ((pSpatialLayer->iVideoWidth + 15) >> 4);
     iRefFrame = g_ksLevelLimits[pSpatialLayer->uiLevelIdc - 1].uiMaxDPBMbs / uiPicInMBs;
+
+    //check iMaxNumRefFrame
     if (iRefFrame < pParam->iMaxNumRefFrame) {
+      WelsLog (pLogCtx, WELS_LOG_WARNING, "iMaxNumRefFrame(%d) adjusted to %d because of limitation from uiLevelIdc=%d",
+               pParam->iMaxNumRefFrame, iRefFrame, pSpatialLayer->uiLevelIdc);
       pParam->iMaxNumRefFrame = iRefFrame;
-      if (pParam->iMaxNumRefFrame < pParam->iNumRefFrame)
-        pParam->iNumRefFrame = pParam->iMaxNumRefFrame;
+
+      //check iNumRefFrame
+      if (iRefFrame < pParam->iNumRefFrame) {
+        WelsLog (pLogCtx, WELS_LOG_WARNING, "iNumRefFrame(%d) adjusted to %d because of limitation from uiLevelIdc=%d",
+                 pParam->iNumRefFrame, iRefFrame, pSpatialLayer->uiLevelIdc);
+        pParam->iNumRefFrame = iRefFrame;
+      }
+    } else {
+      //because it is level first now, so adjust max-ref
+      WelsLog (pLogCtx, WELS_LOG_INFO,
+               "iMaxNumRefFrame(%d) adjusted to %d because of uiLevelIdc=%d -- under level-idc first strategy ",
+               pParam->iMaxNumRefFrame, iRefFrame, pSpatialLayer->uiLevelIdc);
+      pParam->iMaxNumRefFrame = iRefFrame;
     }
-    if (pParam->iMaxNumRefFrame < 1) {
-      pParam->iMaxNumRefFrame = 1;
-      WelsLog (pLogCtx, WELS_LOG_ERROR, "error Level setting (%d)", pSpatialLayer->uiLevelIdc);
-      return ENC_RETURN_UNSUPPORTED_PARA;
-    }
   }
 
   return ENC_RETURN_SUCCESS;
 }
+
 static inline ELevelIdc WelsGetLevelIdc (const SWelsSPS* kpSps, float fFrameRate, int32_t iTargetBitRate) {
   int32_t iOrder;
   for (iOrder = 0; iOrder < LEVEL_NUMBER; iOrder++) {
@@ -365,7 +444,6 @@
                      const uint32_t kuiSpsId, const bool kbEnableFrameCropping, bool bEnableRc,
                      const int32_t kiDlayerCount) {
   memset (pSps, 0, sizeof (SWelsSPS));
-  ELevelIdc uiLevel = LEVEL_5_2;
   pSps->uiSpsId		= kuiSpsId;
   pSps->iMbWidth	= (pLayerParam->iVideoWidth + 15) >> 4;
   pSps->iMbHeight	= (pLayerParam->iVideoHeight + 15) >> 4;
@@ -385,14 +463,6 @@
   }
 
   pSps->uiProfileIdc	= pLayerParam->uiProfileIdc ? pLayerParam->uiProfileIdc : PRO_BASELINE;
-
-  if (bEnableRc)  //fixed QP condition
-    uiLevel	= WelsGetLevelIdc (pSps, pLayerParamInternal->fOutputFrameRate, pLayerParam->iSpatialBitrate);
-  else
-    uiLevel  = WelsGetLevelIdc (pSps, pLayerParamInternal->fOutputFrameRate,
-                                0); // Set tar_br = 0 to remove the bitrate constraint; a better way is to set actual tar_br as 0
-
-
   if (pLayerParam->uiProfileIdc == PRO_BASELINE) {
     pSps->bConstraintSet0Flag = true;
   }
@@ -403,6 +473,7 @@
     pSps->bConstraintSet2Flag = true;
   }
 
+  ELevelIdc uiLevel	= WelsGetLevelIdc (pSps, pLayerParamInternal->fOutputFrameRate, pLayerParam->iSpatialBitrate);
   //update level
   //for Scalable Baseline, Scalable High, and Scalable High Intra profiles.If level_idc is equal to 9, the indicated level is level 1b.
   //for the Baseline, Constrained Baseline, Main, and Extended profiles,If level_idc is equal to 11 and constraint_set3_flag is equal to 1, the indicated level is level 1b.
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -242,7 +242,14 @@
                  "bEnableFrameSkip = %d,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.",
                  pCfg->bEnableFrameSkip);
   }
-  return WelsCheckRefFrameLimitation (pLogCtx, pCfg);
+  // ref-frames validation
+  if (((pCfg->iUsageType == CAMERA_VIDEO_REAL_TIME) || (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME))
+      ? WelsCheckRefFrameLimitationNumRefFirst (pLogCtx, pCfg)
+      : WelsCheckRefFrameLimitationLevelIdcFirst (pLogCtx, pCfg)) {
+    WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsCheckRefFrameLimitation failed");
+    return ENC_RETURN_INVALIDINPUT;
+  }
+  return ENC_RETURN_SUCCESS;
 }
 
 
@@ -4017,12 +4024,20 @@
     iNumRefFrame		= WELS_CLIP3 (iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA);
 
   }
-  if (sConfig.iNumRefFrame < iNumRefFrame)
-    sConfig.iNumRefFrame = iNumRefFrame;
-  if (sConfig.iNumRefFrame > sConfig.iMaxNumRefFrame)
-    sConfig.iMaxNumRefFrame = sConfig.iNumRefFrame;
+  if (iNumRefFrame > sConfig.iMaxNumRefFrame) {
+    WelsLog (pLogCtx, WELS_LOG_WARNING,
+             " CWelsH264SVCEncoder::SetOption LTR flag = %d and number = %d: Required number of reference increased to %d and iMaxNumRefFrame is adjusted",
+             sConfig.bEnableLongTermReference, sConfig.iLTRRefNum, iNumRefFrame, sConfig.iMaxNumRefFrame);
+    sConfig.iMaxNumRefFrame = iNumRefFrame;
+  }
 
-  WelsLog (pLogCtx, WELS_LOG_INFO, " CWelsH264SVCEncoder::SetOption enable LTR = %d,ltrnum = %d",
+  if (sConfig.iNumRefFrame < iNumRefFrame) {
+    WelsLog (pLogCtx, WELS_LOG_WARNING,
+             " CWelsH264SVCEncoder::SetOption LTR flag = %d and number = %d, Required number of reference increased from Old = %d to New = %d because of LTR setting",
+             sConfig.bEnableLongTermReference, sConfig.iLTRRefNum, sConfig.iNumRefFrame, iNumRefFrame);
+    sConfig.iNumRefFrame = iNumRefFrame;
+  }
+  WelsLog (pLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption enable LTR = %d,ltrnum = %d",
            sConfig.bEnableLongTermReference, sConfig.iLTRRefNum);
   iRet = WelsEncoderParamAdjust (ppCtx, &sConfig);
   return iRet;
--- a/codec/encoder/plus/src/welsEncoderExt.cpp
+++ b/codec/encoder/plus/src/welsEncoderExt.cpp
@@ -317,8 +317,7 @@
       pCfg->iNumRefFrame		= WELS_CLIP3 (pCfg->iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA);
     }
   }
-  if (pCfg->iNumRefFrame > pCfg->iMaxNumRefFrame)
-    pCfg->iMaxNumRefFrame = pCfg->iNumRefFrame;
+
   if (pCfg->iLtrMarkPeriod == 0) {
     pCfg->iLtrMarkPeriod = 30;
   }
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -97,6 +97,7 @@
     param_.iRCMode = RC_OFF_MODE; //rc off
     param_.iMultipleThreadIdc = 1; //single thread
     param_.iSpatialLayerNum = iLayers;
+    param_.iNumRefFrame = AUTO_REF_PIC_COUNT;
     for (int i = 0; i < iLayers; i++) {
       param_.sSpatialLayers[i].iVideoWidth = width >> (iLayers - i - 1);
       param_.sSpatialLayers[i].iVideoHeight = height >> (iLayers - i - 1);
@@ -230,7 +231,7 @@
   param_.iSpatialLayerNum   = rand() % SPATIAL_LAYER_NUM_RANGE;
 
   param_.uiIntraPeriod      = rand() - 1;
-  param_.iNumRefFrame       = rand();
+  param_.iNumRefFrame       = AUTO_REF_PIC_COUNT;
   param_.iMultipleThreadIdc = rand();
 
   param_.bEnableSpsPpsIdAddition   = (rand() % 2 == 0) ? false : true;
--- a/test/encoder/EncUT_EncoderExt.cpp
+++ b/test/encoder/EncUT_EncoderExt.cpp
@@ -138,6 +138,7 @@
   pParamExt->iTargetBitrate = 50000;
   pParamExt->iTemporalLayerNum = 3;
   pParamExt->iSpatialLayerNum = 1;
+  pParamExt->iNumRefFrame = AUTO_REF_PIC_COUNT;
   pParamExt->sSpatialLayers[0].iVideoHeight = pParamExt->iPicHeight;
   pParamExt->sSpatialLayers[0].iVideoWidth = pParamExt->iPicWidth;
   pParamExt->sSpatialLayers[0].iSpatialBitrate = 50000;
@@ -278,6 +279,7 @@
   pParamExt->sSpatialLayers[0].iSpatialBitrate = 50000;
   pParamExt->iTemporalLayerNum = 1;
   pParamExt->iSpatialLayerNum = 1;
+  pParamExt->iNumRefFrame = AUTO_REF_PIC_COUNT;
 
   for (int i = 0; i < 2; i++) {
     pParamExt->iUsageType = ((i == 0) ? SCREEN_CONTENT_REAL_TIME : CAMERA_VIDEO_REAL_TIME);