add new SpsPpsStrategy and UT

This commit is contained in:
Sijia Chen 2015-01-15 18:04:39 +08:00
parent e9ec603fd7
commit 98ed302990
16 changed files with 1150 additions and 161 deletions

View File

@ -385,6 +385,17 @@ typedef enum {
HIGH_COMPLEXITY ///< high complexity, lowest speed, high quality
} ECOMPLEXITY_MODE;
/**
* @brief Enumulate for the stategy of SPS/PPS strategy
*/
typedef enum {
CONSTANT_ID = 0, ///< constant id in SPS/PPS
INCREASING_ID = 0x01, ///< SPS/PPS id increases at each IDR
SPS_LISTING = 0x02, ///< using SPS in the existing list if possible
SPS_LISTING_AND_PPS_INCREASING = 0x03,
SPS_PPS_LISTING = 0x06,
} EParameterSetStrategy;
// TODO: Refine the parameters definition.
/**
* @brief SVC Encoding Parameters
@ -421,7 +432,7 @@ typedef struct TagEncParamExt {
ECOMPLEXITY_MODE iComplexityMode;
unsigned int uiIntraPeriod; ///< period of Intra frame
int iNumRefFrame; ///< number of reference frame used
bool bEnableSpsPpsIdAddition; ///< false:not adjust ID in SPS/PPS; true: adjust ID in SPS/PPS
int iSpsPpsIdStrategy; ///< different stategy in adjust ID in SPS/PPS: 0- constant ID, 1-additional ID, 6-mapping and additional
bool bPrefixNalAddingCtrl; ///< false:not use Prefix NAL; true: use Prefix NAL
bool bEnableSSEI; ///< false:not use SSEI; true: use SSEI -- TODO: planning to remove the interface of SSEI
bool bSimulcastAVC; ///< (when encoding more than 1 spatial layer) false: use SVC syntax for higher layers; true: use Simulcast AVC -- coming soon

View File

@ -232,8 +232,8 @@ int ParseConfig (CReadConfig& cRdCfg, SSourcePicture* pSrcPic, SEncParamExt& pSv
pSvcParam.uiIntraPeriod = atoi (strTag[1].c_str());
} else if (strTag[0].compare ("MaxNalSize") == 0) {
pSvcParam.uiMaxNalSize = atoi (strTag[1].c_str());
} else if (strTag[0].compare ("EnableSpsPpsIDAddition") == 0) {
pSvcParam.bEnableSpsPpsIdAddition = atoi (strTag[1].c_str()) ? true : false;
} else if (strTag[0].compare ("SpsPpsIDStrategy") == 0) {
pSvcParam.iSpsPpsIdStrategy = atoi (strTag[1].c_str());
} else if (strTag[0].compare ("EnableScalableSEI") == 0) {
pSvcParam.bEnableSSEI = atoi (strTag[1].c_str()) ? true : false;
} else if (strTag[0].compare ("EnableFrameCropping") == 0) {
@ -421,7 +421,7 @@ int ParseCommandLine (int argc, char** argv, SSourcePicture* pSrcPic, SEncParamE
pSvcParam.uiMaxNalSize = atoi (argv[n++]);
else if (!strcmp (pCommand, "-spsid") && (n < argc))
pSvcParam.bEnableSpsPpsIdAddition = atoi (argv[n++]) ? true : false;
pSvcParam.iSpsPpsIdStrategy = atoi (argv[n++]);
else if (!strcmp (pCommand, "-cabac") && (n < argc))
pSvcParam.iEntropyCodingModeFlag = atoi (argv[n++]);
@ -591,7 +591,7 @@ int FillSpecificParameters (SEncParamExt& sParam) {
sParam.bEnableLongTermReference = 0; // long term reference control
sParam.iLtrMarkPeriod = 30;
sParam.uiIntraPeriod = 320; // period of Intra frame
sParam.bEnableSpsPpsIdAddition = 1;
sParam.iSpsPpsIdStrategy = INCREASING_ID;
sParam.bPrefixNalAddingCtrl = 0;
sParam.iComplexityMode = MEDIUM_COMPLEXITY;
int iIndexLayer = 0;

View File

@ -141,8 +141,26 @@ int32_t WelsInitPps (SWelsPPS* pPps,
const bool kbDeblockingFilterPresentFlag,
const bool kbUsingSubsetSps,
const bool kbEntropyCodingModeFlag);
int32_t WelsCheckRefFrameLimitationNumRefFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam);
int32_t WelsCheckRefFrameLimitationLevelIdcFirst (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam);
int32_t WelsAdjustLevel( SSpatialLayerConfig* pSpatialLayer);
int32_t WelsAdjustLevel (SSpatialLayerConfig* pSpatialLayer);
/*!
* \brief check if the current parameter can found a presenting sps
* \param pParam the current encoding paramter in SWelsSvcCodingParam
* \param kbUseSubsetSps bool
* \param iDlayerIndex int, the index of current D layer
* \param iDlayerCount int, the number of total D layer
* \param pSpsArray array of all the stored SPSs
* \param pSubsetArray array of all the stored Subset-SPSs
* \return 0 - successful
* -1 - cannot find existing SPS for current encoder parameter
*/
int32_t FindExistingSps (SWelsSvcCodingParam* pParam, const bool kbUseSubsetSps, const int32_t iDlayerIndex,
const int32_t iDlayerCount, const int32_t iSpsNumInUse,
SWelsSPS* pSpsArray,
SSubsetSps* pSubsetArray);
}
#endif//WELS_ACCESS_UNIT_PARSER_H__

View File

@ -48,7 +48,7 @@ namespace WelsEnc {
* \param pEncCtx sWelsEncCtx*
* \return successful - 0; otherwise none 0 for failed
*/
int32_t RequestMemorySvc (sWelsEncCtx** ppCtx);
int32_t RequestMemorySvc (sWelsEncCtx** ppCtx, SExistingParasetList* pExistingParasetList);
/*!
* \brief free memory in SVC core encoder

View File

@ -191,6 +191,7 @@ typedef struct TagWelsEncCtx {
SSubsetSps* pSubsetArray; // MAX_SPS_COUNT by standard compatible
SSubsetSps* pSubsetSps;
int32_t iSpsNum; // number of pSps used
int32_t iSubsetSpsNum; // number of pSps used
int32_t iPpsNum; // number of pPps used
// Output
@ -216,6 +217,7 @@ typedef struct TagWelsEncCtx {
pDqIdcMap; // overall DQ map of full scalability in specific frame (All full D/T/Q layers involved) // pDqIdcMap[dq_index] for each SDqIdc pData
SParaSetOffset sPSOVector;
SParaSetOffset* pPSOVector;
CMemoryAlign* pMemAlign;
#if defined(STAT_OUTPUT)

View File

@ -75,7 +75,8 @@ void GomValidCheck (const int32_t kiMbWidth, const int32_t kiMbHeight, int32_t*
* \param para SWelsSvcCodingParam*
* \return successful - 0; otherwise none 0 for failed
*/
int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pPara, SLogContext* pLogCtx);
int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pPara, SLogContext* pLogCtx,
SExistingParasetList* pExistingParasetList);
/*!
* \brief uninitialize Wels encoder core library

View File

@ -162,7 +162,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
param.bEnableAdaptiveQuant = true; // adaptive quantization control
param.bEnableFrameSkip = true; // frame skipping
param.bEnableLongTermReference = false; // long term reference control
param.bEnableSpsPpsIdAddition = true; // pSps pPps id addition control
param.iSpsPpsIdStrategy = INCREASING_ID; // pSps pPps id addition control
param.bPrefixNalAddingCtrl = false; // prefix NAL adding control
param.iSpatialLayerNum = 1; // number of dependency(Spatial/CGS) layers used to be encoded
param.iTemporalLayerNum = 1; // number of temporal layer specified
@ -350,8 +350,8 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
bPrefixNalAddingCtrl = pCodingParam.bPrefixNalAddingCtrl;
bEnableSpsPpsIdAddition =
pCodingParam.bEnableSpsPpsIdAddition;//For SVC meeting application, to avoid mosaic issue caused by cross-IDR reference.
iSpsPpsIdStrategy =
pCodingParam.iSpsPpsIdStrategy;//For SVC meeting application, to avoid mosaic issue caused by cross-IDR reference.
//SHOULD enable this feature.
SSpatialLayerInternal* pDlp = &sDependencyLayers[0];
@ -477,6 +477,18 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt {
} SWelsSvcCodingParam;
typedef struct TagExistingParasetList {
SWelsSPS sSps[MAX_SPS_COUNT];
SSubsetSps sSubsetSps[MAX_SPS_COUNT];
SWelsPPS sPps[MAX_PPS_COUNT];
uint32_t uiInUseSpsNum;
uint32_t uiInUseSubsetSpsNum;
uint32_t uiInUsePpsNum;
} SExistingParasetList;
static inline int32_t FreeCodingParam (SWelsSvcCodingParam** pParam, CMemoryAlign* pMa) {
if (pParam == NULL || *pParam == NULL || pMa == NULL)
return 1;

View File

@ -83,9 +83,15 @@ typedef struct TagParaSetOffset {
bool
bPpsIdMappingIntoSubsetsps[MAX_DQ_LAYER_NUM/*+1*/]; // need not extra +1 due no MGS and FMO case so far
int32_t iPpsIdList[MAX_DQ_LAYER_NUM][MAX_PPS_COUNT]; //index0: max pps types; index1: for differnt IDRs, if only index0=1, index1 can reach MAX_PPS_COUNT
#if _DEBUG
bool bEnableSpsPpsIdAddition;
int32_t iSpsPpsIdStrategy;
#endif
uint32_t uiInUseSpsNum;
uint32_t uiInUseSubsetSpsNum;
uint32_t uiInUsePpsNum;
} SParaSetOffset;

View File

@ -171,6 +171,7 @@
#define UNAVAILABLE_DQ_ID ((uint8_t)(-1))
#define LAYER_NUM_EXCHANGEABLE 2
#define INVALID_ID (-1)
#define NAL_HEADER_ADD_0X30BYTES 50

View File

