/*!
 * \copy
 *     Copyright (c)  2009-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * \file	au_parser.c
 *
 * \brief	Interfaces introduced in Access Unit level based parser
 *
 * \date	03/10/2009 Created
 *
 *************************************************************************************
 */
#include "codec_def.h"
#include "au_parser.h"
#include "decoder.h"
#include "error_code.h"
#include "memmgr_nal_unit.h"
#include "decoder_core.h"
#include "bit_stream.h"
#include "mem_align.h"

namespace WelsDec {
/*!
 *************************************************************************************
 * \brief	Start Code Prefix (0x 00 00 00 01) detection
 *
 * \param 	pBuf		bitstream payload buffer
 * \param	pOffset		offset between NAL rbsp and original bitsteam that
 * 				start code prefix is seperated from.
 * \param	iBufSize	count size of buffer
 *
 * \return	RBSP buffer of start code prefix exclusive
 *
 * \note	N/A
 *************************************************************************************
 */
uint8_t* DetectStartCodePrefix (const uint8_t* kpBuf, int32_t* pOffset, int32_t iBufSize) {
  uint8_t* pBits = (uint8_t*)kpBuf;

  do {
    int32_t iIdx = 0;
    while ((iIdx < iBufSize) && (! (*pBits))) {
      ++ pBits;
      ++ iIdx;
    }
    if (iIdx >= iBufSize)  break;

    ++ iIdx;
    ++ pBits;

    if ((iIdx >= 3) && ((* (pBits - 1)) == 0x1)) {
      *pOffset = (int32_t) (((uintptr_t)pBits) - ((uintptr_t)kpBuf));
      return pBits;
    }

    iBufSize -= iIdx;
  }  while (1);

  return NULL;
}

/*!
 *************************************************************************************
 * \brief	to parse nal unit
 *
 * \param	pCtx		    decoder context
 * \param 	pNalUnitHeader	parsed result of NAL Unit Header to output
 * \param   pSrcRbsp        bitstream buffer to input
 * \param   iSrcRbspLen     length size of bitstream buffer payload
 * \param	pSrcNal
 * \param	iSrcNalLen
 * \param	pConsumedBytes	consumed bytes during parsing
 *
 * \return	decoded bytes payload, might be (pSrcRbsp+1) if no escapes
 *
 * \note	N/A
 *************************************************************************************
 */
uint8_t* ParseNalHeader (PWelsDecoderContext pCtx, SNalUnitHeader* pNalUnitHeader, uint8_t* pSrcRbsp,
                         int32_t iSrcRbspLen, uint8_t* pSrcNal, int32_t iSrcNalLen, int32_t* pConsumedBytes) {
  PNalUnit pCurNal = NULL;
  uint8_t* pNal     = pSrcRbsp;
  int32_t iNalSize  = iSrcRbspLen;
  PBitStringAux pBs = NULL;
  bool bExtensionFlag = false;
  int32_t iErr	= ERR_NONE;
  int32_t iBitSize = 0;
  SDataBuffer* pSavedData = &pCtx->sSavedData;
  SLogContext* pLogCtx = & (pCtx->sLogCtx);
  pNalUnitHeader->eNalUnitType = NAL_UNIT_UNSPEC_0;//SHOULD init it. because pCtx->sCurNalHead is common variable.

  //remove the consecutive ZERO at the end of current NAL in the reverse order.--2011.6.1
  {
    int32_t iIndex = iSrcRbspLen - 1;
    uint8_t uiBsZero = 0;
    while (iIndex >= 0) {
      uiBsZero = pSrcRbsp[iIndex];
      if (0 == uiBsZero) {
        --iNalSize;
        --iIndex;
      } else {
        break;
      }
    }
  }

  pNalUnitHeader->uiForbiddenZeroBit	= (uint8_t) (pNal[0] >> 7);			// uiForbiddenZeroBit
  if (pNalUnitHeader->uiForbiddenZeroBit) { //2010.4.14
    pCtx->iErrorCode |= dsBitstreamError;
    return NULL; //uiForbiddenZeroBit should always equal to 0
  }

  pNalUnitHeader->uiNalRefIdc		= (uint8_t) (pNal[0] >> 5);			// uiNalRefIdc
  pNalUnitHeader->eNalUnitType		= (EWelsNalUnitType) (pNal[0] & 0x1f);	// eNalUnitType

  ++pNal;
  --iNalSize;
  ++ (*pConsumedBytes);

  if (! (IS_SEI_NAL (pNalUnitHeader->eNalUnitType) || IS_SPS_NAL (pNalUnitHeader->eNalUnitType)
         || pCtx->bSpsExistAheadFlag)) {
    if (pCtx->bPrintFrameErrorTraceFlag) {
      WelsLog (pLogCtx, WELS_LOG_WARNING,
               "parse_nal(), no exist Sequence Parameter Sets ahead of sequence when try to decode NAL(type:%d).",
               pNalUnitHeader->eNalUnitType);
    }
    pCtx->iErrorCode	= dsNoParamSets;
    return NULL;
  }
  if (! (IS_SEI_NAL (pNalUnitHeader->eNalUnitType) || IS_PARAM_SETS_NALS (pNalUnitHeader->eNalUnitType)
         || pCtx->bPpsExistAheadFlag)) {
    if (pCtx->bPrintFrameErrorTraceFlag) {
      WelsLog (pLogCtx, WELS_LOG_WARNING,
               "parse_nal(), no exist Picture Parameter Sets ahead of sequence when try to decode NAL(type:%d).",
               pNalUnitHeader->eNalUnitType);
    }
    pCtx->iErrorCode	= dsNoParamSets;
    return NULL;
  }
  if ((IS_VCL_NAL_AVC_BASE (pNalUnitHeader->eNalUnitType) && ! (pCtx->bSpsExistAheadFlag || pCtx->bPpsExistAheadFlag)) ||
      (IS_NEW_INTRODUCED_SVC_NAL (pNalUnitHeader->eNalUnitType) && ! (pCtx->bSpsExistAheadFlag || pCtx->bSubspsExistAheadFlag
          || pCtx->bPpsExistAheadFlag))) {
    if (pCtx->bPrintFrameErrorTraceFlag) {
      WelsLog (pLogCtx, WELS_LOG_WARNING,
               "ParseNalHeader(), no exist Parameter Sets ahead of sequence when try to decode slice(type:%d).",
               pNalUnitHeader->eNalUnitType);
    }
    pCtx->iErrorCode	|= dsNoParamSets;
    return NULL;
  }


  switch (pNalUnitHeader->eNalUnitType) {
  case NAL_UNIT_SEI:
    if (pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
      pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1;
      pCtx->bAuReadyFlag = true;
    }
    break;

  case NAL_UNIT_PREFIX:
    pCurNal = &pCtx->sPrefixNal;
    pCurNal->uiTimeStamp = pCtx->uiTimeStamp;

    if (iNalSize < NAL_UNIT_HEADER_EXT_SIZE) {
      PAccessUnit pCurAu	   = pCtx->pAccessUnitList;
      uint32_t uiAvailNalNum = pCurAu->uiAvailUnitsNum;

      if (uiAvailNalNum > 0) {
        pCurAu->uiEndPos = uiAvailNalNum - 1;
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
          pCtx->bAuReadyFlag = true;
        }
      }
      pCurNal->sNalData.sPrefixNal.bPrefixNalCorrectFlag = false;
      pCtx->iErrorCode |= dsBitstreamError;
      return NULL;
    }

    DecodeNalHeaderExt (pCurNal, pNal);
    if ((pCurNal->sNalHeaderExt.uiQualityId != 0) || (pCurNal->sNalHeaderExt.bUseRefBasePicFlag != 0)) {
      WelsLog (pLogCtx, WELS_LOG_WARNING,
               "ParseNalHeader() in Prefix Nal Unit:uiQualityId (%d) != 0, bUseRefBasePicFlag (%d) != 0, not supported!",
               pCurNal->sNalHeaderExt.uiQualityId, pCurNal->sNalHeaderExt.bUseRefBasePicFlag);
      PAccessUnit pCurAu	   = pCtx->pAccessUnitList;
      uint32_t uiAvailNalNum = pCurAu->uiAvailUnitsNum;

      if (uiAvailNalNum > 0) {
        pCurAu->uiEndPos = uiAvailNalNum - 1;
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
          pCtx->bAuReadyFlag = true;
        }
      }
      pCurNal->sNalData.sPrefixNal.bPrefixNalCorrectFlag = false;
      pCtx->iErrorCode |= dsBitstreamError;
      return NULL;
    }

    pNal            += NAL_UNIT_HEADER_EXT_SIZE;
    iNalSize        -= NAL_UNIT_HEADER_EXT_SIZE;
    *pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE;

    pCurNal->sNalHeaderExt.sNalUnitHeader.uiForbiddenZeroBit = pNalUnitHeader->uiForbiddenZeroBit;
    pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc		  = pNalUnitHeader->uiNalRefIdc;
    pCurNal->sNalHeaderExt.sNalUnitHeader.eNalUnitType	      = pNalUnitHeader->eNalUnitType;
    if (pNalUnitHeader->uiNalRefIdc != 0) {
      pBs = &pCtx->sBs;
      iBitSize = (iNalSize << 3) - BsGetTrailingBits (pNal + iNalSize - 1); // convert into bit

      iErr = InitBits (pBs, pNal, iBitSize);
      if (iErr) {
        WelsLog (pLogCtx, WELS_LOG_ERROR, "NAL_UNIT_PREFIX: InitBits() fail due invalid access.");
        pCtx->iErrorCode	|= dsBitstreamError;
        return NULL;
      }
      ParsePrefixNalUnit (pCtx, pBs);
    }
    pCurNal->sNalData.sPrefixNal.bPrefixNalCorrectFlag = true;

