ref: 98ed30299067aaac1b45020671b2368b6e499d91
parent: e9ec603fd7932087932c092ed28348380726f3ae
author: Sijia Chen <sijchen@cisco.com>
date: Thu Jan 15 13:04:39 EST 2015
add new SpsPpsStrategy and UT
--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -385,6 +385,17 @@
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 @@
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
--- a/codec/console/enc/src/welsenc.cpp
+++ b/codec/console/enc/src/welsenc.cpp
@@ -232,8 +232,8 @@
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 @@
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 @@
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;
--- a/codec/encoder/core/inc/au_set.h
+++ b/codec/encoder/core/inc/au_set.h
@@ -141,8 +141,26 @@
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__
--- a/codec/encoder/core/inc/encoder.h
+++ b/codec/encoder/core/inc/encoder.h
@@ -48,7 +48,7 @@
* \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
--- a/codec/encoder/core/inc/encoder_context.h
+++ b/codec/encoder/core/inc/encoder_context.h
@@ -191,6 +191,7 @@
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 @@
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)
--- a/codec/encoder/core/inc/extern.h
+++ b/codec/encoder/core/inc/extern.h
@@ -75,7 +75,8 @@
* \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
--- a/codec/encoder/core/inc/param_svc.h
+++ b/codec/encoder/core/inc/param_svc.h
@@ -162,7 +162,7 @@
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 @@
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];
@@ -476,6 +476,18 @@
}
} 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)
--- a/codec/encoder/core/inc/wels_common_basis.h
+++ b/codec/encoder/core/inc/wels_common_basis.h
@@ -83,9 +83,15 @@
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;
--- a/codec/encoder/core/inc/wels_const.h
+++ b/codec/encoder/core/inc/wels_const.h
@@ -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
--- a/codec/encoder/core/src/au_set.cpp
+++ b/codec/encoder/core/src/au_set.cpp
@@ -336,27 +336,27 @@
* \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
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -323,6 +323,12 @@
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 @@
++ 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,9 +857,9 @@
}
}
-int32_t WelsGenerateNewSps (sWelsEncCtx* pCtx, const bool kbUseSubsetSps, const int32_t iDlayerIndex,
- const int32_t iDlayerCount, const int32_t kiSpsId,
- SWelsSPS*& pSps, SSubsetSps*& pSubsetSps) {
+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;
if (!kbUseSubsetSps) {
@@ -866,9 +876,6 @@
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 @@
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,16 +1171,53 @@
}
// 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)->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");
+ (*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,13 +1229,80 @@
pDqIdc->uiSpatialId = iDlayerIndex;
- WelsGenerateNewSps (*ppCtx, bUseSubsetSps, iDlayerIndex,
- iDlayerCount, iSpsId, pSps, pSubsetSps);
+ 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);
- pPps = & (*ppCtx)->pPPSArray[iPpsId];
- // initialize pPps
- WelsInitPps (pPps, pSps, pSubsetSps, iPpsId, true, bUseSubsetSps, pParam->iEntropyCodingModeFlag != 0);
+ 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
{
iResult = InitSlicePEncCtx (& (*ppCtx)->pSliceCtxList[iDlayerIndex],
@@ -1085,7 +1315,7 @@
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 @@
if (bUseSubsetSps)
++ iSpsId;
++ iPpsId;
- ++ (*ppCtx)->iSpsNum;
+ 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 @@
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 @@
//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 @@
* \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 @@
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 @@
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,46 +3115,68 @@
/* 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;
- /* generate Subset SPS */
- WelsLoadNal (pCtx->pOut, NAL_UNIT_SUBSET_SPS, NRI_PRI_HIGHEST);
+ 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);
- WelsWriteSubsetSpsSyntax (&pCtx->pSubsetArray[iId], &pCtx->pOut->sBsWrite,
- & (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_SUBSETSPS].iParaSetIdDelta[0]));
- WelsUnloadNal (pCtx->pOut);
- } else {
- iId = 0;
+ 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;
- /* 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);
+ 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);
+
+ WelsWriteSubsetSpsSyntax (&pCtx->pSubsetArray[iId], &pCtx->pOut->sBsWrite,
+ & (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_SUBSETSPS].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,
@@ -2921,8 +3193,30 @@
/* 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 @@
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 @@
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 @@
(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,21 +4171,53 @@
}
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
@@ -3897,14 +4224,22 @@
(*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 @@
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;
--- a/codec/encoder/core/src/svc_encode_slice.cpp
+++ b/codec/encoder/core/src/svc_encode_slice.cpp
@@ -237,7 +237,8 @@
}
}
-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 @@
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 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 @@
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 @@
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 ];
--- a/codec/encoder/plus/src/welsEncoderExt.cpp
+++ b/codec/encoder/plus/src/welsEncoderExt.cpp
@@ -332,7 +332,7 @@
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 @@
}
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
"CWelsH264SVCEncoder::ForceIntraFrame(), bIDR= %d", bIDR);
+
ForceCodingIDR (m_pEncContext);
m_pEncContext->sEncoderStatistics.uiIDRReqNum++;
@@ -486,8 +487,8 @@
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 @@
pParam->iSpatialLayerNum,
pParam->fMaxFrameRate,
pParam->uiIntraPeriod,
- pParam->bEnableSpsPpsIdAddition,
+ pParam->iSpsPpsIdStrategy,
pParam->bPrefixNalAddingCtrl,
pParam->bEnableDenoise,
pParam->bEnableBackgroundDetection,
@@ -513,7 +514,9 @@
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 @@
#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 @@
}
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: {
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -88,26 +88,25 @@
BaseDecoderTest::TearDown();
}
- virtual void prepareParam (int iLayers, int iSlices, int width, int height, float framerate) {
- memset (¶m_, 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 @@
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 @@
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 @@
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 @@
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 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -498,7 +524,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -535,7 +561,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -554,7 +580,8 @@
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 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -809,7 +836,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -868,7 +895,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -918,7 +945,7 @@
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, ¶m_);
param_.bEnableLongTermReference = true;
param_.iLTRRefNum = 1;
encoder_->Uninitialize();
@@ -985,7 +1012,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -1036,7 +1063,7 @@
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, ¶m_);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -1086,7 +1113,7 @@
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, ¶m_);
param_.bPrefixNalAddingCtrl = false;
param_.iTemporalLayerNum = (rand() % 4) + 1;
encoder_->Uninitialize();
@@ -1155,7 +1182,7 @@
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, ¶m_);
param_.bPrefixNalAddingCtrl = true;
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 1;
@@ -1210,7 +1237,7 @@
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, ¶m_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 2;
encoder_->Uninitialize();
@@ -1266,7 +1293,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (¶m_);
@@ -1330,7 +1357,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -1393,7 +1420,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -1473,7 +1500,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -1612,7 +1639,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -1745,7 +1772,7 @@
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, ¶m_);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -1914,7 +1941,7 @@
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, ¶m_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
@@ -1979,7 +2006,7 @@
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, ¶m_);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
@@ -2065,7 +2092,7 @@
int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
int iSliceNum = 1;
encoder_->GetDefaultParams (¶m_);
- prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate);
+ prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, ¶m_);
int rv = encoder_->InitializeExt (¶m_);
ASSERT_TRUE (rv == cmResultSuccess);
@@ -2128,8 +2155,8 @@
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 @@
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, ¶m_);
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 @@
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, ¶m_);
param_.iSpatialLayerNum = kiTotalLayer;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -2475,7 +2502,7 @@
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, ¶m_);
param_.iSpatialLayerNum = iLayerNum;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (¶m_);
@@ -2523,5 +2550,436 @@
}
iFrame++;
} //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
}
--- /dev/null
+++ b/test/encoder/EncUT_ParameterSetStrategy.cpp
@@ -1,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);
+}
+
+
--- a/test/encoder/targets.mk
+++ b/test/encoder/targets.mk
@@ -11,6 +11,7 @@
$(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\