@ -336,27 +336,27 @@ int32_t WelsWriteSubsetSpsSyntax (SSubsetSps* pSubsetSps, SBitStringAux* pBitStr
* \note Call it in case EWelsNalUnitType is PPS.
*************************************************************************************
*/
int32_t WelsWritePpsSyntax (SWelsPPS* pPps, SBitStringAux* pBitStringAux, SParaSetOffset* sPSOVector) {
int32_t WelsWritePpsSyntax (SWelsPPS* pPps, SBitStringAux* pBitStringAux, SParaSetOffset* pPSOVector) {
SBitStringAux* pLocalBitStringAux = pBitStringAux;
bool bUsedSubset = sPSOVector->bPpsIdMappingIntoSubsetsps[pPps->iPpsId];
int32_t iParameterSetType = (bUsedSubset ? PARA_SET_TYPE_SUBSETSPS : PARA_SET_TYPE_AVCSPS);
const int32_t kiParameterSetType = (pPSOVector != NULL) ? (pPSOVector->bPpsIdMappingIntoSubsetsps[pPps->iPpsId] ?
PARA_SET_TYPE_SUBSETSPS : PARA_SET_TYPE_AVCSPS) : 0;
BsWriteUE (pLocalBitStringAux, pPps->iPpsId +
sPSOVector->sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[pPps->iPpsId]);
BsWriteUE (pLocalBitStringAux, pPps->iSpsId +
sPSOVector->sParaSetOffsetVariable[iParameterSetType].iParaSetIdDelta[pPps->iSpsId]);
BsWriteUE (pLocalBitStringAux, pPps->iPpsId
+ ((pPSOVector != NULL) ? (pPSOVector->sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[pPps->iPpsId]) : 0));
BsWriteUE (pLocalBitStringAux, pPps->iSpsId
+ ((pPSOVector != NULL) ? (pPSOVector->sParaSetOffsetVariable[kiParameterSetType].iParaSetIdDelta[pPps->iSpsId]) : 0));
#if _DEBUG
//SParaSetOffset use, 110421
if (sPSOVector->bEnableSpsPpsIdAddition) {
if ((pPSOVector != NULL) && (INCREASING_ID & pPSOVector->iSpsPpsIdStrategy)) {
const int32_t kiTmpSpsIdInBs = pPps->iSpsId +
sPSOVector->sParaSetOffsetVariable[iParameterSetType].iParaSetIdDelta[pPps->iSpsId];
pPSOVector->sParaSetOffsetVariable[kiParameterSetType].iParaSetIdDelta[pPps->iSpsId];
const int32_t tmp_pps_id_in_bs = pPps->iPpsId +
sPSOVector->sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[pPps->iPpsId];
pPSOVector->sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[pPps->iPpsId];
assert (MAX_SPS_COUNT > kiTmpSpsIdInBs);
assert (MAX_PPS_COUNT > tmp_pps_id_in_bs);
assert (sPSOVector->sParaSetOffsetVariable[iParameterSetType].bUsedParaSetIdInBs[kiTmpSpsIdInBs]);
assert (pPSOVector->sParaSetOffsetVariable[kiParameterSetType].bUsedParaSetIdInBs[kiTmpSpsIdInBs]);
}
#endif

View File

@ -323,6 +323,12 @@ int32_t ParamValidationExt (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingPa
pCodingParam->bDeblockingParallelFlag = true;
}
if (pCodingParam->iSpatialLayerNum > 1 && (SPS_LISTING & pCodingParam->iSpsPpsIdStrategy)) {
WelsLog (pLogCtx, WELS_LOG_INFO,
"ParamValidationExt(), iSpsPpsIdStrategy adjusted to CONSTANT_ID");
pCodingParam->iSpsPpsIdStrategy = CONSTANT_ID;
}
for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) {
SSpatialLayerConfig* pSpatialLayer = &pCodingParam->sSpatialLayers[i];
const int32_t kiPicWidth = pSpatialLayer->iVideoWidth;
@ -665,8 +671,12 @@ static inline int32_t AcquireLayersNals (sWelsEncCtx** ppCtx, SWelsSvcCodingPara
++ iDIndex;
} while (iDIndex < iNumDependencyLayers);
// count parasets
iCountNumNals += 1 + iNumDependencyLayers + (iCountNumLayers << 1) +
iCountNumLayers; // plus iCountNumLayers for reserved application
iCountNumLayers // plus iCountNumLayers for reserved application
+ ((SPS_LISTING & pParam->iSpsPpsIdStrategy) ? MAX_SPS_COUNT : 0) //for Sps
+ (((SPS_LISTING & pParam->iSpsPpsIdStrategy) && (iNumDependencyLayers > 1)) ? MAX_SPS_COUNT : 0) //for SubsetSps
+ ((SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy) ? MAX_PPS_COUNT : 0);
// to check number of layers / nals / slices dependencies, 12/8/2010
if (iCountNumLayers > MAX_LAYER_NUM_OF_FRAME) {
@ -847,7 +857,7 @@ void FreeMbCache (SMbCache* pMbCache, CMemoryAlign* pMa) {
}
}
int32_t WelsGenerateNewSps (sWelsEncCtx* pCtx, const bool kbUseSubsetSps, const int32_t iDlayerIndex,
static int32_t WelsGenerateNewSps (sWelsEncCtx* pCtx, const bool kbUseSubsetSps, const int32_t iDlayerIndex,
const int32_t iDlayerCount, const int32_t kiSpsId,
SWelsSPS*& pSps, SSubsetSps*& pSubsetSps) {
int32_t iRet = 0;
@ -866,9 +876,6 @@ int32_t WelsGenerateNewSps (sWelsEncCtx* pCtx, const bool kbUseSubsetSps, const
iRet = WelsInitSps (pSps, pDlayerParam, &pParam->sDependencyLayers[iDlayerIndex], pParam->uiIntraPeriod,
pParam->iMaxNumRefFrame,
kiSpsId, pParam->bEnableFrameCroppingFlag, pParam->iRCMode != RC_OFF_MODE, iDlayerCount);
} else {
iRet = WelsInitSubsetSps (pSubsetSps, pDlayerParam, &pParam->sDependencyLayers[iDlayerIndex], pParam->uiIntraPeriod,
pParam->iMaxNumRefFrame,
@ -877,12 +884,131 @@ int32_t WelsGenerateNewSps (sWelsEncCtx* pCtx, const bool kbUseSubsetSps, const
return iRet;
}
static bool CheckMatchedSps (SWelsSPS* const pSps1, SWelsSPS* const pSps2) {
if ((pSps1->iMbWidth != pSps2->iMbWidth)
|| (pSps1->iMbHeight != pSps2->iMbHeight)) {
return false;
}
if ((pSps1->uiLog2MaxFrameNum != pSps2->uiLog2MaxFrameNum)
|| (pSps1->iLog2MaxPocLsb != pSps2->iLog2MaxPocLsb)) {
return false;
}
if (pSps1->iNumRefFrames != pSps2->iNumRefFrames) {
return false;
}
if ((pSps1->bFrameCroppingFlag != pSps2->bFrameCroppingFlag)
|| (pSps1->sFrameCrop.iCropLeft != pSps2->sFrameCrop.iCropLeft)
|| (pSps1->sFrameCrop.iCropRight != pSps2->sFrameCrop.iCropRight)
|| (pSps1->sFrameCrop.iCropTop != pSps2->sFrameCrop.iCropTop)
|| (pSps1->sFrameCrop.iCropBottom != pSps2->sFrameCrop.iCropBottom)
) {
return false;
}
if ((pSps1->uiProfileIdc != pSps2->uiProfileIdc)
|| (pSps1->bConstraintSet0Flag != pSps2->bConstraintSet0Flag)
|| (pSps1->bConstraintSet1Flag != pSps2->bConstraintSet1Flag)
|| (pSps1->bConstraintSet2Flag != pSps2->bConstraintSet2Flag)
|| (pSps1->bConstraintSet3Flag != pSps2->bConstraintSet3Flag)
|| (pSps1->iLevelIdc != pSps2->iLevelIdc)) {
return false;
}
return true;
}
static bool CheckMatchedSubsetSps (SSubsetSps* const pSubsetSps1, SSubsetSps* const pSubsetSps2) {
if (!CheckMatchedSps (&pSubsetSps1->pSps, &pSubsetSps2->pSps)) {
return false;
}
if ((pSubsetSps1->sSpsSvcExt.iExtendedSpatialScalability != pSubsetSps2->sSpsSvcExt.iExtendedSpatialScalability)
|| (pSubsetSps1->sSpsSvcExt.bAdaptiveTcoeffLevelPredFlag != pSubsetSps2->sSpsSvcExt.bAdaptiveTcoeffLevelPredFlag)
|| (pSubsetSps1->sSpsSvcExt.bSeqTcoeffLevelPredFlag != pSubsetSps2->sSpsSvcExt.bSeqTcoeffLevelPredFlag)
|| (pSubsetSps1->sSpsSvcExt.bSliceHeaderRestrictionFlag != pSubsetSps2->sSpsSvcExt.bSliceHeaderRestrictionFlag)) {
return false;
}
return true;
}
int32_t FindExistingSps (SWelsSvcCodingParam* pParam, const bool kbUseSubsetSps, const int32_t iDlayerIndex,
const int32_t iDlayerCount, const int32_t iSpsNumInUse,
SWelsSPS* pSpsArray,
SSubsetSps* pSubsetArray) {
SSpatialLayerConfig* pDlayerParam = &pParam->sSpatialLayers[iDlayerIndex];
assert (iSpsNumInUse <= MAX_SPS_COUNT);
if (!kbUseSubsetSps) {
SWelsSPS sTmpSps;
WelsInitSps (&sTmpSps, pDlayerParam, &pParam->sDependencyLayers[iDlayerIndex], pParam->uiIntraPeriod,
pParam->iMaxNumRefFrame,
0, pParam->bEnableFrameCroppingFlag, pParam->iRCMode != RC_OFF_MODE, iDlayerCount);
for (int32_t iId = 0; iId < iSpsNumInUse; iId++) {
if (CheckMatchedSps (&sTmpSps, &pSpsArray[iId])) {
return iId;
}
}
} else {
SSubsetSps sTmpSubsetSps;
WelsInitSubsetSps (&sTmpSubsetSps, pDlayerParam, &pParam->sDependencyLayers[iDlayerIndex], pParam->uiIntraPeriod,
pParam->iMaxNumRefFrame,
0, pParam->bEnableFrameCroppingFlag, pParam->iRCMode != RC_OFF_MODE);
for (int32_t iId = 0; iId < iSpsNumInUse; iId++) {
if (CheckMatchedSubsetSps (&sTmpSubsetSps, &pSubsetArray[iId])) {
return iId;
}
}
}
return INVALID_ID;
}
int32_t FindExistingPps (SWelsSPS* pSps, SSubsetSps* pSubsetSps, const bool kbUseSubsetSps, const int32_t iSpsId,
const bool kbEntropyCodingFlag, const int32_t iPpsNumInUse,
SWelsPPS* pPpsArray) {
#if !defined(DISABLE_FMO_FEATURE)
// feature not supported yet
return INVALID_ID;
#endif//!DISABLE_FMO_FEATURE
SWelsPPS sTmpPps;
WelsInitPps (&sTmpPps,
pSps,
pSubsetSps,
0,
true,
kbUseSubsetSps,
kbEntropyCodingFlag);
assert (iPpsNumInUse <= MAX_PPS_COUNT);
for (int32_t iId = 0; iId < iPpsNumInUse; iId++) {
if ((sTmpPps.iSpsId == pPpsArray[iId].iSpsId)
&& (sTmpPps.bEntropyCodingModeFlag == pPpsArray[iId].bEntropyCodingModeFlag)
&& (sTmpPps.iPicInitQp == pPpsArray[iId].iPicInitQp)
&& (sTmpPps.iPicInitQs == pPpsArray[iId].iPicInitQs)
&& (sTmpPps.uiChromaQpIndexOffset == pPpsArray[iId].uiChromaQpIndexOffset)
&& (sTmpPps.bDeblockingFilterControlPresentFlag == pPpsArray[iId].bDeblockingFilterControlPresentFlag)
) {
return iId;
}
}
return INVALID_ID;
}
/*!
* \brief initialize ppDqLayerList and slicepEncCtx_list due to count number of layers available
* \pParam pCtx sWelsEncCtx*
* \return 0 - successful; otherwise failed
*/
static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx) {
static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx, SExistingParasetList* pExistingParasetList) {
SWelsSvcCodingParam* pParam = NULL;
SWelsSPS* pSps = NULL;
SSubsetSps* pSubsetSps = NULL;
@ -1045,15 +1171,52 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx) {
}
// for dynamically malloc for parameter sets memory instead of maximal items for standard to reduce size, 3/18/2010
(*ppCtx)->pPPSArray = (SWelsPPS*)pMa->WelsMalloc (iDlayerCount * sizeof (SWelsPPS), "pPPSArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pPPSArray), FreeMemorySvc (ppCtx))
// SPS
if (! (SPS_LISTING & pParam->iSpsPpsIdStrategy)) {
(*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (sizeof (SWelsSPS), "pSpsArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx))
if (iDlayerCount > 1) {
(*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc ((iDlayerCount - 1) * sizeof (SSubsetSps), "pSubsetArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc (ppCtx))
}
} else {
// pParam->iSpsPpsIdStrategy == SPS_LISTING_AND_PPS_INCREASING
// new memory
(*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SWelsSPS), "pSpsArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx))
(*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SSubsetSps), "pSubsetArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc (ppCtx))
// copy from existing if the pointer exists
if (NULL != pExistingParasetList) {
(*ppCtx)->sPSOVector.uiInUseSpsNum = pExistingParasetList->uiInUseSpsNum;
(*ppCtx)->sPSOVector.uiInUseSubsetSpsNum = pExistingParasetList->uiInUseSubsetSpsNum;
memcpy ((*ppCtx)->pSpsArray, pExistingParasetList->sSps, MAX_SPS_COUNT * sizeof (SWelsSPS));
memcpy ((*ppCtx)->pSubsetArray, pExistingParasetList->sSubsetSps, MAX_SPS_COUNT * sizeof (SSubsetSps));
}
}
// PPS
if (! (SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy)) {
(*ppCtx)->pPPSArray = (SWelsPPS*)pMa->WelsMalloc (iDlayerCount * sizeof (SWelsPPS), "pPPSArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pPPSArray), FreeMemorySvc (ppCtx))
} else {
(*ppCtx)->pPPSArray = (SWelsPPS*)pMa->WelsMalloc (MAX_PPS_COUNT * sizeof (SWelsPPS), "pPPSArray");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pPPSArray), FreeMemorySvc (ppCtx))
// copy from existing if the pointer exists
if (NULL != pExistingParasetList) {
(*ppCtx)->sPSOVector.uiInUsePpsNum = pExistingParasetList->uiInUsePpsNum;
memcpy ((*ppCtx)->pPPSArray, pExistingParasetList->sPps, MAX_PPS_COUNT * sizeof (SWelsPPS));
}
}
if (INCREASING_ID & pParam->iSpsPpsIdStrategy) {
(*ppCtx)->pPSOVector = & ((*ppCtx)->sPSOVector);
} else {
(*ppCtx)->pPSOVector = NULL;
}
(*ppCtx)->pDqIdcMap = (SDqIdc*)pMa->WelsMallocz (iDlayerCount * sizeof (SDqIdc), "pDqIdcMap");
WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pDqIdcMap), FreeMemorySvc (ppCtx))
@ -1066,12 +1229,79 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx) {
pDqIdc->uiSpatialId = iDlayerIndex;
if (! (SPS_LISTING & pParam->iSpsPpsIdStrategy)) {
WelsGenerateNewSps (*ppCtx, bUseSubsetSps, iDlayerIndex,
iDlayerCount, iSpsId, pSps, pSubsetSps);
} else {
//SPS_LISTING_AND_PPS_INCREASING == pParam->iSpsPpsIdStrategy
//check if the current param can fit in an existing SPS
const int32_t kiFoundSpsId = FindExistingSps ((*ppCtx)->pSvcParam, bUseSubsetSps, iDlayerIndex, iDlayerCount,
bUseSubsetSps ? ((*ppCtx)->sPSOVector.uiInUseSubsetSpsNum) : ((*ppCtx)->sPSOVector.uiInUseSpsNum),
(*ppCtx)->pSpsArray,
(*ppCtx)->pSubsetArray);
if (INVALID_ID != kiFoundSpsId) {
//if yes, set pSps or pSubsetSps to it
iSpsId = kiFoundSpsId;
if (!bUseSubsetSps) {
pSps = & ((*ppCtx)->pSpsArray[kiFoundSpsId]);
} else {
pSubsetSps = & ((*ppCtx)->pSubsetArray[kiFoundSpsId]);
}
} else {
//if no, generate a new SPS as usual
if ((SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy) && (MAX_PPS_COUNT <= (*ppCtx)->sPSOVector.uiInUsePpsNum)) {
//check if we can generate new SPS or not
WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
"InitDqLayers(), cannot generate new SPS under the SPS_PPS_LISTING mode!");
return ENC_RETURN_UNSUPPORTED_PARA;
}
iSpsId = (!bUseSubsetSps) ? ((*ppCtx)->sPSOVector.uiInUseSpsNum++) : ((*ppCtx)->sPSOVector.uiInUseSubsetSpsNum++);
if (iSpsId >= MAX_SPS_COUNT) {
if (SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy) {
WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
"InitDqLayers(), cannot generate new SPS under the SPS_PPS_LISTING mode!");
return ENC_RETURN_UNSUPPORTED_PARA;
}
// reset current list
if (!bUseSubsetSps) {
(*ppCtx)->sPSOVector.uiInUseSpsNum = 1;
memset ((*ppCtx)->pSpsArray, 0, MAX_SPS_COUNT * sizeof (SWelsSPS));
} else {
(*ppCtx)->sPSOVector.uiInUseSubsetSpsNum = 1;
memset ((*ppCtx)->pSubsetArray, 0, MAX_SPS_COUNT * sizeof (SSubsetSps));
}
iSpsId = 0;
}
WelsGenerateNewSps (*ppCtx, bUseSubsetSps, iDlayerIndex,
iDlayerCount, iSpsId, pSps, pSubsetSps);
}
}
if (! (SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy)) {
pPps = & (*ppCtx)->pPPSArray[iPpsId];
// initialize pPps
WelsInitPps (pPps, pSps, pSubsetSps, iPpsId, true, bUseSubsetSps, pParam->iEntropyCodingModeFlag != 0);
} else {
const int32_t kiFoundPpsId = FindExistingPps (pSps, pSubsetSps, bUseSubsetSps, iSpsId,
pParam->iEntropyCodingModeFlag != 0,
(*ppCtx)->sPSOVector.uiInUsePpsNum,
(*ppCtx)->pPPSArray);
if (INVALID_ID != kiFoundPpsId) {
//if yes, set pPps to it
iPpsId = kiFoundPpsId;
pPps = & ((*ppCtx)->pPPSArray[kiFoundPpsId]);
} else {
iPpsId = ((*ppCtx)->sPSOVector.uiInUsePpsNum++);
pPps = & (*ppCtx)->pPPSArray[iPpsId];
WelsInitPps (pPps, pSps, pSubsetSps, iPpsId, true, bUseSubsetSps, pParam->iEntropyCodingModeFlag != 0);
}
}
// Not using FMO in SVC coding so far, come back if need FMO
{
@ -1085,7 +1315,7 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx) {
if (iResult) {
WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "InitDqLayers(), InitSlicePEncCtx failed(%d)!", iResult);
FreeMemorySvc (ppCtx);
return 1;
return iResult;
}
(*ppCtx)->ppDqLayerList[iDlayerIndex]->pSliceEncCtx = & (*ppCtx)->pSliceCtxList[iDlayerIndex];
}
@ -1097,12 +1327,23 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx) {
if (bUseSubsetSps)
++ iSpsId;
++ iPpsId;
if (bUseSubsetSps) {
++ (*ppCtx)->iSubsetSpsNum;
} else {
++ (*ppCtx)->iSpsNum;
}
++ (*ppCtx)->iPpsNum;
++ iDlayerIndex;
}
return 0;
if (SPS_LISTING & pParam->iSpsPpsIdStrategy) {
(*ppCtx)->iSpsNum = (*ppCtx)->sPSOVector.uiInUseSpsNum;
(*ppCtx)->iSubsetSpsNum = (*ppCtx)->sPSOVector.uiInUseSubsetSpsNum;
}
if (SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy) {
(*ppCtx)->iPpsNum = (*ppCtx)->sPSOVector.uiInUsePpsNum;
}
return ENC_RETURN_SUCCESS;
}
int32_t AllocStrideTables (sWelsEncCtx** ppCtx, const int32_t kiNumSpatialLayers) {
@ -1411,7 +1652,7 @@ void GetMvMvdRange (SWelsSvcCodingParam* pParam, int32_t& iMvRange, int32_t& iMv
iMvdRange = WELS_MIN (iMvdRange, iFixMvdRange);
}
int32_t RequestMemorySvc (sWelsEncCtx** ppCtx) {
int32_t RequestMemorySvc (sWelsEncCtx** ppCtx, SExistingParasetList* pExistingParasetList) {
SWelsSvcCodingParam* pParam = (*ppCtx)->pSvcParam;
CMemoryAlign* pMa = (*ppCtx)->pMemAlign;
SSpatialLayerConfig* pFinalSpatial = NULL;
@ -1616,7 +1857,7 @@ int32_t RequestMemorySvc (sWelsEncCtx** ppCtx) {
//End of pVaa memory allocation
iResult = InitDqLayers (ppCtx);
iResult = InitDqLayers (ppCtx, pExistingParasetList);
if (iResult) {
WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), InitDqLayers failed(%d)!", iResult);
FreeMemorySvc (ppCtx);
@ -2130,7 +2371,8 @@ int32_t GetMultipleThreadIdc (SLogContext* pLogCtx, SWelsSvcCodingParam* pCoding
* \pParam pParam SWelsSvcCodingParam*
* \return successful - 0; otherwise none 0 for failed
*/
int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingParam, SLogContext* pLogCtx) {
int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingParam, SLogContext* pLogCtx,
SExistingParasetList* pExistingParasetList) {
sWelsEncCtx* pCtx = NULL;
int32_t iRet = 0;
int16_t iSliceNum = 1; // number of slices used
@ -2189,7 +2431,7 @@ int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingPar
pCtx->iActiveThreadsNum = pCodingParam->iCountThreadsNum;
pCtx->iMaxSliceCount = iSliceNum;
iRet = RequestMemorySvc (&pCtx);
iRet = RequestMemorySvc (&pCtx, pExistingParasetList);
if (iRet != 0) {
WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), RequestMemorySvc failed return %d.", iRet);
FreeMemorySvc (&pCtx);
@ -2553,18 +2795,26 @@ void WelsInitCurrentLayer (sWelsEncCtx* pCtx,
iSliceCount = GetCurrentSliceNum (pCurDq->pSliceEncCtx);
assert (iSliceCount > 0);
pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId = pDqIdc->iPpsId;
int32_t iCurPpsId = pDqIdc->iPpsId;
int32_t iCurSpsId = pDqIdc->iSpsId;
if (SPS_PPS_LISTING == pParam->iSpsPpsIdStrategy) {
iCurPpsId = pCtx->sPSOVector.iPpsIdList[pDqIdc->iPpsId][WELS_ABS (pCtx->uiIdrPicId - 1) % MAX_PPS_COUNT];
}
pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId = iCurPpsId;
pCurDq->sLayerInfo.pPpsP =
pBaseSlice->sSliceHeaderExt.sSliceHeader.pPps = &pCtx->pPPSArray[pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId];
pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId = pDqIdc->iSpsId;
pBaseSlice->sSliceHeaderExt.sSliceHeader.pPps = &pCtx->pPPSArray[iCurPpsId];
pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId = iCurSpsId;
if (kbUseSubsetSpsFlag) {
pCurDq->sLayerInfo.pSubsetSpsP = &pCtx->pSubsetArray[pDqIdc->iSpsId];
pCurDq->sLayerInfo.pSubsetSpsP = &pCtx->pSubsetArray[iCurSpsId];
pCurDq->sLayerInfo.pSpsP =
pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps = &pCurDq->sLayerInfo.pSubsetSpsP->pSps;
} else {
pCurDq->sLayerInfo.pSubsetSpsP = NULL;
pCurDq->sLayerInfo.pSpsP =
pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps = &pCtx->pSpsArray[pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId];
pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps = &pCtx->pSpsArray[iCurSpsId];
}
pSlice = pBaseSlice;
@ -2865,29 +3115,60 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN
/* write all SPS */
iIdx = 0;
while (iIdx < pCtx->iSpsNum) {
SDqIdc* pDqIdc = &pCtx->pDqIdcMap[iIdx];
const int32_t kiDid = pDqIdc->uiSpatialId;
const bool kbUsingSubsetSps = (kiDid > BASE_DEPENDENCY_ID);
iNal = pCtx->pOut->iNalIndex;
if (pCtx->pSvcParam->bEnableSpsPpsIdAddition) {
if (INCREASING_ID == pCtx->pSvcParam->iSpsPpsIdStrategy) {
#if _DEBUG
pCtx->sPSOVector.bEnableSpsPpsIdAddition = 1;
assert (kiDid < MAX_DEPENDENCY_LAYER);
pCtx->sPSOVector.iSpsPpsIdStrategy = INCREASING_ID;
assert (iIdx < MAX_DQ_LAYER_NUM);
#endif
ParasetIdAdditionIdAdjust (& (pCtx->sPSOVector.sParaSetOffsetVariable[kbUsingSubsetSps ? PARA_SET_TYPE_SUBSETSPS :
PARA_SET_TYPE_AVCSPS]),
(kbUsingSubsetSps) ? (pCtx->pSubsetArray[iIdx - 1].pSps.uiSpsId) : (pCtx->pSpsArray[0].uiSpsId),
ParasetIdAdditionIdAdjust (& (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS]),
pCtx->pSpsArray[0].uiSpsId,
MAX_SPS_COUNT);
} else {
} else if (CONSTANT_ID == pCtx->pSvcParam->iSpsPpsIdStrategy) {
memset (& (pCtx->sPSOVector), 0, sizeof (pCtx->sPSOVector));
}
if (kbUsingSubsetSps) {
iId = iIdx - 1;
/* generate sequence parameters set */
iId = (SPS_LISTING & pCtx->pSvcParam->iSpsPpsIdStrategy) ? iIdx : 0;
WelsLoadNal (pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST);
WelsWriteSpsNal (&pCtx->pSpsArray[iId], &pCtx->pOut->sBsWrite,
& (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS].iParaSetIdDelta[0]));
WelsUnloadNal (pCtx->pOut);
iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length
pCtx->pFrameBs + pCtx->iPosBsBuffer,
&iNalLength);
WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
pNalLen[iCountNal] = iNalLength;
pCtx->iPosBsBuffer += iNalLength;
iSize += iNalLength;
++ iIdx;
++ iCountNal;
}
/* write all Subset SPS */
iIdx = 0;
while (iIdx < pCtx->iSubsetSpsNum) {
iNal = pCtx->pOut->iNalIndex;
if (INCREASING_ID == pCtx->pSvcParam->iSpsPpsIdStrategy) {
#if _DEBUG
pCtx->sPSOVector.iSpsPpsIdStrategy = INCREASING_ID;
assert (iIdx < MAX_DQ_LAYER_NUM);
#endif
ParasetIdAdditionIdAdjust (& (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_SUBSETSPS]),
pCtx->pSubsetArray[iIdx].pSps.uiSpsId,
MAX_SPS_COUNT);
}
iId = iIdx;
/* generate Subset SPS */
WelsLoadNal (pCtx->pOut, NAL_UNIT_SUBSET_SPS, NRI_PRI_HIGHEST);
@ -2895,15 +3176,6 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN
WelsWriteSubsetSpsSyntax (&pCtx->pSubsetArray[iId], &pCtx->pOut->sBsWrite,
& (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_SUBSETSPS].iParaSetIdDelta[0]));
WelsUnloadNal (pCtx->pOut);
} else {
iId = 0;
/* generate sequence parameters set */
WelsLoadNal (pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST);
WelsWriteSpsNal (&pCtx->pSpsArray[0], &pCtx->pOut->sBsWrite,
& (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS].iParaSetIdDelta[0]));
WelsUnloadNal (pCtx->pOut);
}
iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length
@ -2921,8 +3193,30 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN
/* write all PPS */
iIdx = 0;
if ((SPS_PPS_LISTING == pCtx->pSvcParam->iSpsPpsIdStrategy) && (pCtx->iPpsNum < MAX_PPS_COUNT)) {
assert (pCtx->iPpsNum <= MAX_DQ_LAYER_NUM);
//Generate PPS LIST
int32_t iPpsId = 0, iUsePpsNum = pCtx->iPpsNum;
for (int32_t iIdrRound = 0; iIdrRound < MAX_PPS_COUNT; iIdrRound++) {
for (iPpsId = 0; iPpsId < pCtx->iPpsNum; iPpsId++) {
pCtx->sPSOVector.iPpsIdList[iPpsId][iIdrRound] = ((iIdrRound * iUsePpsNum + iPpsId) % MAX_PPS_COUNT);
}
}
for (iPpsId = iUsePpsNum; iPpsId < MAX_PPS_COUNT; iPpsId++) {
memcpy (& (pCtx->pPPSArray[iPpsId]), & (pCtx->pPPSArray[iPpsId % iUsePpsNum]), sizeof (SWelsPPS));
pCtx->pPPSArray[iPpsId].iPpsId = iPpsId;
pCtx->iPpsNum++;
}
assert (pCtx->iPpsNum == MAX_PPS_COUNT);
pCtx->sPSOVector.uiInUsePpsNum = pCtx->iPpsNum;
}
while (iIdx < pCtx->iPpsNum) {
if (pCtx->pSvcParam->bEnableSpsPpsIdAddition) {
if ((INCREASING_ID & pCtx->pSvcParam->iSpsPpsIdStrategy)) {
//para_set_type = 2: PPS, use MAX_PPS_COUNT
ParasetIdAdditionIdAdjust (&pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS], pCtx->pPPSArray[iIdx].iPpsId,
MAX_PPS_COUNT);
@ -2931,7 +3225,8 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN
iNal = pCtx->pOut->iNalIndex;
/* generate picture parameter set */
WelsLoadNal (pCtx->pOut, NAL_UNIT_PPS, NRI_PRI_HIGHEST);
WelsWritePpsSyntax (&pCtx->pPPSArray[iIdx], &pCtx->pOut->sBsWrite, & (pCtx->sPSOVector));
WelsWritePpsSyntax (&pCtx->pPPSArray[iIdx], &pCtx->pOut->sBsWrite,
((SPS_PPS_LISTING != pCtx->pSvcParam->iSpsPpsIdStrategy)) ? (& (pCtx->sPSOVector)) : NULL);
WelsUnloadNal (pCtx->pOut);
iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
@ -3237,7 +3532,6 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour
iDidList[iSpatialIdx] = iCurDid;
// Encoding this picture might mulitiple sQualityStat layers potentially be encoded as followed
switch (pParam->sSliceCfg.uiSliceMode) {
case SM_FIXEDSLCNUM_SLICE:
case SM_AUTO_SLICE: {
@ -3829,7 +4123,8 @@ int32_t WelsEncoderParamAdjust (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pNewPa
(pOldParam->iLTRRefNum != pNewParam->iLTRRefNum) ||
(pOldParam->iMultipleThreadIdc != pNewParam->iMultipleThreadIdc) ||
(pOldParam->bEnableBackgroundDetection != pNewParam->bEnableBackgroundDetection) ||
(pOldParam->bEnableAdaptiveQuant != pNewParam->bEnableAdaptiveQuant);
(pOldParam->bEnableAdaptiveQuant != pNewParam->bEnableAdaptiveQuant) ||
(pOldParam->iSpsPpsIdStrategy != pNewParam->iSpsPpsIdStrategy);
if (pNewParam->iMaxNumRefFrame > pOldParam->iMaxNumRefFrame) {
bNeedReset = true;
}
@ -3876,35 +4171,75 @@ int32_t WelsEncoderParamAdjust (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pNewPa
}
if (bNeedReset) {
SParaSetOffsetVariable sTmpPsoVariable[PARA_SET_TYPE];
uint16_t uiTmpIdrPicId;//this is for LTR!
SLogContext sLogCtx = (*ppCtx)->sLogCtx;
for (int32_t k = 0; k < PARA_SET_TYPE; k++)
memset (((*ppCtx)->sPSOVector.sParaSetOffsetVariable[k].bUsedParaSetIdInBs), 0, MAX_PPS_COUNT * sizeof (bool));
memcpy (sTmpPsoVariable, (*ppCtx)->sPSOVector.sParaSetOffsetVariable,
(PARA_SET_TYPE)*sizeof (SParaSetOffsetVariable)); // confirmed_safe_unsafe_usage
uiTmpIdrPicId = (*ppCtx)->uiIdrPicId;
int32_t iOldSpsPpsIdStrategy = pOldParam->iSpsPpsIdStrategy;
SParaSetOffsetVariable sTmpPsoVariable[PARA_SET_TYPE];
int32_t iTmpPpsIdList[MAX_DQ_LAYER_NUM * MAX_PPS_COUNT];
uint16_t uiTmpIdrPicId = (*ppCtx)->uiIdrPicId;//this is for LTR!
SEncoderStatistics sTempEncoderStatistics = (*ppCtx)->sEncoderStatistics;
SExistingParasetList sExistingParasetList;
SExistingParasetList* pExistingParasetList = NULL;
if ((CONSTANT_ID != iOldSpsPpsIdStrategy) && (CONSTANT_ID != pNewParam->iSpsPpsIdStrategy)) {
for (int32_t k = 0; k < PARA_SET_TYPE; k++) {
memset (((*ppCtx)->sPSOVector.sParaSetOffsetVariable[k].bUsedParaSetIdInBs), 0, MAX_PPS_COUNT * sizeof (bool));
}
memcpy (sTmpPsoVariable, (*ppCtx)->sPSOVector.sParaSetOffsetVariable,
(PARA_SET_TYPE)*sizeof (SParaSetOffsetVariable)); // confirmed_safe_unsafe_usage
if ((SPS_LISTING & iOldSpsPpsIdStrategy)
&& (SPS_LISTING & pNewParam->iSpsPpsIdStrategy)) {
pExistingParasetList = &sExistingParasetList;
sExistingParasetList.uiInUseSpsNum = (*ppCtx)->sPSOVector.uiInUseSpsNum;
sExistingParasetList.uiInUseSubsetSpsNum = (*ppCtx)->sPSOVector.uiInUseSubsetSpsNum;
memcpy (sExistingParasetList.sSps, (*ppCtx)->pSpsArray, MAX_SPS_COUNT * sizeof (SWelsSPS));
memcpy (sExistingParasetList.sSubsetSps, (*ppCtx)->pSubsetArray, MAX_SPS_COUNT * sizeof (SSubsetSps));
}
if ((SPS_PPS_LISTING == iOldSpsPpsIdStrategy)
&& (SPS_PPS_LISTING == pNewParam->iSpsPpsIdStrategy)) {
pExistingParasetList = &sExistingParasetList;
sExistingParasetList.uiInUseSpsNum = (*ppCtx)->sPSOVector.uiInUseSpsNum;
sExistingParasetList.uiInUseSubsetSpsNum = (*ppCtx)->sPSOVector.uiInUseSubsetSpsNum;
sExistingParasetList.uiInUsePpsNum = (*ppCtx)->sPSOVector.uiInUsePpsNum;
memcpy (sExistingParasetList.sSps, (*ppCtx)->pSpsArray, MAX_SPS_COUNT * sizeof (SWelsSPS));
memcpy (sExistingParasetList.sSubsetSps, (*ppCtx)->pSubsetArray, MAX_SPS_COUNT * sizeof (SSubsetSps));
memcpy (sExistingParasetList.sPps, (*ppCtx)->pPps, MAX_PPS_COUNT * sizeof (SWelsPPS));
memcpy (iTmpPpsIdList, ((*ppCtx)->sPSOVector.iPpsIdList), MAX_DQ_LAYER_NUM * MAX_PPS_COUNT * sizeof (int32_t));
}
}
WelsUninitEncoderExt (ppCtx);
/* Update new parameters */
if (WelsInitEncoderExt (ppCtx, pNewParam, &sLogCtx))
if (WelsInitEncoderExt (ppCtx, pNewParam, &sLogCtx, pExistingParasetList))
return 1;
// reset the scaled spatial picture size
(*ppCtx)->pVpp->WelsPreprocessReset (*ppCtx);
//if WelsInitEncoderExt succeed
//load back the needed structure
//for FLEXIBLE_PARASET_ID
memcpy ((*ppCtx)->sPSOVector.sParaSetOffsetVariable, sTmpPsoVariable,
(PARA_SET_TYPE)*sizeof (SParaSetOffsetVariable)); // confirmed_safe_unsafe_usage
//for LTR
(*ppCtx)->uiIdrPicId = uiTmpIdrPicId;
//for sEncoderStatistics
(*ppCtx)->sEncoderStatistics = sTempEncoderStatistics;
//load back the needed structure for iSpsPpsIdStrategy
if ((CONSTANT_ID != iOldSpsPpsIdStrategy) && (CONSTANT_ID != pNewParam->iSpsPpsIdStrategy)) {
memcpy ((*ppCtx)->sPSOVector.sParaSetOffsetVariable, sTmpPsoVariable,
(PARA_SET_TYPE)*sizeof (SParaSetOffsetVariable)); // confirmed_safe_unsafe_usage
}
if ((SPS_PPS_LISTING == iOldSpsPpsIdStrategy)
&& (SPS_PPS_LISTING == pNewParam->iSpsPpsIdStrategy)) {
memcpy (((*ppCtx)->sPSOVector.iPpsIdList), iTmpPpsIdList, MAX_DQ_LAYER_NUM * MAX_PPS_COUNT * sizeof (int32_t));
}
} else {
/* maybe adjustment introduced in bitrate or little settings adjustment and so on.. */
pNewParam->iNumRefFrame = WELS_CLIP3 (pNewParam->iNumRefFrame, MIN_REF_PIC_COUNT,
@ -3919,7 +4254,7 @@ int32_t WelsEncoderParamAdjust (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pNewPa
pOldParam->fMaxFrameRate = pNewParam->fMaxFrameRate; // maximal frame rate [Hz / fps]
pOldParam->iComplexityMode = pNewParam->iComplexityMode; // color space of input sequence
pOldParam->uiIntraPeriod = pNewParam->uiIntraPeriod; // intra period (multiple of GOP size as desired)
pOldParam->bEnableSpsPpsIdAddition = pNewParam->bEnableSpsPpsIdAddition;
pOldParam->iSpsPpsIdStrategy = pNewParam->iSpsPpsIdStrategy;
pOldParam->bPrefixNalAddingCtrl = pNewParam->bPrefixNalAddingCtrl;
pOldParam->iNumRefFrame = pNewParam->iNumRefFrame; // number of reference frame used
pOldParam->uiGopSize = pNewParam->uiGopSize;

View File

@ -237,7 +237,8 @@ void WriteRefPicMarking (SBitStringAux* pBs, SSliceHeader* pSliceHeader, SNalUni
}
}
void WelsSliceHeaderWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice, int32_t* pPpsIdDelta) {
void WelsSliceHeaderWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice,
int32_t* pPpsIdDelta) {
SWelsSPS* pSps = pCurLayer->sLayerInfo.pSpsP;
SWelsPPS* pPps = pCurLayer->sLayerInfo.pPpsP;
SSliceHeader* pSliceHeader = &pSlice->sSliceHeaderExt.sSliceHeader;
@ -246,7 +247,7 @@ void WelsSliceHeaderWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCur
BsWriteUE (pBs, pSliceHeader->iFirstMbInSlice);
BsWriteUE (pBs, pSliceHeader->eSliceType); /* same type things */
BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + pPpsIdDelta[pSliceHeader->pPps->iPpsId]);
BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + ((pPpsIdDelta != NULL) ? pPpsIdDelta[pSliceHeader->pPps->iPpsId] : 0));
BsWriteBits (pBs, pSps->uiLog2MaxFrameNum, pSliceHeader->iFrameNum);
@ -301,7 +302,8 @@ void WelsSliceHeaderWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCur
}
}
void WelsSliceHeaderExtWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice, int32_t* pPpsIdDelta) {
void WelsSliceHeaderExtWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* pCurLayer, SSlice* pSlice,
int32_t* pPpsIdDelta) {
SWelsSPS* pSps = pCurLayer->sLayerInfo.pSpsP;
SWelsPPS* pPps = pCurLayer->sLayerInfo.pPpsP;
SSubsetSps* pSubSps = pCurLayer->sLayerInfo.pSubsetSpsP;
@ -312,7 +314,7 @@ void WelsSliceHeaderExtWrite (sWelsEncCtx* pCtx, SBitStringAux* pBs, SDqLayer* p
BsWriteUE (pBs, pSliceHeader->iFirstMbInSlice);
BsWriteUE (pBs, pSliceHeader->eSliceType); /* same type things */
BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + pPpsIdDelta[pSliceHeader->pPps->iPpsId]);
BsWriteUE (pBs, pSliceHeader->pPps->iPpsId + ((pPpsIdDelta != NULL) ? pPpsIdDelta[pSliceHeader->pPps->iPpsId] : 0));
BsWriteBits (pBs, pSps->uiLog2MaxFrameNum, pSliceHeader->iFrameNum);
@ -727,11 +729,12 @@ int32_t WelsCodeOneSlice (sWelsEncCtx* pEncCtx, const int32_t kiSliceIdx, const
WelsSliceHeaderExtInit (pEncCtx, pCurLayer, pCurSlice);
g_pWelsWriteSliceHeader[pCurSlice->bSliceHeaderExtFlag] (pEncCtx, pBs, pCurLayer, pCurSlice,
& (pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[0]));
((SPS_PPS_LISTING != pEncCtx->pSvcParam->iSpsPpsIdStrategy) ? (&
(pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[0])) : NULL));
#if _DEBUG
if (pEncCtx->sPSOVector.bEnableSpsPpsIdAddition) {
if (INCREASING_ID & pEncCtx->sPSOVector.iSpsPpsIdStrategy) {
const int32_t kiEncoderPpsId = pCurSlice->sSliceHeaderExt.sSliceHeader.pPps->iPpsId;
const int32_t kiTmpPpsIdInBs = kiEncoderPpsId +
pEncCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS].iParaSetIdDelta[ kiEncoderPpsId ];

View File

@ -332,7 +332,7 @@ int CWelsH264SVCEncoder::InitializeInternal (SWelsSvcCodingParam* pCfg) {
m_iMaxPicHeight = pCfg->iPicHeight;
TraceParamInfo (pCfg);
if (WelsInitEncoderExt (&m_pEncContext, pCfg, &m_pWelsTrace->m_sLogCtx)) {
if (WelsInitEncoderExt (&m_pEncContext, pCfg, &m_pWelsTrace->m_sLogCtx, NULL)) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), WelsInitEncoderExt failed.");
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_DEBUG,
"Problematic Input Base Param: iUsageType=%d, Resolution=%dx%d, FR=%f, TLayerNum=%d, DLayerNum=%d",
@ -477,6 +477,7 @@ int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR) {
}
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::ForceIntraFrame(), bIDR= %d", bIDR);
ForceCodingIDR (m_pEncContext);
m_pEncContext->sEncoderStatistics.uiIDRReqNum++;
@ -486,8 +487,8 @@ int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR) {
void CWelsH264SVCEncoder::TraceParamInfo (SEncParamExt* pParam) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"iUsageType = %d,iPicWidth= %d;iPicHeight= %d;iTargetBitrate= %d;iMaxBitrate= %d;iRCMode= %d;iPaddingFlag= %d;iTemporalLayerNum= %d;iSpatialLayerNum= %d;fFrameRate= %.6ff;uiIntraPeriod= %d;\
bEnableSpsPpsIdAddition = %d;bPrefixNalAddingCtrl = %d;bEnableDenoise= %d;bEnableBackgroundDetection= %d;bEnableAdaptiveQuant= %d;bEnableFrameSkip= %d;bEnableLongTermReference= %d;iLtrMarkPeriod= %d;\
iComplexityMode = %d;iNumRefFrame = %d;iEntropyCodingModeFlag = %d;uiMaxNalSize = %d;iLTRRefNum = %d;iMultipleThreadIdc = %d;iLoopFilterDisableIdc = %d",
iSpsPpsIdStrategy = %d;bPrefixNalAddingCtrl = %d;bEnableDenoise= %d;bEnableBackgroundDetection= %d;bEnableAdaptiveQuant= %d;bEnableFrameSkip= %d;bEnableLongTermReference= %d;iLtrMarkPeriod= %d;\
iComplexityMode = %d;iNumRefFrame = %d;iEntropyCodingModeFlag = %d;uiMaxNalSize = %d;iLTRRefNum = %d;iMultipleThreadIdc = %d;iLoopFilterDisableIdc = %d (offset(alpha/beta): %d,%d)",
pParam->iUsageType,
pParam->iPicWidth,
pParam->iPicHeight,
@ -499,7 +500,7 @@ void CWelsH264SVCEncoder::TraceParamInfo (SEncParamExt* pParam) {
pParam->iSpatialLayerNum,
pParam->fMaxFrameRate,
pParam->uiIntraPeriod,
pParam->bEnableSpsPpsIdAddition,
pParam->iSpsPpsIdStrategy,
pParam->bPrefixNalAddingCtrl,
pParam->bEnableDenoise,
pParam->bEnableBackgroundDetection,
@ -513,7 +514,9 @@ void CWelsH264SVCEncoder::TraceParamInfo (SEncParamExt* pParam) {
pParam->uiMaxNalSize,
pParam->iLTRRefNum,
pParam->iMultipleThreadIdc,
pParam->iLoopFilterDisableIdc
pParam->iLoopFilterDisableIdc,
pParam->iLoopFilterAlphaC0Offset,
pParam->iLoopFilterBetaOffset
);
int32_t i = 0;
int32_t iSpatialLayers = (pParam->iSpatialLayerNum < MAX_SPATIAL_LAYER_NUM) ? (pParam->iSpatialLayerNum) :
@ -706,16 +709,26 @@ int CWelsH264SVCEncoder::SetOption (ENCODER_OPTION eOptionId, void* pOption) {
#endif//OUTPUT_BIT_STREAM
if (sEncodingParam.iSpatialLayerNum < 1
|| sEncodingParam.iSpatialLayerNum > MAX_SPATIAL_LAYER_NUM) { // verify number of spatial layer
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!",
sEncodingParam.iSpatialLayerNum);
return cmInitParaError;
}
if (sConfig.ParamTranscode (sEncodingParam)) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, ParamTranscode failed!");
return cmInitParaError;
}
if (sConfig.iSpatialLayerNum < 1) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!",
sConfig.iSpatialLayerNum);
return cmInitParaError;
}
if (sConfig.DetermineTemporalSettings()) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, DetermineTemporalSettings failed!");
return cmInitParaError;
}
@ -898,11 +911,17 @@ int CWelsH264SVCEncoder::SetOption (ENCODER_OPTION eOptionId, void* pOption) {
}
break;
case ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION: {
bool iValue = * ((bool*)pOption);
m_pEncContext->pSvcParam->bEnableSpsPpsIdAddition = iValue;
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, " CWelsH264SVCEncoder::SetOption enable SPS/PPS ID = %d ",
m_pEncContext->pSvcParam->bEnableSpsPpsIdAddition);
int32_t iValue = * ((int32_t*)pOption);
if (((iValue > INCREASING_ID) || (m_pEncContext->pSvcParam->iSpsPpsIdStrategy > INCREASING_ID))
&& m_pEncContext->pSvcParam->iSpsPpsIdStrategy != iValue) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR,
" CWelsH264SVCEncoder::SetOption iSpsPpsIdStrategy changing in the middle of call is NOT allowed for iSpsPpsIdStrategy>INCREASING_ID: existing setting is %d and the new one is %d",
m_pEncContext->pSvcParam->iSpsPpsIdStrategy, iValue);
return cmInitParaError;
}
m_pEncContext->pSvcParam->iSpsPpsIdStrategy = iValue;
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, " CWelsH264SVCEncoder::SetOption iSpsPpsIdStrategy = %d ",
m_pEncContext->pSvcParam->iSpsPpsIdStrategy);
}
break;
case ENCODER_OPTION_CURRENT_PATH: {

View File

@ -88,26 +88,25 @@ class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFilePar
BaseDecoderTest::TearDown();
}
virtual void prepareParam (int iLayers, int iSlices, int width, int height, float framerate) {
memset (&param_, 0, sizeof (SEncParamExt));
param_.iUsageType = CAMERA_VIDEO_REAL_TIME;
param_.iPicWidth = width;
param_.iPicHeight = height;
param_.fMaxFrameRate = framerate;
param_.iRCMode = RC_OFF_MODE; //rc off
param_.iMultipleThreadIdc = 1; //single thread
param_.iSpatialLayerNum = iLayers;
param_.iNumRefFrame = AUTO_REF_PIC_COUNT;
virtual void prepareParam (int iLayers, int iSlices, int width, int height, float framerate, SEncParamExt* pParam) {
memset (pParam, 0, sizeof (SEncParamExt));
pParam->iUsageType = CAMERA_VIDEO_REAL_TIME;
pParam->iPicWidth = width;
pParam->iPicHeight = height;
pParam->fMaxFrameRate = framerate;
pParam->iRCMode = RC_OFF_MODE; //rc off
pParam->iMultipleThreadIdc = 1; //single thread
pParam->iSpatialLayerNum = iLayers;
pParam->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);
param_.sSpatialLayers[i].fFrameRate = framerate;
param_.sSpatialLayers[i].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
param_.sSpatialLayers[i].sSliceCfg.sSliceArgument.uiSliceNum = iSlices;
pParam->sSpatialLayers[i].iVideoWidth = width >> (iLayers - i - 1);
pParam->sSpatialLayers[i].iVideoHeight = height >> (iLayers - i - 1);
pParam->sSpatialLayers[i].fFrameRate = framerate;
pParam->sSpatialLayers[i].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
pParam->sSpatialLayers[i].sSliceCfg.sSliceArgument.uiSliceNum = iSlices;
}
}
}
virtual void prepareEncDecParam (const EncodeDecodeFileParamBase EncDecFileParam) {
//for encoder
//I420: 1(Y) + 1/4(U) + 1/4(V)
@ -147,6 +146,15 @@ class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFilePar
len = layerInfo.pNalLengthInByte[iSliceNum];
}
virtual int GetRandWidth() {
return (WELS_CLIP3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, 2, MAX_WIDTH));
}
virtual int GetRandHeight() {
return (WELS_CLIP3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, 2, MAX_HEIGHT));
}
protected:
SEncParamExt param_;
BufferedData buf_;
@ -171,8 +179,8 @@ class EncodeDecodeTestAPI : public EncodeDecodeTestBase {
EncodeDecodeTestBase::TearDown();
}
void prepareParam (int iLayers, int iSlices, int width, int height, float framerate) {
EncodeDecodeTestBase::prepareParam (iLayers, iSlices, width, height, framerate);
void prepareParam (int iLayers, int iSlices, int width, int height, float framerate, SEncParamExt* pParam) {
EncodeDecodeTestBase::prepareParam (iLayers, iSlices, width, height, framerate, pParam);
}
void InitialEncDec (int iWidth, int iHeight);
@ -192,6 +200,24 @@ class EncodeDecodeTestAPI : public EncodeDecodeTestBase {
else if (1 == iCheckTypeIndex)
ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
}
void EncDecOneFrame (const int iWidth, const int iHeight, const int iFrame, FILE* pfEnc) {
int iLen = 0, rv;
InitialEncDec (iWidth, iHeight);
EncodeOneFrame (iFrame);
//extract target layer data
encToDecData (info, iLen);
//call decoder
unsigned char* pData[3] = { NULL };
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iLen, pData, &dstBufInfo_);
EXPECT_TRUE (rv == cmResultSuccess) << " rv = " << rv << " iFrameIdx = " << iFrame;
if (NULL != pfEnc) {
fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, pfEnc);
}
}
};
void EncodeDecodeTestAPI::InitialEncDec (int iWidth, int iHeight) {
@ -234,7 +260,7 @@ void EncodeDecodeTestAPI::RandomParamExtCombination() {
param_.iNumRefFrame = AUTO_REF_PIC_COUNT;
param_.iMultipleThreadIdc = rand();
param_.bEnableSpsPpsIdAddition = (rand() % 2 == 0) ? false : true;
param_.iSpsPpsIdStrategy = rand() % 3;
param_.bPrefixNalAddingCtrl = (rand() % 2 == 0) ? false : true;
param_.bEnableSSEI = (rand() % 2 == 0) ? false : true;
param_.iPaddingFlag = rand() % 2;
@ -462,7 +488,7 @@ static const EncodeDecodeFileParamBase kFileParamArray[] = {
TEST_P (EncodeDecodeTestAPI, DecoderVclNal) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -498,7 +524,7 @@ TEST_P (EncodeDecodeTestAPI, DecoderVclNal) {
TEST_P (EncodeDecodeTestAPI, GetOptionFramenum) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -535,7 +561,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionFramenum) {
TEST_P (EncodeDecodeTestAPI, GetOptionIDR) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -554,7 +580,8 @@ TEST_P (EncodeDecodeTestAPI, GetOptionIDR) {
int32_t iSpsPpsIdAddition = 0;
int iIdx = 0;
while (iIdx <= p.numframes) {
iSpsPpsIdAddition = rand() % 2;
iSpsPpsIdAddition = rand() %
2; //the current strategy supports more than 2 modes, but the switch between the modes>2 is not allowed
iIDRPeriod = (rand() % 150) + 1;
encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod);
encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition);
@ -776,7 +803,7 @@ int SimulateNALLoss (const unsigned char* pSrc, int& iSrcLen, std::vector<SLost
TEST_P (EncodeDecodeTestAPI, GetOptionLTR_ALLIDR) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -809,7 +836,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionLTR_ALLLTR) {
SLTRMarkingFeedback m_LTR_Marking_Feedback;
SLTRRecoverRequest m_LTR_Recover_Request;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -868,7 +895,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionLTR_Engine) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -918,7 +945,7 @@ TEST_P (EncodeDecodeTestAPI, SetOptionECFlag_ERROR_CON_DISABLE) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.bEnableLongTermReference = true;
param_.iLTRRefNum = 1;
encoder_->Uninitialize();
@ -985,7 +1012,7 @@ TEST_P (EncodeDecodeTestAPI, SetOptionECFlag_ERROR_CON_SLICE_COPY) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -1036,7 +1063,7 @@ TEST_P (EncodeDecodeTestAPI, SetOptionECFlag_ERROR_CON_SLICE_COPY) {
TEST_P (EncodeDecodeTestAPI, InOutTimeStamp) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -1086,7 +1113,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionTid_AVC_NOPREFIX) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.bPrefixNalAddingCtrl = false;
param_.iTemporalLayerNum = (rand() % 4) + 1;
encoder_->Uninitialize();
@ -1155,7 +1182,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionTid_AVC_WITH_PREFIX_NOLOSS) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.bPrefixNalAddingCtrl = true;
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 1;
@ -1210,7 +1237,7 @@ TEST_P (EncodeDecodeTestAPI, GetOptionTid_SVC_L1_NOLOSS) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (2, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (2, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 2;
encoder_->Uninitialize();
@ -1266,7 +1293,7 @@ TEST_P (EncodeDecodeTestAPI, SetOption_Trace) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (&param_);
@ -1330,7 +1357,7 @@ TEST_P (EncodeDecodeTestAPI, SetOption_Trace_NULL) {
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -1393,7 +1420,7 @@ TEST_P (EncodeDecodeTestAPI, SetOptionECIDC_GeneralSliceChange) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -1473,7 +1500,7 @@ TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificFrameChange) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -1612,7 +1639,7 @@ TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRLoss) {
uint32_t uiEcIdc = 2; //default set as SLICE_COPY
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, 2, p.width, p.height, p.frameRate);
prepareParam (1, 2, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -1745,7 +1772,7 @@ TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRNoLoss) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, 2, p.width, p.height, p.frameRate);
prepareParam (1, 2, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -1914,7 +1941,7 @@ TEST_F (EncodeDecodeTestAPI, Engine_SVC_Switch_I) {
EncodeDecodeFileParamBase p = kSVCSwitch[0];
p.width = p.width << 2;
p.height = p.height << 2;
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
@ -1979,7 +2006,7 @@ TEST_F (EncodeDecodeTestAPI, Engine_SVC_Switch_P) {
int iLastDid = 0;
p.width = p.width << 2;
p.height = p.height << 2;
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate);
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate, &param_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
@ -2065,7 +2092,7 @@ TEST_F (EncodeDecodeTestAPI, SetOptionEncParamExt) {
int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
int iSliceNum = 1;
encoder_->GetDefaultParams (&param_);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &param_);
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
@ -2128,8 +2155,8 @@ class DecodeCrashTestAPI : public EncodeDecodeTestBase {
ASSERT_TRUE (ucBuf_ == NULL);
}
void prepareParam (int iLayerNum, int iSliceNum, int width, int height, float framerate) {
EncodeDecodeTestBase::prepareParam (iLayerNum, iSliceNum, width, height, framerate);
void prepareParam (int iLayerNum, int iSliceNum, int width, int height, float framerate, SEncParamExt* pParam) {
EncodeDecodeTestBase::prepareParam (iLayerNum, iSliceNum, width, height, framerate, pParam);
}
void prepareEncDecParam (const EncodeDecodeFileParamBase EncDecFileParam);
@ -2203,11 +2230,11 @@ TEST_F (DecodeCrashTestAPI, DecoderCrashTest) {
int iSeed = rand() % 3; //3 indicates the length of kParamArray[] used in the following
EncodeDecodeParamBase p = kParamArray[iSeed];
//Initialize Encoder
prepareParam (1, 1, p.width, p.height, p.frameRate);
prepareParam (1, 1, p.width, p.height, p.frameRate, &param_);
param_.iRCMode = RC_BITRATE_MODE;
param_.iTargetBitrate = p.iTarBitrate;
param_.uiIntraPeriod = 0;
param_.bEnableSpsPpsIdAddition = true;
param_.iSpsPpsIdStrategy = INCREASING_ID;
param_.bEnableBackgroundDetection = true;
param_.bEnableSceneChangeDetect = true;
param_.bPrefixNalAddingCtrl = true;
@ -2398,7 +2425,7 @@ TEST_F (DecodeParseAPI, ParseOnly_General) {
p.height = iHeight_;
p.frameRate = kiFrameRate;
p.numframes = kiFrameNum;
prepareParam (kiTotalLayer, kiSliceNum, p.width, p.height, p.frameRate);
prepareParam (kiTotalLayer, kiSliceNum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = kiTotalLayer;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -2475,7 +2502,7 @@ TEST_F (DecodeParseAPI, ParseOnly_SpecSliceLoss) {
p.height = iHeight_;
p.frameRate = kiFrameRate;
p.numframes = 5;
prepareParam (iLayerNum, iSliceNum, p.width, p.height, p.frameRate);
prepareParam (iLayerNum, iSliceNum, p.width, p.height, p.frameRate, &param_);
param_.iSpatialLayerNum = iLayerNum;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
@ -2525,3 +2552,434 @@ TEST_F (DecodeParseAPI, ParseOnly_SpecSliceLoss) {
} //while
}
//#define DEBUG_FILE_SAVE2
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_LISTING_AND_PPS_INCREASING1) {
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
SEncParamExt sParam2;
SEncParamExt sParam3;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
//prepare param2
memcpy (&sParam2, &sParam1, sizeof (SEncParamExt));
while (sParam2.iPicWidth == sParam1.iPicWidth) {
sParam2.iPicWidth = GetRandWidth();
}
prepareParam (iSpatialLayerNum, iSliceNum, sParam2.iPicWidth, sParam2.iPicHeight, fFrameRate, &sParam2);
sParam2.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
//prepare param3
memcpy (&sParam3, &sParam1, sizeof (SEncParamExt));
while (sParam3.iPicHeight == sParam1.iPicHeight) {
sParam3.iPicHeight = GetRandHeight();
}
prepareParam (iSpatialLayerNum, iSliceNum, sParam3.iPicWidth, sParam3.iPicHeight, fFrameRate, &sParam3);
sParam3.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE2
fEnc = fopen ("enc2.264", "wb");
#endif
// Test part#1
// step#1: pParam1
//int TraceLevel = WELS_LOG_INFO;
//encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &TraceLevel);
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// new IDR
rv = encoder_->ForceIntraFrame (true);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// step#2: pParam2
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption: rv = " << rv << " at " << sParam2.iPicWidth << "x" <<
sParam2.iPicHeight;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
// new IDR
rv = encoder_->ForceIntraFrame (true);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
// step#3: back to pParam1
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// step#4: back to pParam2
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv << sParam2.iPicWidth << sParam2.iPicHeight;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
#ifdef DEBUG_FILE_SAVE2
fclose (fEnc);
#endif
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
// Test part#2
// step#1: pParam1
rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt Failed: rv = " << rv;
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam3);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam3: rv = " << rv;
#ifdef DEBUG_FILE_SAVE2
fEnc = fopen ("enc3.264", "wb");
#endif
iEncFrameNum = 0;
EncDecOneFrame (sParam3.iPicWidth, sParam3.iPicHeight, iEncFrameNum++, fEnc);
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
#ifdef DEBUG_FILE_SAVE2
fclose (fEnc);
#endif
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
}
#define DEBUG_FILE_SAVE5
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_LISTING_AND_PPS_INCREASING2) {
//usage 3: 2 Params with different num_ref, encode IDR0, P1, IDR2;
//the bs will show two SPS and different PPS
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
SEncParamExt sParam2;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
sParam1.iTemporalLayerNum = 1;
//prepare param2
memcpy (&sParam2, &sParam1, sizeof (SEncParamExt));
prepareParam (iSpatialLayerNum, iSliceNum, sParam2.iPicWidth, sParam2.iPicHeight, fFrameRate, &sParam2);
sParam2.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
sParam2.iTemporalLayerNum = 3;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE5
fEnc = fopen ("encID2.264", "wb");
#endif
// step#1: pParam1
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
// step#2: pParam2
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
// step#3: set back to pParam1, with a smaller num_ref, it still uses the previous SPS
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam1: rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// new IDR, PPS increases
rv = encoder_->ForceIntraFrame (true);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
#ifdef DEBUG_FILE_SAVE5
fclose (fEnc);
#endif
}
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_LISTING_AND_PPS_INCREASING3) {
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
SEncParamExt sParam2;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE2
fEnc = fopen ("enc4.264", "wb");
#endif
// step#1: pParam1
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt Failed: rv = " << rv;
int max_count = 65; // make it more then twice as MAX_SPS_COUNT
std::vector<int> vWidthTable;
vWidthTable.push_back (sParam1.iPicWidth);
std::vector<int>::iterator vWidthTableIt;
for (int times = 0; times < max_count; times++) {
//prepare param2
memcpy (&sParam2, &sParam1, sizeof (SEncParamExt));
do {
sParam2.iPicWidth = GetRandWidth();
vWidthTableIt = std::find (vWidthTable.begin(), vWidthTable.end(), sParam2.iPicWidth);
} while (vWidthTableIt == vWidthTable.end());
vWidthTable.push_back (sParam2.iPicWidth);
prepareParam (iSpatialLayerNum, iSliceNum, sParam2.iPicWidth, sParam2.iPicHeight, fFrameRate, &sParam2);
sParam2.iSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING;
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv << ", sParam2.iPicWidth=" <<
sParam2.iPicWidth;
} // end of setting loop
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
#ifdef DEBUG_FILE_SAVE2
fclose (fEnc);
#endif
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
}
//#define DEBUG_FILE_SAVE6
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_PPS_LISTING1) {
//usage 1: 1 resolution Params, encode IDR0, P1, IDR2;
//the bs will show same SPS and different PPS
// PPS: pic_parameter_set_id 1 ( 0)
// PPS: seq_parameter_set_id 1 ( 0)
// PPS: pic_parameter_set_id 010 ( 1)
// PPS: seq_parameter_set_id 1 ( 0)
// SH: slice_type 011 ( 2)
// SH: pic_parameter_set_id 1 ( 0)
// SH: slice_type 1 ( 0)
// SH: pic_parameter_set_id 1 ( 0)
// SH: slice_type 011 ( 2)
// SH: pic_parameter_set_id 010 ( 1)
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE6
fEnc = fopen ("encLIST1.264", "wb");
#endif
// step#1: pParam1
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// new IDR
rv = encoder_->ForceIntraFrame (true);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
#ifdef DEBUG_FILE_SAVE6
fclose (fEnc);
#endif
}
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_PPS_LISTING2) {
//usage 2: 2 resolution Params, encode IDR0, IDR1, IDR2;
//the bs will show two SPS and different PPS
// === SPS LIST ===
//SPS: seq_parameter_set_id 1 ( 0) -- PARAM1
//SPS: seq_parameter_set_id 010 ( 1) -- PARAM2
// === PPS LIST ===
//PPS: pic_parameter_set_id 1 ( 0)
//PPS: seq_parameter_set_id 1 ( 0)
//PPS: pic_parameter_set_id 010 ( 1)
//PPS: seq_parameter_set_id 010 ( 1)
//PPS: pic_parameter_set_id 011 ( 2) -- PPS2 - SPS0
//PPS: seq_parameter_set_id 1 ( 0)
//PPS: pic_parameter_set_id 00100 ( 3) -- PPS3 - SPS1
//PPS: seq_parameter_set_id 010 ( 1)
//PPS: pic_parameter_set_id 00101 ( 4) -- PPS4 - SPS0
//PPS: seq_parameter_set_id 1 ( 0)
// === VCL LAYER ===
//SH: slice_type 011 ( 2) -- PARAM2
//SH: pic_parameter_set_id 010 ( 1) -- PPS1 - SPS1 - PARAM2
//SH: slice_type 011 ( 2) -- PARAM1
//SH: pic_parameter_set_id 011 ( 2) -- PPS2 - SPS0 - PARAM1
//SH: slice_type 011 ( 2) -- PARAM1
//SH: pic_parameter_set_id 00101 ( 4) -- PPS4 - SPS0 - PARAM1
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
SEncParamExt sParam2;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare param2
memcpy (&sParam2, &sParam1, sizeof (SEncParamExt));
while (sParam2.iPicWidth == sParam1.iPicWidth) {
sParam2.iPicWidth = GetRandWidth();
}
prepareParam (iSpatialLayerNum, iSliceNum, sParam2.iPicWidth, sParam2.iPicHeight, fFrameRate, &sParam2);
sParam2.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE5
fEnc = fopen ("encLIST2.264", "wb");
#endif
// step#1: pParam1
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
// step#2: pParam2
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
// step#3: back to pParam1, SHOULD NOT encounter ERROR
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
// new IDR
rv = encoder_->ForceIntraFrame (true);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
EncDecOneFrame (sParam1.iPicWidth, sParam1.iPicHeight, iEncFrameNum++, fEnc);
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
#ifdef DEBUG_FILE_SAVE5
fclose (fEnc);
#endif
}
TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_PPS_LISTING3) {
int iWidth = GetRandWidth();
int iHeight = GetRandHeight();
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = 0;
int iSpatialLayerNum = 1;
int iSliceNum = 1;
// prepare params
SEncParamExt sParam1;
SEncParamExt sParam2;
SEncParamExt sParam3;
encoder_->GetDefaultParams (&sParam1);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &sParam1);
sParam1.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare param2
memcpy (&sParam2, &sParam1, sizeof (SEncParamExt));
while (sParam2.iPicWidth == sParam1.iPicWidth) {
sParam2.iPicWidth = GetRandWidth();
}
prepareParam (iSpatialLayerNum, iSliceNum, sParam2.iPicWidth, sParam2.iPicHeight, fFrameRate, &sParam2);
sParam2.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare param3
memcpy (&sParam3, &sParam1, sizeof (SEncParamExt));
while (sParam3.iPicWidth == sParam1.iPicWidth || sParam3.iPicWidth == sParam2.iPicWidth) {
sParam3.iPicWidth = GetRandWidth();
}
prepareParam (iSpatialLayerNum, iSliceNum, sParam3.iPicWidth, sParam3.iPicHeight, fFrameRate, &sParam3);
sParam3.iSpsPpsIdStrategy = SPS_PPS_LISTING;
//prepare output if needed
FILE* fEnc = NULL;
#ifdef DEBUG_FILE_SAVE5
fEnc = fopen ("enc4.264", "wb");
#endif
// step#1: ordinary encoding
int rv = encoder_->InitializeExt (&sParam1);
ASSERT_TRUE (rv == cmResultSuccess) << "InitializeExt: rv = " << rv << " at " << sParam1.iPicWidth << "x" <<
sParam1.iPicHeight;
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam2);
ASSERT_TRUE (rv == cmResultSuccess) << "SetOption Failed sParam2: rv = " << rv;
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
// step#2: set strategy for success
int32_t iNewStra = SPS_PPS_LISTING;
rv = encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iNewStra);
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv << " iNewStra=" << iNewStra;
// step#3: setting new strategy, SHOULD encounter ERROR
unsigned int TraceLevel = WELS_LOG_QUIET;
rv = encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &TraceLevel);
ASSERT_TRUE (rv == cmResultSuccess);
iNewStra = CONSTANT_ID;
rv = encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iNewStra);
ASSERT_TRUE (rv != cmResultSuccess);
EncDecOneFrame (sParam2.iPicWidth, sParam2.iPicHeight, iEncFrameNum++, fEnc);
// step#4: pParam3, SHOULD encounter ERROR
rv = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sParam3);
ASSERT_TRUE (rv != cmResultSuccess) << "SetOption: rv = " << rv << " at " << sParam3.iPicWidth << "x" <<
sParam3.iPicHeight;
rv = encoder_->Uninitialize();
ASSERT_TRUE (rv == cmResultSuccess) << "rv = " << rv;
#ifdef DEBUG_FILE_SAVE5
fclose (fEnc);
#endif
}