    break;
  case NAL_UNIT_CODED_SLICE_EXT:
    bExtensionFlag = true;
  case NAL_UNIT_CODED_SLICE:
  case NAL_UNIT_CODED_SLICE_IDR: {
    PAccessUnit pCurAu		= NULL;
    uint32_t uiAvailNalNum;
    pCurNal = MemGetNextNal (&pCtx->pAccessUnitList);
    if (NULL == pCurNal) {
      WelsLog (pLogCtx, WELS_LOG_ERROR, "MemGetNextNal() fail due out of memory.");
      pCtx->iErrorCode	|= dsOutOfMemory;
      return NULL;
    }
    pCurNal->uiTimeStamp = pCtx->uiTimeStamp;
    pCurNal->sNalHeaderExt.sNalUnitHeader.uiForbiddenZeroBit = pNalUnitHeader->uiForbiddenZeroBit;
    pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc		  = pNalUnitHeader->uiNalRefIdc;
    pCurNal->sNalHeaderExt.sNalUnitHeader.eNalUnitType	  = pNalUnitHeader->eNalUnitType;
    pCurAu	      = pCtx->pAccessUnitList;
    uiAvailNalNum = pCurAu->uiAvailUnitsNum;


    if (pNalUnitHeader->eNalUnitType == NAL_UNIT_CODED_SLICE_EXT) {
      if (iNalSize < NAL_UNIT_HEADER_EXT_SIZE) {
        ForceClearCurrentNal (pCurAu);

        if (uiAvailNalNum > 1) {
          pCurAu->uiEndPos = uiAvailNalNum - 2;
          if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
            pCtx->bAuReadyFlag = true;
          }
        }
        pCtx->iErrorCode |= dsBitstreamError;
        return NULL;
      }

      DecodeNalHeaderExt (pCurNal, pNal);
      if (pCurNal->sNalHeaderExt.uiQualityId != 0 ||
          pCurNal->sNalHeaderExt.bUseRefBasePicFlag) {
        if (pCurNal->sNalHeaderExt.uiQualityId != 0)
          WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseNalHeader():uiQualityId (%d) != 0, MGS not supported!",
                   pCurNal->sNalHeaderExt.uiQualityId);
        if (pCurNal->sNalHeaderExt.bUseRefBasePicFlag != 0)
          WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseNalHeader():bUseRefBasePicFlag (%d) != 0, MGS not supported!",
                   pCurNal->sNalHeaderExt.bUseRefBasePicFlag);

        ForceClearCurrentNal (pCurAu);

        if (uiAvailNalNum > 1) {
          pCurAu->uiEndPos = uiAvailNalNum - 2;
          if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
            pCtx->bAuReadyFlag = true;
          }
        }
        pCtx->iErrorCode |= dsBitstreamError;
        return NULL;
      }
      pNal            += NAL_UNIT_HEADER_EXT_SIZE;
      iNalSize        -= NAL_UNIT_HEADER_EXT_SIZE;
      *pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE;

      if (pCtx->bParseOnly) {
        pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
        int32_t iTrailingZeroByte = 0;
        while (pSrcNal[iSrcNalLen - iTrailingZeroByte - 1] == 0x0) //remove final trailing 0 bytes
          iTrailingZeroByte++;
        int32_t iActualLen = iSrcNalLen - iTrailingZeroByte;
        pCurNal->sNalData.sVclNal.iNalLength = iActualLen - NAL_UNIT_HEADER_EXT_SIZE;
        //unify start code as 0x0001
        int32_t iCurrStartByte = 4; //4 for 0x0001, 3 for 0x001
        if (pSrcNal[0] == 0x0 && pSrcNal[1] == 0x0 && pSrcNal[2] == 0x1) { //if 0x001
          iCurrStartByte = 3;
          pCurNal->sNalData.sVclNal.iNalLength++;
        }
        if (pCurNal->sNalHeaderExt.bIdrFlag) {
          * (pSrcNal + iCurrStartByte) &= 0xE0;
          * (pSrcNal + iCurrStartByte) |= 0x05;
        } else {
          * (pSrcNal + iCurrStartByte) &= 0xE0;
          * (pSrcNal + iCurrStartByte) |= 0x01;
        }
        pSavedData->pCurPos[0] = pSavedData->pCurPos[1] = pSavedData->pCurPos[2] = 0x0;
        pSavedData->pCurPos[3] = 0x1;
        pSavedData->pCurPos[4] = * (pSrcNal + iCurrStartByte);
        pSavedData->pCurPos += 5;
        int32_t iOffset = iCurrStartByte + 1 + NAL_UNIT_HEADER_EXT_SIZE;
        memcpy (pSavedData->pCurPos, pSrcNal + iOffset, iActualLen - iOffset);
        pSavedData->pCurPos += iActualLen - iOffset;
      }
    } else {
      if (pCtx->bParseOnly) {
        pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
        int32_t iTrailingZeroByte = 0;
        while (pSrcNal[iSrcNalLen - iTrailingZeroByte - 1] == 0x0) //remove final trailing 0 bytes
          iTrailingZeroByte++;
        int32_t iActualLen = iSrcNalLen - iTrailingZeroByte;
        pCurNal->sNalData.sVclNal.iNalLength = iActualLen;
        //unify start code as 0x0001
        int32_t iStartDeltaByte = 0; //0 for 0x0001, 1 for 0x001
        if (pSrcNal[0] == 0x0 && pSrcNal[1] == 0x0 && pSrcNal[2] == 0x1) { //if 0x001
          pSavedData->pCurPos[0] = 0x0;
          iStartDeltaByte = 1;
          pCurNal->sNalData.sVclNal.iNalLength++;
        }
        memcpy (pSavedData->pCurPos + iStartDeltaByte, pSrcNal, iActualLen);
        pSavedData->pCurPos += iStartDeltaByte + iActualLen;
      }
      if (NAL_UNIT_PREFIX == pCtx->sPrefixNal.sNalHeaderExt.sNalUnitHeader.eNalUnitType) {
        if (pCtx->sPrefixNal.sNalData.sPrefixNal.bPrefixNalCorrectFlag) {
          PrefetchNalHeaderExtSyntax (pCtx, pCurNal, &pCtx->sPrefixNal);
        }
      }

      pCurNal->sNalHeaderExt.bIdrFlag = (NAL_UNIT_CODED_SLICE_IDR == pNalUnitHeader->eNalUnitType) ? true :
                                        false;   //SHOULD update this flag for AVC if no prefix NAL
      pCurNal->sNalHeaderExt.iNoInterLayerPredFlag = 1;
    }

    pBs = &pCurAu->pNalUnitsList[uiAvailNalNum - 1]->sNalData.sVclNal.sSliceBitsRead;
    iBitSize = (iNalSize << 3) - BsGetTrailingBits (pNal + iNalSize - 1); // convert into bit
    iErr = InitBits (pBs, pNal, iBitSize);
    if (iErr) {
      ForceClearCurrentNal (pCurAu);
      if (uiAvailNalNum > 1) {
        pCurAu->uiEndPos = uiAvailNalNum - 2;
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
          pCtx->bAuReadyFlag = true;
        }
      }
      WelsLog (pLogCtx, WELS_LOG_ERROR, "NAL_UNIT_CODED_SLICE: InitBits() fail due invalid access.");
      pCtx->iErrorCode	|= dsBitstreamError;
      return NULL;
    }
    iErr = ParseSliceHeaderSyntaxs (pCtx, pBs, bExtensionFlag);
    if (iErr != ERR_NONE) {
      if ((uiAvailNalNum == 1) && (pCurNal->sNalHeaderExt.bIdrFlag)) { //IDR parse error
        ResetActiveSPSForEachLayer (pCtx);
      }
      //if current NAL occur error when parsing, should clean it from pNalUnitsList
      //otherwise, when Next good NAL decoding, this corrupt NAL is considered as normal NAL and lead to decoder crash
      ForceClearCurrentNal (pCurAu);

      if (uiAvailNalNum > 1) {
        pCurAu->uiEndPos = uiAvailNalNum - 2;
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) {
          pCtx->bAuReadyFlag = true;
        }
      }
      pCtx->iErrorCode |= dsBitstreamError;
      return NULL;
    }

    if ((uiAvailNalNum == 1)
        && CheckNextAuNewSeq (pCtx, pCurNal, pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps)) {
      ResetActiveSPSForEachLayer (pCtx);
    }
    if ((uiAvailNalNum > 1) &&
        CheckAccessUnitBoundary (pCtx, pCurAu->pNalUnitsList[uiAvailNalNum - 1], pCurAu->pNalUnitsList[uiAvailNalNum - 2],
                                 pCurAu->pNalUnitsList[uiAvailNalNum - 1]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps)) {
      pCurAu->uiEndPos = uiAvailNalNum - 2;
      pCtx->bAuReadyFlag = true;
      pCtx->bNextNewSeqBegin = CheckNextAuNewSeq (pCtx, pCurNal, pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps);

    }
  }
  break;
  default:
    break;
  }

  return pNal;
}


