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);