View File

@ -0,0 +1,122 @@
#include <stdlib.h>
#include "gtest/gtest.h"
#include "au_set.h"
#include "param_svc.h"
#include "parameter_sets.h"
#include "wels_const.h"
using namespace WelsEnc;
class ParameterSetStrategyTest : public ::testing::Test {
public:
virtual void SetUp() {
pMa = NULL;
m_pSpsArray = NULL;
m_pSubsetArray = NULL;
pMa = new CMemoryAlign (0);
m_pSpsArray = (SWelsSPS*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SWelsSPS), "m_pSpsArray");
ASSERT_TRUE (NULL != m_pSpsArray);
m_pSubsetArray = (SSubsetSps*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SSubsetSps), "m_pSubsetArray");
ASSERT_TRUE (NULL != m_pSubsetArray);
m_pSpsArrayPointer = &m_pSpsArray[0];
m_pSubsetArrayPointer = &m_pSubsetArray[0];
}
virtual void TearDown() {
pMa->WelsFree (m_pSpsArray, "m_pSpsArray");
pMa->WelsFree (m_pSubsetArray, "m_pSubsetArray");
delete pMa;
}
void GenerateParam (SWelsSvcCodingParam* pParam);
public:
CMemoryAlign* pMa;
SWelsSPS* m_pSpsArray;
SSubsetSps* m_pSubsetArray;
SWelsSPS* m_pSpsArrayPointer;
SSubsetSps* m_pSubsetArrayPointer;
};
void ParameterSetStrategyTest::GenerateParam (SWelsSvcCodingParam* pParam) {
SEncParamBase sEncParamBase;
//TODO: consider randomize it
sEncParamBase.iUsageType = CAMERA_VIDEO_REAL_TIME;
sEncParamBase.iPicWidth = 1280;
sEncParamBase.iPicHeight = 720;
sEncParamBase.iTargetBitrate = 1000000;
sEncParamBase.iRCMode = RC_BITRATE_MODE;
sEncParamBase.fMaxFrameRate = 30.0f;
pParam->ParamBaseTranscode (sEncParamBase);
}
TEST_F (ParameterSetStrategyTest, FindExistingSps) {
int iDlayerIndex = 0;
int iDlayerCount = 0;
bool bUseSubsetSps = false;
int iFoundId = -1;
int iRet = 0;
SSpatialLayerConfig* pDlayerParam;
//init parameter
SWelsSvcCodingParam sParam1;
GenerateParam (&sParam1);
//prepare first SPS
int iCurSpsId = 0;
int iCurSpsInUse = 1;
m_pSpsArrayPointer = &m_pSpsArray[iCurSpsId];
pDlayerParam = & (sParam1.sSpatialLayers[iDlayerIndex]);
iRet = WelsInitSps (m_pSpsArrayPointer, pDlayerParam, &sParam1.sDependencyLayers[iDlayerIndex], sParam1.uiIntraPeriod,
sParam1.iMaxNumRefFrame,
iCurSpsId, sParam1.bEnableFrameCroppingFlag, sParam1.iRCMode != RC_OFF_MODE, iDlayerCount);
// try finding #0
iFoundId = FindExistingSps (&sParam1, bUseSubsetSps, iDlayerIndex, iDlayerCount, iCurSpsInUse,
m_pSpsArray, m_pSubsetArray);
EXPECT_EQ (iFoundId, iCurSpsId);
// try not finding
SWelsSvcCodingParam sParam2 = sParam1;
sParam2.iMaxNumRefFrame ++;
iFoundId = FindExistingSps (&sParam2, bUseSubsetSps, iDlayerIndex, iDlayerCount, iCurSpsInUse,
m_pSpsArray, m_pSubsetArray);
EXPECT_EQ (iFoundId, INVALID_ID);
// add new sps
iCurSpsId = 1;
m_pSpsArrayPointer = &m_pSpsArray[iCurSpsId];
pDlayerParam = & (sParam2.sSpatialLayers[iDlayerIndex]);
iRet = WelsInitSps (m_pSpsArrayPointer, pDlayerParam, &sParam2.sDependencyLayers[iDlayerIndex], sParam2.uiIntraPeriod,
sParam2.iMaxNumRefFrame,
iCurSpsId, sParam2.bEnableFrameCroppingFlag, sParam2.iRCMode != RC_OFF_MODE, iDlayerCount);
iCurSpsInUse = 2;
// try finding #1
iFoundId = FindExistingSps (&sParam2, bUseSubsetSps, iDlayerIndex, iDlayerCount, iCurSpsInUse,
m_pSpsArray, m_pSubsetArray);
EXPECT_EQ (iFoundId, iCurSpsId);
// try finding #0
iFoundId = FindExistingSps (&sParam1, bUseSubsetSps, iDlayerIndex, iDlayerCount, iCurSpsInUse,
m_pSpsArray, m_pSubsetArray);
EXPECT_EQ (iFoundId, 0);
// try not finding
if (sParam2.sDependencyLayers[0].iActualWidth > 1) {
sParam2.sDependencyLayers[0].iActualWidth--;
} else {
sParam2.sDependencyLayers[0].iActualWidth++;
}
iFoundId = FindExistingSps (&sParam2, bUseSubsetSps, iDlayerIndex, iDlayerCount, iCurSpsInUse,
m_pSpsArray, m_pSubsetArray);
EXPECT_EQ (iFoundId, INVALID_ID);
}

View File

@ -11,6 +11,7 @@ ENCODER_UNITTEST_CPP_SRCS=\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_MemoryAlloc.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_MemoryZero.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_MotionEstimate.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_ParameterSetStrategy.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_Reconstruct.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_Sample.cpp\
$(ENCODER_UNITTEST_SRCDIR)/EncUT_SVC_me.cpp\