bool CheckAccessUnitBoundaryExt (PNalUnitHeaderExt pLastNalHdrExt, PNalUnitHeaderExt pCurNalHeaderExt,
                                 PSliceHeader pLastSliceHeader, PSliceHeader pCurSliceHeader) {
  const PSps kpSps = pCurSliceHeader->pSps;

  //Sub-clause 7.1.4.1.1 temporal_id
  if (pLastNalHdrExt->uiTemporalId != pCurNalHeaderExt->uiTemporalId) {
    return true;
  }

  // Subclause 7.4.1.2.5
  if (pLastSliceHeader->iRedundantPicCnt < pCurSliceHeader->iRedundantPicCnt)
    return false;
  else if (pLastSliceHeader->iRedundantPicCnt > pCurSliceHeader->iRedundantPicCnt)
    return true;

  // Subclause G7.4.1.2.4
  if (pLastNalHdrExt->uiDependencyId < pCurNalHeaderExt->uiDependencyId)
    return false;
  else if (pLastNalHdrExt->uiDependencyId > pCurNalHeaderExt->uiDependencyId)
    return true;
  if (pLastNalHdrExt->uiQualityId < pCurNalHeaderExt->uiQualityId)
    return false;
  else if (pLastNalHdrExt->uiQualityId > pCurNalHeaderExt->uiQualityId)
    return true;

  // Subclause 7.4.1.2.4
  if (pLastSliceHeader->iFrameNum != pCurSliceHeader->iFrameNum)
    return true;
  if (pLastSliceHeader->iPpsId != pCurSliceHeader->iPpsId)
    return true;
  if (pLastSliceHeader->pSps->iSpsId != pCurSliceHeader->pSps->iSpsId)
    return true;
  if (pLastSliceHeader->bFieldPicFlag != pCurSliceHeader->bFieldPicFlag)
    return true;
  if (pLastSliceHeader->bBottomFiledFlag != pCurSliceHeader->bBottomFiledFlag)
    return true;
  if ((pLastNalHdrExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) != (pCurNalHeaderExt->sNalUnitHeader.uiNalRefIdc !=
      NRI_PRI_LOWEST))
    return true;
  if (pLastNalHdrExt->bIdrFlag != pCurNalHeaderExt->bIdrFlag)
    return true;
  if (pCurNalHeaderExt->bIdrFlag) {
    if (pLastSliceHeader->uiIdrPicId != pCurSliceHeader->uiIdrPicId)
      return true;
  }
  if (kpSps->uiPocType == 0) {
    if (pLastSliceHeader->iPicOrderCntLsb != pCurSliceHeader->iPicOrderCntLsb)
      return true;
    if (pLastSliceHeader->iDeltaPicOrderCntBottom != pCurSliceHeader->iDeltaPicOrderCntBottom)
      return true;
  } else if (kpSps->uiPocType == 1) {
    if (pLastSliceHeader->iDeltaPicOrderCnt[0] != pCurSliceHeader->iDeltaPicOrderCnt[0])
      return true;
    if (pLastSliceHeader->iDeltaPicOrderCnt[1] != pCurSliceHeader->iDeltaPicOrderCnt[1])
      return true;
  }
  if (memcmp (pLastSliceHeader->pPps, pCurSliceHeader->pPps, sizeof (SPps)) != 0
      || memcmp (pLastSliceHeader->pSps, pCurSliceHeader->pSps, sizeof (SSps)) != 0) {
    return true;
  }
  return false;
}


bool CheckAccessUnitBoundary (PWelsDecoderContext pCtx, const PNalUnit kpCurNal, const PNalUnit kpLastNal,
                              const PSps kpSps) {
  const PNalUnitHeaderExt kpLastNalHeaderExt = &kpLastNal->sNalHeaderExt;
  const PNalUnitHeaderExt kpCurNalHeaderExt = &kpCurNal->sNalHeaderExt;
  const SSliceHeader* kpLastSliceHeader = &kpLastNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader;
  const SSliceHeader* kpCurSliceHeader = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader;
  if (pCtx->pActiveLayerSps[kpCurNalHeaderExt->uiDependencyId] != NULL
      && pCtx->pActiveLayerSps[kpCurNalHeaderExt->uiDependencyId] != kpSps) {
    return true; // the active sps changed, new sequence begins, so the current au is ready
  }

  //Sub-clause 7.1.4.1.1 temporal_id
  if (kpLastNalHeaderExt->uiTemporalId != kpCurNalHeaderExt->uiTemporalId) {
    return true;
  }
  if (kpLastSliceHeader->iFrameNum != kpCurSliceHeader->iFrameNum)
    return true;
  // Subclause 7.4.1.2.5
  if (kpLastSliceHeader->iRedundantPicCnt > kpCurSliceHeader->iRedundantPicCnt)
    return true;

  // Subclause G7.4.1.2.4
  if (kpLastNalHeaderExt->uiDependencyId > kpCurNalHeaderExt->uiDependencyId)
    return true;
  // Subclause 7.4.1.2.4
  if (kpLastNalHeaderExt->uiDependencyId == kpCurNalHeaderExt->uiDependencyId
      && kpLastSliceHeader->iPpsId != kpCurSliceHeader->iPpsId)
    return true;
  if (kpLastSliceHeader->bFieldPicFlag != kpCurSliceHeader->bFieldPicFlag)
    return true;
  if (kpLastSliceHeader->bBottomFiledFlag != kpCurSliceHeader->bBottomFiledFlag)
    return true;
  if ((kpLastNalHeaderExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) != (kpCurNalHeaderExt->sNalUnitHeader.uiNalRefIdc
      != NRI_PRI_LOWEST))
    return true;
  if (kpLastNalHeaderExt->bIdrFlag != kpCurNalHeaderExt->bIdrFlag)
    return true;
  if (kpCurNalHeaderExt->bIdrFlag) {
    if (kpLastSliceHeader->uiIdrPicId != kpCurSliceHeader->uiIdrPicId)
      return true;
  }
  if (kpSps->uiPocType == 0) {
    if (kpLastSliceHeader->iPicOrderCntLsb != kpCurSliceHeader->iPicOrderCntLsb)
      return true;
    if (kpLastSliceHeader->iDeltaPicOrderCntBottom != kpCurSliceHeader->iDeltaPicOrderCntBottom)
      return true;
  } else if (kpSps->uiPocType == 1) {
    if (kpLastSliceHeader->iDeltaPicOrderCnt[0] != kpCurSliceHeader->iDeltaPicOrderCnt[0])
      return true;
    if (kpLastSliceHeader->iDeltaPicOrderCnt[1] != kpCurSliceHeader->iDeltaPicOrderCnt[1])
      return true;
  }

  return false;
}

bool CheckNextAuNewSeq (PWelsDecoderContext pCtx, const PNalUnit kpCurNal, const PSps kpSps) {
  const PNalUnitHeaderExt kpCurNalHeaderExt = &kpCurNal->sNalHeaderExt;
  if (pCtx->pActiveLayerSps[kpCurNalHeaderExt->uiDependencyId] != NULL
      && pCtx->pActiveLayerSps[kpCurNalHeaderExt->uiDependencyId] != kpSps)
    return true;
  if (kpCurNalHeaderExt->bIdrFlag)
    return true;

  return false;
}

/*!
 *************************************************************************************
 * \brief	to parse NON VCL NAL Units
 *
 * \param 	pCtx		decoder context
 * \param	rbsp		rbsp buffer of NAL Unit
 * \param	src_len		length of rbsp buffer
 *
 * \return	0 - successed
 *	    	1 - failed
 *
 *************************************************************************************
 */
int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen, uint8_t* pSrcNal,
                        const int32_t kSrcNalLen) {
  PBitStringAux	pBs = NULL;
  EWelsNalUnitType eNalType	= NAL_UNIT_UNSPEC_0; // make initial value as unspecified
  int32_t iPicWidth		= 0;
  int32_t iPicHeight		= 0;
  int32_t iBitSize		= 0;
  int32_t iErr				= ERR_NONE;
  if (kiSrcLen <= 0)
    return iErr;

  pBs	     = &pCtx->sBs;	// SBitStringAux instance for non VCL NALs decoding
  iBitSize = (kiSrcLen << 3) - BsGetTrailingBits (pRbsp + kiSrcLen - 1); // convert into bit
  eNalType = pCtx->sCurNalHead.eNalUnitType;

  switch (eNalType) {
  case NAL_UNIT_SPS:
  case NAL_UNIT_SUBSET_SPS:
    if (iBitSize > 0) {
      iErr = InitBits (pBs, pRbsp, iBitSize);
      if (ERR_NONE != iErr) {
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
          pCtx->iErrorCode |= dsNoParamSets;
        else
          pCtx->iErrorCode |= dsBitstreamError;
        return iErr;
      }
    }
    iErr = ParseSps (pCtx, pBs, &iPicWidth, &iPicHeight, pSrcNal, kSrcNalLen);
    if (ERR_NONE != iErr) {	// modified for pSps/pSubsetSps invalid, 12/1/2009
      if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
        pCtx->iErrorCode |= dsNoParamSets;
      else
        pCtx->iErrorCode |= dsBitstreamError;
      return iErr;
    }

    break;

  case NAL_UNIT_PPS:
    if (iBitSize > 0) {
      iErr = InitBits (pBs, pRbsp, iBitSize);
      if (ERR_NONE != iErr) {
        if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
          pCtx->iErrorCode |= dsNoParamSets;
        else
          pCtx->iErrorCode |= dsBitstreamError;
        return iErr;
      }
    }
    iErr = ParsePps (pCtx, &pCtx->sPpsBuffer[0], pBs, pSrcNal, kSrcNalLen);
    if (ERR_NONE != iErr) {	// modified for pps invalid, 12/1/2009
      if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
        pCtx->iErrorCode |= dsNoParamSets;
      else
        pCtx->iErrorCode |= dsBitstreamError;
      return iErr;
    }

    pCtx->bPpsExistAheadFlag	= true;

    break;

  case NAL_UNIT_SEI:

    break;

  case NAL_UNIT_PREFIX:
    break;
  case NAL_UNIT_CODED_SLICE_DPA:
  case NAL_UNIT_CODED_SLICE_DPB:
  case NAL_UNIT_CODED_SLICE_DPC:

    break;

  default:
    break;
  }

  return iErr;
}

