shithub: openh264

Download patch

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 (&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 @@
       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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   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, &param_);
   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, &param_);
   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, &param_);
   param_.iSpatialLayerNum = 1;
 
   int rv = encoder_->InitializeExt (&param_);
@@ -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, &param_);
   param_.iSpatialLayerNum = 1;
   int rv = encoder_->InitializeExt (&param_);
   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, &param_);
   param_.iSpatialLayerNum = 1;
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
@@ -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, &param_);
   param_.iSpatialLayerNum = 1;
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
@@ -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, &param_);
   param_.iSpatialLayerNum = 1;
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
@@ -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, &param_);
   param_.iSpatialLayerNum = 1;
   encoder_->Uninitialize();
   int rv = encoder_->InitializeExt (&param_);
@@ -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, &param_);
   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, &param_);
   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 (&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 @@
     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, &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 @@
   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 @@
   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_);
@@ -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\