enhance param checking with num-ref and related logging

This commit is contained in:
Sijia Chen 2015-01-12 10:39:51 +08:00
parent 04cb9f3477
commit ea06cbe06b
8 changed files with 133 additions and 54 deletions

View File

@ -371,8 +371,9 @@ typedef struct {
* @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;
/**

View File

@ -141,7 +141,8 @@ int32_t WelsInitPps (SWelsPPS* pPps,
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__

View File

@ -135,7 +135,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
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 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
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 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
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);
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;
}
} 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 (iNumRefFrame > iMaxNumRefFrame)
if ((iNumRefFrame != AUTO_REF_PIC_COUNT) && (iNumRefFrame > iMaxNumRefFrame)) {
iMaxNumRefFrame = iNumRefFrame;
}
iLTRRefNum = (pCodingParam.bEnableLongTermReference ? pCodingParam.iLTRRefNum : 0);
iLtrMarkPeriod = pCodingParam.iLtrMarkPeriod;
bPrefixNalAddingCtrl = pCodingParam.bPrefixNalAddingCtrl;

View File

@ -65,7 +65,7 @@ static inline int32_t WelsCheckLevelLimitation (const SWelsSPS* kpSps, const SLe
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 @@ int32_t WelsAdjustLevel (SSpatialLayerConfig* pSpatialLayer) {
}
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;
}
if (pParam->iMaxNumRefFrame < 1) {
pParam->iMaxNumRefFrame = 1;
WelsLog (pLogCtx, WELS_LOG_ERROR, "error Level setting (%d)", pSpatialLayer->uiLevelIdc);
return ENC_RETURN_UNSUPPORTED_PARA;
} 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;
}
}
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 @@ int32_t WelsInitSps (SWelsSPS* pSps, SSpatialLayerConfig* pLayerParam, SSpatialL
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 @@ int32_t WelsInitSps (SWelsSPS* pSps, SSpatialLayerConfig* pLayerParam, SSpatialL
}
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 @@ int32_t WelsInitSps (SWelsSPS* pSps, SSpatialLayerConfig* pLayerParam, SSpatialL
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.

View File

@ -242,7 +242,14 @@ int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) {
"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,11 +4024,19 @@ int32_t WelsEncoderApplyLTR (SLogContext* pLogCtx, sWelsEncCtx** ppCtx, SLTRConf
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;
}
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);

View File

@ -317,8 +317,7 @@ int CWelsH264SVCEncoder::InitializeInternal (SWelsSvcCodingParam* pCfg) {
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;
}

View File

@ -97,6 +97,7 @@ class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFilePar
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 @@ void EncodeDecodeTestAPI::RandomParamExtCombination() {
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;

View File

@ -138,6 +138,7 @@ void EncoderInterfaceTest::InitializeParamExt() {
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 @@ TEST_F (EncoderInterfaceTest, TemporalLayerSettingTest) {
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);