int32_t ParseRefBasePicMarking (PBitStringAux pBs, PRefBasePicMarking pRefBasePicMarking) {
  uint32_t uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_ref_base_pic_marking_mode_flag
  const bool kbAdaptiveMarkingModeFlag = !!uiCode;
  pRefBasePicMarking->bAdaptiveRefBasePicMarkingModeFlag = kbAdaptiveMarkingModeFlag;
  if (kbAdaptiveMarkingModeFlag) {
    int32_t iIdx = 0;
    do {
      WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //MMCO_base
      const uint32_t kuiMmco = uiCode;

      pRefBasePicMarking->mmco_base[iIdx].uiMmcoType	= kuiMmco;

      if (kuiMmco == MMCO_END)
        break;

      if (kuiMmco == MMCO_SHORT2UNUSED) {
        WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //difference_of_base_pic_nums_minus1
        pRefBasePicMarking->mmco_base[iIdx].uiDiffOfPicNums	= 1 + uiCode;
        pRefBasePicMarking->mmco_base[iIdx].iShortFrameNum	= 0;
      } else if (kuiMmco == MMCO_LONG2UNUSED) {
        WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_base_pic_num
        pRefBasePicMarking->mmco_base[iIdx].uiLongTermPicNum	= uiCode;
      }
      ++ iIdx;
    } while (iIdx < MAX_MMCO_COUNT);
  }
  return ERR_NONE;
}

int32_t ParsePrefixNalUnit (PWelsDecoderContext pCtx, PBitStringAux pBs) {
  PNalUnit pCurNal = &pCtx->sPrefixNal;
  uint32_t uiCode;

  if (pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc != 0) {
    PNalUnitHeaderExt head_ext = &pCurNal->sNalHeaderExt;
    PPrefixNalUnit sPrefixNal = &pCurNal->sNalData.sPrefixNal;
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //store_ref_base_pic_flag
    sPrefixNal->bStoreRefBasePicFlag	= !!uiCode;
    if ((head_ext->bUseRefBasePicFlag || sPrefixNal->bStoreRefBasePicFlag) && !head_ext->bIdrFlag) {
      WELS_READ_VERIFY (ParseRefBasePicMarking (pBs, &sPrefixNal->sRefPicBaseMarking));
    }
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //additional_prefix_nal_unit_extension_flag
    sPrefixNal->bPrefixNalUnitAdditionalExtFlag = !!uiCode;
    if (sPrefixNal->bPrefixNalUnitAdditionalExtFlag) {
      WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //additional_prefix_nal_unit_extension_data_flag
      sPrefixNal->bPrefixNalUnitExtFlag	= !!uiCode;
    }
  }
  return ERR_NONE;
}

#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_LEFT_OFFSET_MIN -32768
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_LEFT_OFFSET_MAX 32767
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_TOP_OFFSET_MIN -32768
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_TOP_OFFSET_MAX 32767
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_RIGHT_OFFSET_MIN -32768
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_RIGHT_OFFSET_MAX 32767
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_BOTTOM_OFFSET_MIN -32768
#define SUBSET_SPS_SEQ_SCALED_REF_LAYER_BOTTOM_OFFSET_MAX 32767




int32_t DecodeSpsSvcExt (PWelsDecoderContext pCtx, PSubsetSps pSpsExt, PBitStringAux pBs) {
  PSpsSvcExt  pExt			= NULL;
  uint32_t uiCode;
  int32_t iCode;

  pExt	= &pSpsExt->sSpsSvcExt;

  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //inter_layer_deblocking_filter_control_present_flag
  pExt->bInterLayerDeblockingFilterCtrlPresentFlag	= !!uiCode;
  WELS_READ_VERIFY (BsGetBits (pBs, 2, &uiCode)); //extended_spatial_scalability_idc
  pExt->uiExtendedSpatialScalability						= uiCode;
  if (pExt->uiExtendedSpatialScalability > 2) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING,
             "DecodeSpsSvcExt():extended_spatial_scalability (%d) != 0, ESS not supported!",
             pExt->uiExtendedSpatialScalability);
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_ESS);
  }

  pExt->uiChromaPhaseXPlus1Flag	=
    0;	// FIXME: Incoherent with JVT X201 standard (= 1), but conformance to JSVM (= 0) implementation.
  pExt->uiChromaPhaseYPlus1		= 1;

  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //chroma_phase_x_plus1_flag
  pExt->uiChromaPhaseXPlus1Flag	= uiCode;
  WELS_READ_VERIFY (BsGetBits (pBs, 2, &uiCode)); //chroma_phase_y_plus1
  pExt->uiChromaPhaseYPlus1		= uiCode;

  pExt->uiSeqRefLayerChromaPhaseXPlus1Flag	= pExt->uiChromaPhaseXPlus1Flag;
  pExt->uiSeqRefLayerChromaPhaseYPlus1		= pExt->uiChromaPhaseYPlus1;
  memset (&pExt->sSeqScaledRefLayer, 0, sizeof (SPosOffset));

  if (pExt->uiExtendedSpatialScalability == 1) {
    SPosOffset* const kpPos = &pExt->sSeqScaledRefLayer;
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //seq_ref_layer_chroma_phase_x_plus1_flag
    pExt->uiSeqRefLayerChromaPhaseXPlus1Flag	= uiCode;
    WELS_READ_VERIFY (BsGetBits (pBs, 2, &uiCode)); //seq_ref_layer_chroma_phase_y_plus1
    pExt->uiSeqRefLayerChromaPhaseYPlus1		= uiCode;

    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //seq_scaled_ref_layer_left_offset
    kpPos->iLeftOffset	= iCode;
    WELS_CHECK_SE_BOTH_WARNING (kpPos->iLeftOffset, SUBSET_SPS_SEQ_SCALED_REF_LAYER_LEFT_OFFSET_MIN,
                                SUBSET_SPS_SEQ_SCALED_REF_LAYER_LEFT_OFFSET_MAX, "seq_scaled_ref_layer_left_offset");
    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //seq_scaled_ref_layer_top_offset
    kpPos->iTopOffset	= iCode;
    WELS_CHECK_SE_BOTH_WARNING (kpPos->iTopOffset, SUBSET_SPS_SEQ_SCALED_REF_LAYER_TOP_OFFSET_MIN,
                                SUBSET_SPS_SEQ_SCALED_REF_LAYER_TOP_OFFSET_MAX, "seq_scaled_ref_layer_top_offset");
    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //seq_scaled_ref_layer_right_offset
    kpPos->iRightOffset	= iCode;
    WELS_CHECK_SE_BOTH_WARNING (kpPos->iRightOffset, SUBSET_SPS_SEQ_SCALED_REF_LAYER_RIGHT_OFFSET_MIN,
                                SUBSET_SPS_SEQ_SCALED_REF_LAYER_RIGHT_OFFSET_MAX, "seq_scaled_ref_layer_right_offset");
    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //seq_scaled_ref_layer_bottom_offset
    kpPos->iBottomOffset = iCode;
    WELS_CHECK_SE_BOTH_WARNING (kpPos->iBottomOffset, SUBSET_SPS_SEQ_SCALED_REF_LAYER_BOTTOM_OFFSET_MIN,
                                SUBSET_SPS_SEQ_SCALED_REF_LAYER_BOTTOM_OFFSET_MAX, "seq_scaled_ref_layer_bottom_offset");
  }

  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //seq_tcoeff_level_prediction_flag
  pExt->bSeqTCoeffLevelPredFlag	= !!uiCode;
  pExt->bAdaptiveTCoeffLevelPredFlag	= false;
  if (pExt->bSeqTCoeffLevelPredFlag) {
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_tcoeff_level_prediction_flag
    pExt->bAdaptiveTCoeffLevelPredFlag	= !!uiCode;
  }
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //slice_header_restriction_flag
  pExt->bSliceHeaderRestrictionFlag	= !!uiCode;



  return 0;
}

const SLevelLimits* GetLevelLimits (int32_t iLevelIdx, bool bConstraint3) {
  switch (iLevelIdx) {
  case 9:
    return &g_ksLevelLimits[1];
  case 10:
    return &g_ksLevelLimits[0];
  case 11:
    if (bConstraint3)
      return &g_ksLevelLimits[1];
    else
      return &g_ksLevelLimits[2];
  case 12:
    return &g_ksLevelLimits[3];
  case 13:
    return &g_ksLevelLimits[4];
  case 20:
    return &g_ksLevelLimits[5];
  case 21:
    return &g_ksLevelLimits[6];
  case 22:
    return &g_ksLevelLimits[7];
  case 30:
    return &g_ksLevelLimits[8];
  case 31:
    return &g_ksLevelLimits[9];
  case 32:
    return &g_ksLevelLimits[10];
  case 40:
    return &g_ksLevelLimits[11];
  case 41:
    return &g_ksLevelLimits[12];
  case 42:
    return &g_ksLevelLimits[13];
  case 50:
    return &g_ksLevelLimits[14];
  case 51:
    return &g_ksLevelLimits[15];
  case 52:
    return &g_ksLevelLimits[16];
  default:
    return NULL;
  }
  return NULL;
}

bool CheckSpsActive (PWelsDecoderContext pCtx, PSps pSps, bool bUseSubsetFlag) {
  for (int i = 0; i < MAX_LAYER_NUM; i++) {
    if (pCtx->pActiveLayerSps[i] == pSps)
      return true;
  }
  // Pre-active, will be used soon
  if (bUseSubsetFlag) {
    if (pSps->iMbWidth > 0  && pSps->iMbHeight > 0 && pCtx->bSubspsAvailFlags[pSps->iSpsId]
        && pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
      PSps pNextUsedSps =
        pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps;
      if (pNextUsedSps->iSpsId == pSps->iSpsId)
        return true;
    }
  } else {
    if (pSps->iMbWidth > 0  && pSps->iMbHeight > 0 && pCtx->bSpsAvailFlags[pSps->iSpsId]
        && pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
      PSps pNextUsedSps =
        pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps;
      if (pNextUsedSps->iSpsId == pSps->iSpsId)
        return true;
    }
  }
  return false;
}

#define  SPS_LOG2_MAX_FRAME_NUM_MINUS4_MAX 12
#define  SPS_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4_MAX 12
#define  SPS_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE_MAX 255
#define  SPS_MAX_NUM_REF_FRAMES_MAX 16
#define  PPS_PIC_INIT_QP_QS_MIN 0
#define  PPS_PIC_INIT_QP_QS_MAX 51
#define  PPS_CHROMA_QP_INDEX_OFFSET_MIN -12
#define  PPS_CHROMA_QP_INDEX_OFFSET_MAX 12
#define  SCALING_LIST_DELTA_SCALE_MAX 127
#define SCALING_LIST_DELTA_SCALE_MIN -128

/*!
 *************************************************************************************
 * \brief	to parse Sequence Parameter Set (SPS)
 *
 * \param	pCtx		Decoder context
 * \param	pBsAux		bitstream reader auxiliary
 * \param	pPicWidth	picture width current Sps represented
 * \param	pPicHeight	picture height current Sps represented
 *
 * \return	0 - successed
 *		1 - failed
 *
 * \note	Call it in case eNalUnitType is SPS.
 *************************************************************************************
 */

int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight,
                  uint8_t* pSrcNal, const int32_t kSrcNalLen) {
  PBitStringAux pBs		= pBsAux;
  SSubsetSps sTempSubsetSps;
  PSps pSps				= NULL;
  PSubsetSps pSubsetSps	= NULL;
  SNalUnitHeader* pNalHead = &pCtx->sCurNalHead;
  ProfileIdc	uiProfileIdc;
  uint8_t	uiLevelIdc;
  int32_t iSpsId;
  uint32_t uiCode;
  int32_t iCode;
  bool bConstraintSetFlags[6] = { false };
  const bool kbUseSubsetFlag   = IS_SUBSET_SPS_NAL (pNalHead->eNalUnitType);

  WELS_READ_VERIFY (BsGetBits (pBs, 8, &uiCode)); //profile_idc
  uiProfileIdc	= uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set0_flag
  bConstraintSetFlags[0]	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set1_flag
  bConstraintSetFlags[1]	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set2_flag
  bConstraintSetFlags[2]	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set3_flag
  bConstraintSetFlags[3]	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set4_flag
  bConstraintSetFlags[4]	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constraint_set5_flag
  bConstraintSetFlags[5]	= !!uiCode;
  WELS_READ_VERIFY (BsGetBits (pBs, 2, &uiCode)); // reserved_zero_2bits, equal to 0
  WELS_READ_VERIFY (BsGetBits (pBs, 8, &uiCode)); // level_idc
  uiLevelIdc	= uiCode;
  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //seq_parameter_set_id
  if (uiCode >= MAX_SPS_COUNT) {	// Modified to check invalid negative iSpsId, 12/1/2009
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " iSpsId is out of range! \n");
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_SPS_ID_OVERFLOW);
  }
  iSpsId		= uiCode;
  pSubsetSps = &sTempSubsetSps;
  pSps = &sTempSubsetSps.sSps;
  memset (pSubsetSps, 0, sizeof (SSubsetSps));
  const SLevelLimits* pSLevelLimits = GetLevelLimits (uiLevelIdc, bConstraintSetFlags[3]);
  if (NULL == pSLevelLimits) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParseSps(): level_idx (%d).\n", uiLevelIdc);
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);
  } else pSps->pSLevelLimits = pSLevelLimits;
  // syntax elements in default
  pSps->uiChromaFormatIdc	= 1;

  pSps->uiProfileIdc	= uiProfileIdc;
  pSps->uiLevelIdc	= uiLevelIdc;
  pSps->iSpsId		= iSpsId;

  if (PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc ||
      PRO_HIGH == uiProfileIdc || PRO_HIGH10 == uiProfileIdc ||
      PRO_HIGH422 == uiProfileIdc || PRO_HIGH444 == uiProfileIdc ||
      PRO_CAVLC444 == uiProfileIdc || 44 == uiProfileIdc) {

    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //chroma_format_idc
    pSps->uiChromaFormatIdc = uiCode;
    if (pSps->uiChromaFormatIdc != 1) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParseSps(): chroma_format_idc (%d) = 1 supported.",
               pSps->uiChromaFormatIdc);
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);
    }
    pSps->uiChromaArrayType = pSps->uiChromaFormatIdc;
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //bit_depth_luma_minus8
    if (uiCode != 0) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParseSps(): bit_depth_luma (%d) Only 8 bit supported.", 8 + uiCode);
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);
    }
    pSps->uiBitDepthLuma		= 8;

    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //bit_depth_chroma_minus8
    if (uiCode != 0) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParseSps(): bit_depth_chroma (%d). Only 8 bit supported.", 8 + uiCode);
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);
    }
    pSps->uiBitDepthChroma	= 8;

    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //qpprime_y_zero_transform_bypass_flag
    pSps->bQpPrimeYZeroTransfBypassFlag	= !!uiCode;
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //seq_scaling_matrix_present_flag
    pSps->bSeqScalingMatrixPresentFlag	= !!uiCode;

    if (pSps->bSeqScalingMatrixPresentFlag)// For high profile, it is not used in current application. FIXME

      WELS_READ_VERIFY (ParseScalingList (pSps, pBs, 0, pSps->bSeqScalingListPresentFlag, pSps->iScalingList4x4,
                                          pSps->iScalingList8x8));
    //if exist, to parse scalinglist matrix value

    //  WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING,
    //         "ParseSps(): seq_scaling_matrix_present_flag (%d). Feature not supported.",
    //       pSps->bSeqScalingMatrixPresentFlag);
    //return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);
  }
  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //log2_max_frame_num_minus4
  WELS_CHECK_SE_UPPER_ERROR (uiCode, SPS_LOG2_MAX_FRAME_NUM_MINUS4_MAX, "log2_max_frame_num_minus4",
                             GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_LOG2_MAX_FRAME_NUM_MINUS4));
  pSps->uiLog2MaxFrameNum	= LOG2_MAX_FRAME_NUM_OFFSET + uiCode;
  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_order_cnt_type
  pSps->uiPocType			= uiCode;

  if (0 == pSps->uiPocType) {
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //log2_max_pic_order_cnt_lsb_minus4
    // log2_max_pic_order_cnt_lsb_minus4 should be in range 0 to 12, inclusive. (sec. 7.4.3)
    WELS_CHECK_SE_UPPER_ERROR (uiCode, SPS_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4_MAX, "log2_max_pic_order_cnt_lsb_minus4",
                               GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4));
    pSps->iLog2MaxPocLsb	= LOG2_MAX_PIC_ORDER_CNT_LSB_OFFSET + uiCode;	// log2_max_pic_order_cnt_lsb_minus4

  } else if (1 == pSps->uiPocType) {
    int32_t i;
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //delta_pic_order_always_zero_flag
    pSps->bDeltaPicOrderAlwaysZeroFlag	= !!uiCode;
    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //offset_for_non_ref_pic
    pSps->iOffsetForNonRefPic			= iCode;
    WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //offset_for_top_to_bottom_field
    pSps->iOffsetForTopToBottomField	= iCode;
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //num_ref_frames_in_pic_order_cnt_cycle
    WELS_CHECK_SE_UPPER_ERROR (uiCode, SPS_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE_MAX,
                               "num_ref_frames_in_pic_order_cnt_cycle", GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS,
                                   ERR_INFO_INVALID_NUM_REF_FRAME_IN_PIC_ORDER_CNT_CYCLE));
    pSps->iNumRefFramesInPocCycle		= uiCode;
    for (i = 0; i < pSps->iNumRefFramesInPocCycle; i++) {
      WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //offset_for_ref_frame[ i ]
      pSps->iOffsetForRefFrame[ i ]	= iCode;
    }
  }
  if (pSps->uiPocType > 2) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " illegal pic_order_cnt_type: %d ! ", pSps->uiPocType);
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_POC_TYPE);
  }

  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //max_num_ref_frames
  pSps->iNumRefFrames	= uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //gaps_in_frame_num_value_allowed_flag
  pSps->bGapsInFrameNumValueAllowedFlag	= !!uiCode;
  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_width_in_mbs_minus1
  pSps->iMbWidth		= PIC_WIDTH_IN_MBS_OFFSET + uiCode;
  if (pSps->iMbWidth > MAX_MB_SIZE) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "pic_width_in_mbs(%d) exceeds the maximum allowed!", pSps->iMbWidth);
    return  GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_MAX_MB_SIZE);
  }
  if (((uint64_t)pSps->iMbWidth * (uint64_t)pSps->iMbWidth) > (uint64_t) (8 * pSLevelLimits->uiMaxFS)) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " the pic_width_in_mbs exceeds the level limits!");
  }
  WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_height_in_map_units_minus1
  pSps->iMbHeight		= PIC_HEIGHT_IN_MAP_UNITS_OFFSET + uiCode;
  if (pSps->iMbHeight > MAX_MB_SIZE) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "pic_height_in_mbs(%d) exceeds the maximum allowed!", pSps->iMbHeight);
    return  GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_MAX_MB_SIZE);
  }
  if (((uint64_t)pSps->iMbHeight * (uint64_t)pSps->iMbHeight) > (uint64_t) (8 * pSLevelLimits->uiMaxFS)) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " the pic_height_in_mbs exceeds the level limits!");
  }
  uint32_t uiTmp32 = pSps->iMbWidth * pSps->iMbHeight;
  if (uiTmp32 > (uint32_t)pSLevelLimits->uiMaxFS) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " the total count of mb exceeds the level limits!");
  }
  pSps->uiTotalMbCount	= uiTmp32;
  WELS_CHECK_SE_UPPER_ERROR (pSps->iNumRefFrames, SPS_MAX_NUM_REF_FRAMES_MAX, "max_num_ref_frames",
                             GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_MAX_NUM_REF_FRAMES));
  // here we check max_num_ref_frames
  uint32_t uiMaxDpbMbs = pSLevelLimits->uiMaxDPBMbs;
  uint32_t uiMaxDpbFrames = uiMaxDpbMbs / pSps->uiTotalMbCount;
  if (uiMaxDpbFrames > SPS_MAX_NUM_REF_FRAMES_MAX)
    uiMaxDpbFrames = SPS_MAX_NUM_REF_FRAMES_MAX;
  if ((uint32_t)pSps->iNumRefFrames > uiMaxDpbFrames) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, " max_num_ref_frames exceeds level limits!");
  }
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //frame_mbs_only_flag
  pSps->bFrameMbsOnlyFlag	= !!uiCode;
  if (!pSps->bFrameMbsOnlyFlag) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParseSps(): frame_mbs_only_flag (%d) not supported.",
             pSps->bFrameMbsOnlyFlag);
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_MBAFF);
  }
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //direct_8x8_inference_flag
  pSps->bDirect8x8InferenceFlag	= !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //frame_cropping_flag
  pSps->bFrameCroppingFlag		= !!uiCode;
  if (pSps->bFrameCroppingFlag) {
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //frame_crop_left_offset
    pSps->sFrameCrop.iLeftOffset	= uiCode;
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //frame_crop_right_offset
    pSps->sFrameCrop.iRightOffset	= uiCode;
    if ((pSps->sFrameCrop.iLeftOffset + pSps->sFrameCrop.iRightOffset) > ((int32_t)pSps->iMbWidth * 16 / 2)) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "frame_crop_left_offset + frame_crop_right_offset exceeds limits!");
    }
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //frame_crop_top_offset
    pSps->sFrameCrop.iTopOffset		= uiCode;
    WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //frame_crop_bottom_offset
    pSps->sFrameCrop.iBottomOffset	= uiCode;
    if ((pSps->sFrameCrop.iTopOffset + pSps->sFrameCrop.iBottomOffset) > ((int32_t)pSps->iMbHeight * 16 / 2)) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "frame_crop_top_offset + frame_crop_right_offset exceeds limits!");
    }
  } else {
    pSps->sFrameCrop.iLeftOffset	= 0;				// frame_crop_left_offset
    pSps->sFrameCrop.iRightOffset	= 0;				// frame_crop_right_offset
    pSps->sFrameCrop.iTopOffset		= 0;				// frame_crop_top_offset
    pSps->sFrameCrop.iBottomOffset	= 0;				// frame_crop_bottom_offset
  }
  WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //vui_parameters_present_flag
  pSps->bVuiParamPresentFlag			= !!uiCode;

  if (pCtx->bParseOnly) {
    if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //sps bs exceeds!
      pCtx->iErrorCode |= dsOutOfMemory;
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
    }
    if (!kbUseSubsetFlag) { //SPS
      SSpsBsInfo* pSpsBs = &pCtx->sSpsBsInfo [iSpsId];
      pSpsBs->iSpsId = iSpsId;
      int32_t iTrailingZeroByte = 0;
      while (pSrcNal[kSrcNalLen - iTrailingZeroByte - 1] == 0x0) //remove final trailing 0 bytes
        iTrailingZeroByte++;
      int32_t iActualLen = kSrcNalLen - iTrailingZeroByte;
      pSpsBs->uiSpsBsLen = (uint16_t) iActualLen;
      //unify start code as 0x0001
      int32_t iStartDeltaByte = 0; //0 for 0x0001, 1 for 0x001
      if (pSrcNal[0] == 0x0 && pSrcNal[1] == 0x0 && pSrcNal[2] == 0x1) { //if 0x001
        pSpsBs->pSpsBsBuf[0] = 0x0; //add 0 to form 0x0001
        iStartDeltaByte++;
        pSpsBs->uiSpsBsLen++;
      }
      memcpy (pSpsBs->pSpsBsBuf + iStartDeltaByte, pSrcNal, iActualLen);
    } else { //subset SPS
      SSpsBsInfo* pSpsBs = &pCtx->sSubsetSpsBsInfo [iSpsId];
      pSpsBs->iSpsId = iSpsId;
      pSpsBs->pSpsBsBuf [0] = pSpsBs->pSpsBsBuf [1] = pSpsBs->pSpsBsBuf [2] = 0x00;
      pSpsBs->pSpsBsBuf [3] = 0x01;
      pSpsBs->pSpsBsBuf [4] = 0x67;

      //re-write subset SPS to SPS
      SBitStringAux sSubsetSpsBs;
      uint8_t* pBsBuf = static_cast<uint8_t*> (WelsMalloc (SPS_PPS_BS_SIZE + 4,
                        "Temp buffer for parse only usage.")); //to reserve 4 bytes for UVLC writing buffer
      if (NULL == pBsBuf) {
        pCtx->iErrorCode |= dsOutOfMemory;
        return pCtx->iErrorCode;
      }
      DecInitBitsForEncoding (&sSubsetSpsBs, pBsBuf, (int32_t) (pBs->pEndBuf - pBs->pStartBuf));
      DecBsWriteBits (&sSubsetSpsBs, 8, 77); //profile_idc, forced to Main profile
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet0Flag); // constraint_set0_flag
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet1Flag); // constraint_set1_flag
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet2Flag); // constraint_set2_flag
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet3Flag); // constraint_set3_flag
      DecBsWriteBits (&sSubsetSpsBs, 4, 0); //constraint_set4_flag, constraint_set5_flag, reserved_zero_2bits
      DecBsWriteBits (&sSubsetSpsBs, 8, pSps->uiLevelIdc); //level_idc
      DecBsWriteUe (&sSubsetSpsBs, pSps->iSpsId); //sps_id
      DecBsWriteUe (&sSubsetSpsBs, pSps->uiLog2MaxFrameNum - 4); //log2_max_frame_num_minus4
      DecBsWriteUe (&sSubsetSpsBs, pSps->uiPocType); //pic_order_cnt_type
      if (pSps->uiPocType == 0) {
        DecBsWriteUe (&sSubsetSpsBs, pSps->iLog2MaxPocLsb - 4); //log2_max_pic_order_cnt_lsb_minus4
      } else if (pSps->uiPocType == 1) {
        DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDeltaPicOrderAlwaysZeroFlag); //delta_pic_order_always_zero_flag
        DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForNonRefPic); //offset_for_no_ref_pic
        DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForTopToBottomField); //offset_for_top_to_bottom_field
        DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFramesInPocCycle); //num_ref_frames_in_pic_order_cnt_cycle
        for (int32_t i = 0; i < pSps->iNumRefFramesInPocCycle; ++i) {
          DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForRefFrame[i]); //offset_for_ref_frame[i]
        }
      }
      DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFrames); //max_num_ref_frames
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bGapsInFrameNumValueAllowedFlag); //gaps_in_frame_num_value_allowed_flag
      DecBsWriteUe (&sSubsetSpsBs, pSps->iMbWidth - 1); //pic_width_in_mbs_minus1
      DecBsWriteUe (&sSubsetSpsBs, pSps->iMbHeight - 1); //pic_height_in_map_units_minus1
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameMbsOnlyFlag); //frame_mbs_only_flag
      if (!pSps->bFrameMbsOnlyFlag) {
        DecBsWriteOneBit (&sSubsetSpsBs, pSps->bMbaffFlag); //mb_adaptive_frame_field_flag
      }
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDirect8x8InferenceFlag); //direct_8x8_inference_flag
      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameCroppingFlag); //frame_cropping_flag
      if (pSps->bFrameCroppingFlag) {
        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iLeftOffset); //frame_crop_left_offset
        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iRightOffset); //frame_crop_right_offset
        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iTopOffset); //frame_crop_top_offset
        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iBottomOffset); //frame_crop_bottom_offset
      }
      DecBsWriteOneBit (&sSubsetSpsBs, 0); //vui_parameters_present_flag
      DecBsRbspTrailingBits (&sSubsetSpsBs); //finished, rbsp trailing bit
      int32_t iRbspSize = (int32_t) (sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf);
      RBSP2EBSP (pSpsBs->pSpsBsBuf + 5, sSubsetSpsBs.pStartBuf, iRbspSize);
      pSpsBs->uiSpsBsLen = (uint16_t) (sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf + 5);
      if (pBsBuf) {
        WelsFree (pBsBuf, "pBsBuf for parse only usage");
      }
    }
  }
  // Check if SPS SVC extension applicated
  if (kbUseSubsetFlag && (PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc)) {
    if (DecodeSpsSvcExt (pCtx, pSubsetSps, pBs) != ERR_NONE) {
      return -1;
    }

    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //svc_vui_parameters_present_flag
    pSubsetSps->bSvcVuiParamPresentFlag = !!uiCode;
    if (pSubsetSps->bSvcVuiParamPresentFlag) {
    }
  }


  if (PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc)
    pCtx->bAvcBasedFlag	= false;

  *pPicWidth	= pSps->iMbWidth << 4;
  *pPicHeight	= pSps->iMbHeight << 4;
  PSps pTmpSps = NULL;
  if (kbUseSubsetFlag) {
    pTmpSps = &pCtx->sSubsetSpsBuffer[iSpsId].sSps;
  } else {
    pTmpSps = &pCtx->sSpsBuffer[iSpsId];
  }
  if (CheckSpsActive (pCtx, pTmpSps, kbUseSubsetFlag)) {
    // we are overwriting the active sps, copy a temp buffer
    if (kbUseSubsetFlag) {
      if (memcmp (&pCtx->sSubsetSpsBuffer[iSpsId], pSubsetSps, sizeof (SSubsetSps)) != 0) {
        if (pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
          memcpy (&pCtx->sSubsetSpsBuffer[MAX_SPS_COUNT], pSubsetSps, sizeof (SSubsetSps));
          pCtx->bAuReadyFlag = true;
          pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1;
          pCtx->iOverwriteFlags |= OVERWRITE_SUBSETSPS;
        } else if ((pCtx->pSps != NULL) && (pCtx->pSps->iSpsId == pSubsetSps->sSps.iSpsId)) {
          memcpy (&pCtx->sSubsetSpsBuffer[MAX_SPS_COUNT], pSubsetSps, sizeof (SSubsetSps));
          pCtx->iOverwriteFlags |= OVERWRITE_SUBSETSPS;
        } else {
          memcpy (&pCtx->sSubsetSpsBuffer[iSpsId], pSubsetSps, sizeof (SSubsetSps));
        }
      }
    } else {
      if (memcmp (&pCtx->sSpsBuffer[iSpsId], pSps, sizeof (SSps)) != 0) {
        if (pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
          memcpy (&pCtx->sSpsBuffer[MAX_SPS_COUNT], pSps, sizeof (SSps));
          pCtx->iOverwriteFlags |= OVERWRITE_SPS;
          pCtx->bAuReadyFlag = true;
          pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1;
        } else if ((pCtx->pSps != NULL) && (pCtx->pSps->iSpsId == pSps->iSpsId)) {
          memcpy (&pCtx->sSpsBuffer[MAX_SPS_COUNT], pSps, sizeof (SSps));
          pCtx->iOverwriteFlags |= OVERWRITE_SPS;
        } else {
          memcpy (&pCtx->sSpsBuffer[iSpsId], pSps, sizeof (SSps));
        }
      }
    }
  }
  // Not overwrite active sps, just copy to final place
  else if (kbUseSubsetFlag) {
    memcpy (&pCtx->sSubsetSpsBuffer[iSpsId], pSubsetSps, sizeof (SSubsetSps));
    pCtx->bSubspsAvailFlags[iSpsId]	= true;
    pCtx->bSubspsExistAheadFlag	= true;
  } else {
    memcpy (&pCtx->sSpsBuffer[iSpsId], pSps, sizeof (SSps));
    pCtx->bSpsAvailFlags[iSpsId] = true;
    pCtx->bSpsExistAheadFlag		= true;
  }
  return 0;
}

/*!
 *************************************************************************************
 * \brief	to parse Picture Parameter Set (PPS)
 *
 * \param	pCtx		Decoder context
 * \param 	pPpsList	pps list
 * \param	pBsAux		bitstream reader auxiliary
 *
 * \return	0 - successed
 *		1 - failed
 *
 * \note	Call it in case eNalUnitType is PPS.
 *************************************************************************************
 */
int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux, uint8_t* pSrcNal,
                  const int32_t kSrcNalLen) {

  PPps pPps = NULL;
  SPps sTempPps;
  uint32_t uiPpsId = 0;
  uint32_t iTmp;
  uint32_t uiCode;
  int32_t iCode;

  WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //pic_parameter_set_id
  uiPpsId = uiCode;
  if (uiPpsId >= MAX_PPS_COUNT) {
    return ERR_INFO_PPS_ID_OVERFLOW;
  }
  pPps = &sTempPps;
  memset (pPps, 0, sizeof (SPps));

  pPps->iPpsId = uiPpsId;
  WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //seq_parameter_set_id
  pPps->iSpsId = uiCode;

  if (pPps->iSpsId >= MAX_SPS_COUNT) {
    return ERR_INFO_SPS_ID_OVERFLOW;
  }

  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //entropy_coding_mode_flag
  pPps->bEntropyCodingModeFlag = !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //bottom_field_pic_order_in_frame_present_flag
  pPps->bPicOrderPresentFlag   = !!uiCode;

  WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //num_slice_groups_minus1
  pPps->uiNumSliceGroups = NUM_SLICE_GROUPS_OFFSET + uiCode;

  if (pPps->uiNumSliceGroups > MAX_SLICEGROUP_IDS) {
    return ERR_INFO_INVALID_SLICEGROUP;
  }

  if (pPps->uiNumSliceGroups > 1) {
    WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //slice_group_map_type
    pPps->uiSliceGroupMapType = uiCode;
    if (pPps->uiSliceGroupMapType > 1) {
      WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "ParsePps(): slice_group_map_type (%d): support only 0,1.",
               pPps->uiSliceGroupMapType);
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_FMOTYPE);
    }

    switch (pPps->uiSliceGroupMapType) {
    case 0:
      for (iTmp = 0; iTmp < pPps->uiNumSliceGroups; iTmp++) {
        WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //run_length_minus1[ iGroup ]
        pPps->uiRunLength[iTmp] = RUN_LENGTH_OFFSET + uiCode;
      }
      break;
    default:
      break;
    }
  }

  WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //num_ref_idx_l0_default_active_minus1
  pPps->uiNumRefIdxL0Active = NUM_REF_IDX_L0_DEFAULT_ACTIVE_OFFSET + uiCode;
  WELS_READ_VERIFY (BsGetUe (pBsAux, &uiCode)); //num_ref_idx_l1_default_active_minus1
  pPps->uiNumRefIdxL1Active = NUM_REF_IDX_L1_DEFAULT_ACTIVE_OFFSET + uiCode;

  if (pPps->uiNumRefIdxL0Active > MAX_REF_PIC_COUNT ||
      pPps->uiNumRefIdxL1Active > MAX_REF_PIC_COUNT) {
    return ERR_INFO_REF_COUNT_OVERFLOW;
  }

  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //weighted_pred_flag
  pPps->bWeightedPredFlag  = !!uiCode;
  WELS_READ_VERIFY (BsGetBits (pBsAux, 2, &uiCode)); //weighted_bipred_idc
  pPps->uiWeightedBipredIdc = uiCode;
  if (pPps->bWeightedPredFlag || pPps->uiWeightedBipredIdc != 0) {
    WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING,
             "ParsePps(): weighted_pred_flag (%d) weighted_bipred_idc (%d) neither supported.\n",
             pPps->bWeightedPredFlag, pPps->uiWeightedBipredIdc);
    return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_WP);
  }

  WELS_READ_VERIFY (BsGetSe (pBsAux, &iCode)); //pic_init_qp_minus26
  pPps->iPicInitQp = PIC_INIT_QP_OFFSET + iCode;
  WELS_CHECK_SE_BOTH_ERROR (pPps->iPicInitQp, PPS_PIC_INIT_QP_QS_MIN, PPS_PIC_INIT_QP_QS_MAX, "pic_init_qp_minus26 + 26",
                            GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_PIC_INIT_QP));
  WELS_READ_VERIFY (BsGetSe (pBsAux, &iCode)); //pic_init_qs_minus26
  pPps->iPicInitQs = PIC_INIT_QS_OFFSET + iCode;
  WELS_CHECK_SE_BOTH_ERROR (pPps->iPicInitQs, PPS_PIC_INIT_QP_QS_MIN, PPS_PIC_INIT_QP_QS_MAX, "pic_init_qs_minus26 + 26",
                            GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_PIC_INIT_QS));
  WELS_READ_VERIFY (BsGetSe (pBsAux, &iCode)); //chroma_qp_index_offset,cb
  pPps->iChromaQpIndexOffset[0]                  = iCode;
  WELS_CHECK_SE_BOTH_ERROR (pPps->iChromaQpIndexOffset[0], PPS_CHROMA_QP_INDEX_OFFSET_MIN, PPS_CHROMA_QP_INDEX_OFFSET_MAX,
                            "chroma_qp_index_offset", GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_CHROMA_QP_INDEX_OFFSET));
  pPps->iChromaQpIndexOffset[1] = pPps->iChromaQpIndexOffset[0];//init cr qp offset
  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //deblocking_filter_control_present_flag
  pPps->bDeblockingFilterControlPresentFlag   = !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //constrained_intra_pred_flag
  pPps->bConstainedIntraPredFlag              = !!uiCode;
  WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode)); //redundant_pic_cnt_present_flag
  pPps->bRedundantPicCntPresentFlag           = !!uiCode;
  /*TODO: to judge whether going on to parse*/
//going on to parse high profile syntax, need fix me
  if (0) {
    WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode));
    pPps->bTransform_8x8_mode_flag = !!uiCode;
    WELS_READ_VERIFY (BsGetOneBit (pBsAux, &uiCode));
    pPps->bPicScalingMatrixPresentFlag = !!uiCode;
    if (pPps->bPicScalingMatrixPresentFlag) {
      if (pCtx->bSpsAvailFlags[pPps->iSpsId])
        WELS_READ_VERIFY (ParseScalingList (&pCtx->sSpsBuffer[pPps->iSpsId], pBsAux, 1, pPps->bPicScalingListPresentFlag,
                                            pPps->iScalingList4x4, pPps->iScalingList8x8));
      else {
        pCtx->bSpsLatePps = true;
        WELS_READ_VERIFY (ParseScalingList (NULL, pBsAux, 1, pPps->bPicScalingListPresentFlag, pPps->iScalingList4x4,
                                            pPps->iScalingList8x8));
      }
    }
    //add second chroma qp parsing process
    WELS_READ_VERIFY (BsGetSe (pBsAux, &iCode)); //chroma_qp_index_offset,cr
    pPps->iChromaQpIndexOffset[1]               = iCode;
    WELS_CHECK_SE_BOTH_ERROR (pPps->iChromaQpIndexOffset[1], PPS_CHROMA_QP_INDEX_OFFSET_MIN, PPS_CHROMA_QP_INDEX_OFFSET_MAX,
                              "second_chroma_qp_index_offset", GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_CHROMA_QP_INDEX_OFFSET));
  }

  if (pCtx->pAccessUnitList->uiAvailUnitsNum > 0) {
    PNalUnit pLastNalUnit = pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum - 1];
    PPps pLastPps = pLastNalUnit->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pPps;
    // the active pps is overwrite, write to a temp place
    if (pLastPps == &pCtx->sPpsBuffer[uiPpsId] && memcmp (&pCtx->sPpsBuffer[uiPpsId], pPps, sizeof (*pPps)) != 0) {
      memcpy (&pCtx->sPpsBuffer[MAX_PPS_COUNT], pPps, sizeof (SPps));
      pCtx->iOverwriteFlags |= OVERWRITE_PPS;
      pCtx->bAuReadyFlag = true;
      pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1;
    } else {
      memcpy (&pCtx->sPpsBuffer[uiPpsId], pPps, sizeof (SPps));
      pCtx->bPpsAvailFlags[uiPpsId] = true;
    }
  } else {
    memcpy (&pCtx->sPpsBuffer[uiPpsId], pPps, sizeof (SPps));
    pCtx->bPpsAvailFlags[uiPpsId] = true;
  }
  if (pCtx->bParseOnly) {
    if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //pps bs exceeds
      pCtx->iErrorCode |= dsOutOfMemory;
      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
    }
    SPpsBsInfo* pPpsBs = &pCtx->sPpsBsInfo [uiPpsId];
    pPpsBs->iPpsId = (int32_t) uiPpsId;
    int32_t iTrailingZeroByte = 0;
    while (pSrcNal[kSrcNalLen - iTrailingZeroByte - 1] == 0x0) //remove final trailing 0 bytes
      iTrailingZeroByte++;
    int32_t iActualLen = kSrcNalLen - iTrailingZeroByte;
    pPpsBs->uiPpsBsLen = (uint16_t) iActualLen;
    //unify start code as 0x0001
    int32_t iStartDeltaByte = 0; //0 for 0x0001, 1 for 0x001
    if (pSrcNal[0] == 0x0 && pSrcNal[1] == 0x0 && pSrcNal[2] == 0x1) { //if 0x001
      pPpsBs->pPpsBsBuf[0] = 0x0; //add 0 to form 0x0001
      iStartDeltaByte++;
      pPpsBs->uiPpsBsLen++;
    }
    memcpy (pPpsBs->pPpsBsBuf + iStartDeltaByte, pSrcNal, iActualLen);
  }
  return ERR_NONE;
}

/*!
 *************************************************************************************
 * \brief	to parse SEI message payload
 *
 * \param 	pSei		sei message to be parsed output
 * \param	pBsAux		bitstream reader auxiliary
 *
 * \return	0 - successed
 *		1 - failed
 *
 * \note	Call it in case eNalUnitType is NAL_UNIT_SEI.
 *************************************************************************************
 */
int32_t ParseSei (void* pSei, PBitStringAux pBsAux) {	// reserved Sei_Msg type


  return ERR_NONE;
}
/*
 *************************************************************************************
 * \brief	to parse scalinglist message payload
 *
 * \param	pps sps scaling list matrix		 message to be parsed output
 * \param	pBsAux		bitstream reader auxiliary
 *
 * \return	0 - successed
 *		1 - failed
 *
 * \note	Call it in case scaling list matrix present at sps or pps level
 *************************************************************************************
 */
int32_t SetScalingListValue (uint8_t* pScalingList, int iScalingListNum, bool* bUseDefaultScalingMatrixFlag,
                             PBitStringAux pBsAux) {	// reserved Sei_Msg type
  int iLastScale = 8;
  int iNextScale = 8;
  int iDeltaScale;
  int32_t iCode;
  for (int j = 0; j < iScalingListNum; j++) {
    if (iNextScale != 0) {
      WELS_READ_VERIFY (BsGetSe (pBsAux, &iCode));
      WELS_CHECK_SE_BOTH_ERROR_NOLOG (iCode, SCALING_LIST_DELTA_SCALE_MIN, SCALING_LIST_DELTA_SCALE_MAX, "DeltaScale",
                                      ERR_SCALING_LIST_DELTA_SCALE);
      iDeltaScale = iCode;
      iNextScale = (iLastScale + iDeltaScale + 256) % 256;
      *bUseDefaultScalingMatrixFlag = (j == 0 && iNextScale == 0);
      if (*bUseDefaultScalingMatrixFlag)
        break;
    }
    pScalingList[g_kuiZigzagScan[j]] = (iNextScale == 0) ? iLastScale : iNextScale;
    iLastScale = pScalingList[g_kuiZigzagScan[j]];
  }


  return ERR_NONE;
}

int32_t ParseScalingList (PSps pSps, PBitStringAux pBs, bool bPPS, bool* pScalingListPresentFlag,
                          uint8_t (*iScalingList4x4)[16], uint8_t (*iScalingList8x8)[64]) {
  uint32_t uiScalingListNum;
  uint32_t uiCode;
  int32_t iRetTmp;
  bool bUseDefaultScalingMatrixFlag4x4 = false;
  bool bUseDefaultScalingMatrixFlag8x8 = false;
  bool bInit = false;
  const uint8_t* defaultScaling[4];

  if (pSps != NULL) {
    uiScalingListNum = (pSps->uiChromaFormatIdc != 3) ? 8 : 12;
    bInit = bPPS && pSps->bSeqScalingMatrixPresentFlag;
  } else
    uiScalingListNum = 12;

//Init default_scaling_list value for sps or pps
  defaultScaling[0] = bInit ? pSps->iScalingList4x4[0] : g_kuiDequantScaling4x4Default[0];
  defaultScaling[1] = bInit ? pSps->iScalingList4x4[3] : g_kuiDequantScaling4x4Default[1];
  defaultScaling[2] = bInit ? pSps->iScalingList8x8[0] : g_kuiDequantScaling8x8Default[0];
  defaultScaling[3] = bInit ? pSps->iScalingList8x8[1] : g_kuiDequantScaling8x8Default[1];

  for (unsigned int i = 0; i < uiScalingListNum; i++) {
    WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode));
    pScalingListPresentFlag[i] = !!uiCode;
    if (!!uiCode) {
      if (i < 6) {
        iRetTmp = SetScalingListValue (iScalingList4x4[i], 16, &bUseDefaultScalingMatrixFlag4x4, pBs);
        if (iRetTmp == ERR_NONE) {
          if (bUseDefaultScalingMatrixFlag4x4) {
            bUseDefaultScalingMatrixFlag4x4 = false;
            memcpy (iScalingList4x4[i], g_kuiDequantScaling4x4Default[i / 3], sizeof (uint8_t) * 16);
          }
        } else
          return iRetTmp;

      } else {
        SetScalingListValue (iScalingList8x8[i - 6], 64, &bUseDefaultScalingMatrixFlag8x8, pBs);
        //if(iRetTmp == ERR_NONE)
        //{
        if (bUseDefaultScalingMatrixFlag8x8) {
          bUseDefaultScalingMatrixFlag8x8 = false;
          memcpy (iScalingList8x8[i - 6], g_kuiDequantScaling8x8Default[ (i - 6) & 1], sizeof (uint8_t) * 64);
        }
        // }

        //else
        // return iRetTmp;
      }

    } else {
      if (i < 6) {
        if ((i != 0) && (i != 3))
          memcpy (iScalingList4x4[i], iScalingList4x4[i - 1], sizeof (uint8_t) * 16);
        else
          memcpy (iScalingList4x4[i], defaultScaling[i / 3], sizeof (uint8_t) * 16);

      } else {
        if ((i == 6) || (i == 7))
          memcpy (iScalingList8x8[i - 6], defaultScaling[ (i & 1) + 2], sizeof (uint8_t) * 64);
        else
          memcpy (iScalingList8x8[i - 6], iScalingList8x8[ (i - 6) / 3], sizeof (uint8_t) * 64);

      }
    }
  }
  return ERR_NONE;

}

/*!
 *************************************************************************************
 * \brief	reset fmo list due to got Sps now
 *
 * \param	pCtx	decoder context
 *
 * \return	count number of fmo context units are reset
 *************************************************************************************
 */
int32_t ResetFmoList (PWelsDecoderContext pCtx) {
  int32_t iCountNum = 0;
  if (NULL != pCtx) {
    // Fixed memory leak due to PPS_ID might not be continuous sometimes, 1/5/2010
    UninitFmoList (&pCtx->sFmoList[0], MAX_PPS_COUNT, pCtx->iActiveFmoNum);
    iCountNum	= pCtx->iActiveFmoNum;
    pCtx->iActiveFmoNum	= 0;
  }
  return iCountNum;
}

} // namespace WelsDec
