shithub: openh264

ref: 9b21ece789c066db96be8810f0892560adcd63b8
dir: /codec/decoder/core/src/au_parser.cpp/

View raw version
/*!
 * \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 <string.h>
#include "codec_def.h"
#include "ls_defines.h"
#include "macros.h"
#include "au_parser.h"
#include "decoder.h"
#include "error_code.h"
#include "dec_frame.h"
#include "dec_golomb.h"
#include "bit_stream.h"
#include "utils.h"
#include "codec_app_def.h"
#include "memmgr_nal_unit.h"
#include "decoder_core.h"
#include "wels_common_basis.h"
#include "decoder_core.h"
#include "manage_dec_ref.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 = ((uint32_t)pBits) - ((uint32_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_t bExtensionFlag = false;
	int32_t iErr	= ERR_NONE;	
	int32_t iBitSize = 0;
	
	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
	{
		return NULL; //uiForbiddenZeroBit should always equal to 0
	}

	pNalUnitHeader->uiNalRefIdc		= (uint8_t)(pNal[0] >> 5);			// uiNalRefIdc
	pNalUnitHeader->eNalUnitType		= (ENalUnitType)(pNal[0] & 0x1f);	// eNalUnitType	
	
	++pNal;
	--iNalSize;
	++(*pConsumedBytes);
	
#ifdef DEBUG_PARSE_INFO
	WelsLog(pCtx, WELS_LOG_INFO, "nal type: %d \n", pNalUnitHeader->eNalUnitType);
#endif
	
	if ( !(IS_SEI_NAL(pNalUnitHeader->eNalUnitType) || IS_SPS_NAL(pNalUnitHeader->eNalUnitType) || pCtx->bSpsExistAheadFlag) )
	{
		WelsLog( pCtx, WELS_LOG_WARNING, "parse_nal(), no exist Sequence Parameter Sets ahead of sequence when try to decode NAL(type:%d).\n", pNalUnitHeader->eNalUnitType);
		pCtx->iErrorCode	= dsNoParamSets;
		return NULL;
	}
	if ( !(IS_SEI_NAL(pNalUnitHeader->eNalUnitType) || IS_PARAM_SETS_NALS(pNalUnitHeader->eNalUnitType) || pCtx->bPpsExistAheadFlag) )
	{
		WelsLog( pCtx, WELS_LOG_WARNING, "parse_nal(), no exist Picture Parameter Sets ahead of sequence when try to decode NAL(type:%d).\n", pNalUnitHeader->eNalUnitType);
		pCtx->iErrorCode	= dsNoParamSets;
		return NULL;
	}
	if ( (IS_VCL_NAL_AVC_BASE(pNalUnitHeader->eNalUnitType) && !(pCtx->bSpsExistAheadFlag || pCtx->bPpsExistAheadFlag)) || 
		(IS_NEW_INTRODUCED_NAL(pNalUnitHeader->eNalUnitType) && !(pCtx->bSpsExistAheadFlag || pCtx->bSubspsExistAheadFlag || pCtx->bPpsExistAheadFlag) ) )
	{
		WelsLog( pCtx, WELS_LOG_WARNING, "ParseNalHeader(), no exist Parameter Sets ahead of sequence when try to decode slice(type:%d).\n", 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_SPS:	
		
		if ( pCtx->pAccessUnitList->uiAvailUnitsNum > 0 )
		{
			pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1;
			pCtx->bAuReadyFlag = true;				
		}
			
		break;

	case NAL_UNIT_PREFIX:
		pCurNal = &pCtx->sPrefixNal;

		if ( iNalSize < NAL_UNIT_HEADER_EXT_SIZE )
		{
			return NULL;
		}

		DecodeNalHeaderExt( pCurNal, pNal );
		
		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;

		pBs = &pCtx->sBs;
		
		iBitSize = (iNalSize<<3) - BsGetTrailingBits( pNal + iNalSize - 1 ); // convert into bit
		
		InitBits( pBs, pNal, iBitSize);

		ParsePrefixNalUnit( pCtx, pBs );
		
		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( pCtx, WELS_LOG_WARNING, "MemGetNextNal() fail due out of memory.\n");
				pCtx->iErrorCode	|= dsOutOfMemory;
				return NULL;
			}

			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 )
				{
					return NULL;
				}

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

                    pCtx->iErrorCode |= dsInvalidArgument;
				    ForceClearCurrentNal( pCurAu );

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

				
				if ( NAL_UNIT_PREFIX == pCtx->sPrefixNal.sNalHeaderExt.sNalUnitHeader.eNalUnitType )
				{
					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
			InitBits( pBs, pNal, iBitSize);
			iErr = ParseSliceHeaderSyntaxs( pCtx, pBs, bExtensionFlag );
			if ( iErr != ERR_NONE )
			{
				//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;
					pCtx->bAuReadyFlag = true;
					

				}
#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID			
				if (  dsNoParamSets & pCtx->iErrorCode )
				{
					if ( uiAvailNalNum <= 1 ) //no any data to decode and SPS/PPS ID mismatch, SHOULD request IDR
					{
#ifdef LONG_TERM_REF
						pCtx->bParamSetsLostFlag = true;
#else
						pCtx->bReferenceLostAtT0Flag = true;
#endif
						ResetParameterSetsState( pCtx );
					}
					return NULL;
				}
				else
				{
					return NULL;
				}
#else
				return NULL;
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
			}

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

			}	
		}
		break;
	default:
		break;
	}  
	
	return pNal;
}	


bool_t 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->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;
	}

	return FALSE;
}	 


bool_t CheckAccessUnitBoundary( 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;

	//Sub-clause 7.1.4.1.1 temporal_id  
	if (kpLastNalHeaderExt->uiTemporalId != kpCurNalHeaderExt->uiTemporalId) {
		return TRUE;
	}

	// Subclause 7.4.1.2.5
	if ( kpLastSliceHeader->iRedundantPicCnt < kpCurSliceHeader->iRedundantPicCnt )
		return FALSE;
	else if ( kpLastSliceHeader->iRedundantPicCnt > kpCurSliceHeader->iRedundantPicCnt )
		return TRUE;

	// Subclause G7.4.1.2.4
	if ( kpLastNalHeaderExt->uiDependencyId < kpCurNalHeaderExt->uiDependencyId )
		return FALSE;
	else if ( kpLastNalHeaderExt->uiDependencyId > kpCurNalHeaderExt->uiDependencyId )
		return TRUE;
	if ( kpLastNalHeaderExt->uiQualityId < kpCurNalHeaderExt->uiQualityId )
		return FALSE;
	else if ( kpLastNalHeaderExt->uiQualityId > kpCurNalHeaderExt->uiQualityId )
		return TRUE;

	// Subclause 7.4.1.2.4
	if ( kpLastSliceHeader->iFrameNum != kpCurSliceHeader->iFrameNum )
		return TRUE;
	if ( 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;
}	 

/*! 
 *************************************************************************************
 * \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 )
{
	PBitStringAux	pBs = NULL;	
	ENalUnitType 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;	

	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 )
				InitBits( pBs, pRbsp, iBitSize );
#ifdef DEBUG_PARSE_INFO
			WelsLog(pCtx, WELS_LOG_INFO, "parsing nal: %d \n", eNalType);
#endif
			iErr = ParseSps( pCtx, pBs, &iPicWidth, &iPicHeight );
			if ( ERR_NONE != iErr )	// modified for pSps/pSubsetSps invalid, 12/1/2009 
			{
				pCtx->iErrorCode |= dsNoParamSets;
				return iErr;
			}

			if ( ERR_NONE == iErr )
				UpdateMaxPictureResolution( pCtx, iPicWidth, iPicHeight );
			
			break;		

		case NAL_UNIT_PPS:
			if ( iBitSize > 0 )
				InitBits( pBs, pRbsp, iBitSize );
#ifdef DEBUG_PARSE_INFO
			WelsLog(pCtx, WELS_LOG_INFO, "parsing nal: %d \n", eNalType);
#endif
			iErr = ParsePps( pCtx, &pCtx->sPpsBuffer[0], pBs );
			if ( ERR_NONE != iErr )	// modified for pps invalid, 12/1/2009 
			{
				pCtx->iErrorCode |= dsNoParamSets;
				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;
}

void_t ParseRefBasePicMarking ( PBitStringAux pBs, PRefBasePicMarking pRefBasePicMarking )
{	
	const bool_t kbAdaptiveMarkingModeFlag = !!BsGetOneBit( pBs );
	pRefBasePicMarking->bAdaptiveRefBasePicMarkingModeFlag = kbAdaptiveMarkingModeFlag;
	if ( kbAdaptiveMarkingModeFlag ){
		int32_t iIdx = 0;
		do {
			const uint32_t kuiMmco = BsGetUe( pBs );

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

			if (kuiMmco == MMCO_END)
				break;

			if (kuiMmco == MMCO_SHORT2UNUSED){
				pRefBasePicMarking->mmco_base[iIdx].uiDiffOfPicNums	= 1 + BsGetUe( pBs );
				pRefBasePicMarking->mmco_base[iIdx].iShortFrameNum	= 0;
			}
			else if (kuiMmco == MMCO_LONG2UNUSED){
				pRefBasePicMarking->mmco_base[iIdx].uiLongTermPicNum	= BsGetUe( pBs );
			}
			++ iIdx;
		} while(iIdx < MAX_MMCO_COUNT);
	}
}

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

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


int32_t DecodeSpsSvcExt( PWelsDecoderContext pCtx, PSubsetSps pSpsExt, PBitStringAux pBs )
{	
	PSpsSvcExt  pExt			= NULL;
	uint8_t uiChromaArrayType	= 1;

	pExt	= &pSpsExt->sSpsSvcExt;
	
	pExt->bInterLayerDeblockingFilterCtrlPresentFlag	= !!BsGetOneBit( pBs );
	pExt->uiExtendedSpatialScalability						= BsGetBits( pBs, 2 );
	if ( pExt->uiExtendedSpatialScalability > 2 )
    {
        WelsLog(pCtx, WELS_LOG_WARNING, "DecodeSpsSvcExt():extended_spatial_scalability (%d) != 0, ESS not supported!\n", 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;
	uiChromaArrayType = pSpsExt->sSps.uiChromaArrayType;

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

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

        kpPos->iLeftOffset	= BsGetSe( pBs );
		kpPos->iTopOffset	= BsGetSe( pBs );
		kpPos->iRightOffset	= BsGetSe( pBs );
		kpPos->iBottomOffset= BsGetSe( pBs );
	}
	
	pExt->bSeqTCoeffLevelPredFlag	= !!BsGetOneBit( pBs );
	pExt->bAdaptiveTCoeffLevelPredFlag	= false;
	if ( pExt->bSeqTCoeffLevelPredFlag )
		pExt->bAdaptiveTCoeffLevelPredFlag	= !!BsGetOneBit( pBs );
	pExt->bSliceHeaderRestrictionFlag	= !!BsGetOneBit( pBs );


	
	return 0;
}

/*! 
 *************************************************************************************
 * \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  )
{
	PBitStringAux pBs		= pBsAux;
	PSps pSps				= NULL;
	PSubsetSps pSubsetSps	= NULL;
	SNalUnitHeader *pNalHead= &pCtx->sCurNalHead;
	ProfileIdc	uiProfileIdc;
	uint8_t	uiLevelIdc;
	int32_t iSpsId;
	bool_t bConstraintSetFlags[6] = { false };
	const bool_t kbUseSubsetFlag   = IS_SUBSET_SPS_NAL(pNalHead->eNalUnitType);

	
	if ( kbUseSubsetFlag )	// SubsetSps
	{
		pCtx->bSubspsExistAheadFlag	= true;
	}
	else	// Sps
	{
		pCtx->bSpsExistAheadFlag		= true;

		// added for EC, 10/28/2009		
		// for safe
		memset( &pCtx->bSpsAvailFlags[0], 0, sizeof(pCtx->bSpsAvailFlags) );
		memset( &pCtx->bSubspsAvailFlags[0], 0, sizeof(pCtx->bSubspsAvailFlags) );
		memset( &pCtx->bPpsAvailFlags[0], 0, sizeof(pCtx->bPpsAvailFlags) );

#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
		pCtx->iSpsTotalNum    = 0;
		pCtx->iSubspsTotalNum = 0;
		pCtx->iPpsTotalNum    = 0;
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID		
	}

	uiProfileIdc	= BsGetBits( pBs, 8 );
	bConstraintSetFlags[0]	= !!BsGetOneBit( pBs );	// constraint_set0_flag
	bConstraintSetFlags[1]	= !!BsGetOneBit( pBs );	// constraint_set1_flag
	bConstraintSetFlags[2]	= !!BsGetOneBit( pBs );	// constraint_set2_flag
	bConstraintSetFlags[3]	= !!BsGetOneBit( pBs );	// constraint_set3_flag
	bConstraintSetFlags[4]	= !!BsGetOneBit( pBs );	// constraint_set4_flag
	bConstraintSetFlags[5]	= !!BsGetOneBit( pBs );	// constraint_set5_flag
	BsGetBits( pBs, 2 );							// reserved_zero_2bits, equal to 0
	uiLevelIdc	= BsGetBits( pBs, 8  );				// level_idc

	iSpsId		= BsGetUe( pBs  );					// seq_parameter_set_id
	
		
	if ( iSpsId >= MAX_SPS_COUNT || iSpsId < 0 )	// Modified to check invalid negative iSpsId, 12/1/2009
	{
		WelsLog( pCtx, WELS_LOG_WARNING, " iSpsId is out of range! \n");
		return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_SPS_ID_OVERFLOW);
	}

	if ( kbUseSubsetFlag )
	{
#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
		pSubsetSps = &pCtx->sSubsetSpsBuffer[pCtx->iSubspsTotalNum];
		pCtx->bSubspsAvailFlags[pCtx->iSubspsTotalNum] = true;
		
		pSubsetSps->sSps.iSpsId = iSpsId;
		pSps = &pSubsetSps->sSps;
		++pCtx->iSubspsTotalNum;
#else
		pSubsetSps	= &pCtx->sSubsetSpsBuffer[iSpsId];
		pSps		= &pSubsetSps->sSps;		
		pCtx->bSubspsAvailFlags[iSpsId]	= true; // added for EC, 10/28/2009
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID			
	}
	else
	{
#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
		pSps = &pCtx->sSpsBuffer[pCtx->iSpsTotalNum];
		pCtx->bSpsAvailFlags[pCtx->iSpsTotalNum] = true;
		
		pSps->iSpsId = iSpsId;
		++pCtx->iSpsTotalNum;
#else
		pSps = &pCtx->sSpsBuffer[iSpsId];		
		pCtx->bSpsAvailFlags[iSpsId] = true; // added for EC, 10/28/2009
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID		
	}

	// syntax elements in default
	pSps->uiChromaFormatIdc	= 1;
	pSps->uiBitDepthLuma		=
	pSps->uiBitDepthChroma	= 8; 
	
	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 ){
		
		pSps->uiChromaFormatIdc = BsGetUe( pBs );	
        if( pSps->uiChromaFormatIdc != 1 )
        {
            WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): chroma_format_idc (%d) = 1 supported.\n", pSps->uiChromaFormatIdc);
            return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);       
        }
        pSps->uiChromaArrayType = pSps->uiChromaFormatIdc;
		pSps->uiBitDepthLuma		= 8 + BsGetUe( pBs );
        if( pSps->uiBitDepthLuma != 8 )
        {
            WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): bit_depth_luma (%d) Only 8 bit supported.\n", pSps->uiBitDepthLuma);
            return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);       
        }
		
		pSps->uiBitDepthChroma	= 8 + BsGetUe( pBs );
        if( pSps->uiBitDepthChroma != 8 )
        {
            WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): bit_depth_chroma (%d). Only 8 bit supported.\n", pSps->uiBitDepthChroma);
            return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);       
        }
		pSps->bQpPrimeYZeroTransfBypassFlag	= !!BsGetOneBit( pBs );
		pSps->bSeqScalingMatrixPresentFlag	= !!BsGetOneBit( pBs );
		
		if ( pSps->bSeqScalingMatrixPresentFlag ){	// For high profile, it is not used in current application. FIXME
            WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): seq_scaling_matrix_present_flag (%d). Feature not supported.\n", pSps->bSeqScalingMatrixPresentFlag);
            return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE);       
		}
	}

	pSps->uiLog2MaxFrameNum	= 4 + BsGetUe( pBs );	// log2_max_frame_num_minus4
	pSps->uiPocType			= BsGetUe( pBs );		// pic_order_cnt_type
	
	if ( 0 == pSps->uiPocType )
	{
		pSps->iLog2MaxPocLsb	= 4 + BsGetUe( pBs );	// log2_max_pic_order_cnt_lsb_minus4
		
	}
	else if ( 1 == pSps->uiPocType )
	{
		int32_t i;
		pSps->bDeltaPicOrderAlwaysZeroFlag	= !!BsGetOneBit( pBs );	// bDeltaPicOrderAlwaysZeroFlag
		pSps->iOffsetForNonRefPic			= BsGetSe( pBs );		// iOffsetForNonRefPic
		pSps->iOffsetForTopToBottomField	= BsGetSe( pBs );		// iOffsetForTopToBottomField
		pSps->iNumRefFramesInPocCycle		= BsGetUe( pBs );	// num_ref_frames_in_pic_order_cnt_cycle
		for( i = 0; i < pSps->iNumRefFramesInPocCycle; i++ )
			pSps->iOffsetForRefFrame[ i ]	= BsGetSe( pBs );		// iOffsetForRefFrame[ i ]
	}
	if ( pSps->uiPocType > 2 )
	{
		WelsLog( pCtx, WELS_LOG_WARNING, " illegal pic_order_cnt_type: %d ! \n", pSps->uiPocType );
		return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_POC_TYPE);
	}

	pSps->iNumRefFrames	= BsGetUe( pBs );		// max_num_ref_frames
	pSps->bGapsInFrameNumValueAllowedFlag	= !!BsGetOneBit( pBs );	// bGapsInFrameNumValueAllowedFlag
	pSps->iMbWidth		= 1 + BsGetUe( pBs );		// pic_width_in_mbs_minus1
	pSps->iMbHeight		= 1 + BsGetUe( pBs );		// pic_height_in_map_units_minus1
	pSps->uiTotalMbCount	= pSps->iMbWidth * pSps->iMbHeight;
	pSps->bFrameMbsOnlyFlag	= !!BsGetOneBit( pBs );	// frame_mbs_only_flag
	
	if ( !pSps->bFrameMbsOnlyFlag )
    {
        WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): frame_mbs_only_flag (%d) not supported.\n", pSps->bFrameMbsOnlyFlag);
		return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_MBAFF);
    }
	pSps->bDirect8x8InferenceFlag	= !!BsGetOneBit( pBs );	// direct_8x8_inference_flag
	pSps->bFrameCroppingFlag		= !!BsGetOneBit( pBs );	// frame_cropping_flag
	if ( pSps->bFrameCroppingFlag )
	{
		pSps->sFrameCrop.iLeftOffset	= BsGetUe( pBs );	// frame_crop_left_offset
		pSps->sFrameCrop.iRightOffset	= BsGetUe( pBs );	// frame_crop_right_offset
		pSps->sFrameCrop.iTopOffset		= BsGetUe( pBs );	// frame_crop_top_offset
        pSps->sFrameCrop.iBottomOffset	= BsGetUe( pBs );	// frame_crop_bottom_offset
	}
	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
	}
	pSps->bVuiParamPresentFlag			= !!BsGetOneBit( pBs );	// vui_parameters_present_flag
	
	// 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;
		}
		
		pSubsetSps->bSvcVuiParamPresentFlag = !!BsGetOneBit( pBs );
		if ( pSubsetSps->bSvcVuiParamPresentFlag ){
		}
	}


	if ( PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc )
		pCtx->bAvcBasedFlag	= false;
	else
		pCtx->bAvcBasedFlag	= true;	// added for avc base pBs

	*pPicWidth	= pSps->iMbWidth << 4;
	*pPicHeight	= pSps->iMbHeight << 4;
	
	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 )
{

	PPps pPps = NULL;	
	uint32_t uiPpsId = 0;
    uint32_t iTmp;

	uiPpsId = BsGetUe(pBsAux);	
	if ( uiPpsId >= MAX_PPS_COUNT )
	{
		return ERR_INFO_PPS_ID_OVERFLOW;
	}

#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
	pPps = &pPpsList[pCtx->iPpsTotalNum];
#else
	pPps = &pPpsList[uiPpsId];
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID	
	
	
	pPps->iPpsId = uiPpsId;
	pPps->iSpsId = BsGetUe(pBsAux);
	
	if (pPps->iSpsId >= MAX_SPS_COUNT)
	{
		return ERR_INFO_SPS_ID_OVERFLOW;
	}

	pPps->bEntropyCodingModeFlag = !!BsGetOneBit(pBsAux);
	pPps->bPicOrderPresentFlag   = !!BsGetOneBit(pBsAux);

	pPps->uiNumSliceGroups = 1 + BsGetUe(pBsAux);

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

	if (pPps->uiNumSliceGroups > 1)
	{
		pPps->uiSliceGroupMapType = BsGetUe(pBsAux);
        if( pPps->uiSliceGroupMapType > 1)
        {
            WelsLog( pCtx, WELS_LOG_WARNING, "ParsePps(): slice_group_map_type (%d): support only 0,1.\n", 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++)
			{
				pPps->uiRunLength[iTmp] = 1 + BsGetUe(pBsAux);
			}
			break;
		default:
			break;
		}
	}

	pPps->uiNumRefIdxL0Active = 1 + BsGetUe(pBsAux);
	pPps->uiNumRefIdxL1Active = 1 + BsGetUe(pBsAux);

	if (pPps->uiNumRefIdxL0Active > MAX_REF_PIC_COUNT ||
		pPps->uiNumRefIdxL1Active > MAX_REF_PIC_COUNT) 
	{
		return ERR_INFO_REF_COUNT_OVERFLOW;
	}
	
	pPps->bWeightedPredFlag  = !!BsGetOneBit(pBsAux);
	pPps->uiWeightedBipredIdc = BsGetBits(pBsAux, 2);
    if( pPps->bWeightedPredFlag || pPps->uiWeightedBipredIdc != 0 )
    {
        WelsLog( pCtx, 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);
    }

	pPps->iPicInitQp = 26 + BsGetSe(pBsAux);
	pPps->iPicInitQs = 26 + BsGetSe(pBsAux);

	pPps->iChromaQpIndexOffset                  = BsGetSe(pBsAux);
	pPps->bDeblockingFilterControlPresentFlag   = !!BsGetOneBit(pBsAux);
	pPps->bConstainedIntraPredFlag              = !!BsGetOneBit(pBsAux);
	pPps->bRedundantPicCntPresentFlag           = !!BsGetOneBit(pBsAux);	


#ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID
	pCtx->bPpsAvailFlags[pCtx->iPpsTotalNum] = true;
	++pCtx->iPpsTotalNum;
#else	
	pCtx->bPpsAvailFlags[uiPpsId] = true; // added for EC, 10/28/2009
#endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID

	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_t *pSei, PBitStringAux pBsAux )	// reserved Sei_Msg type
{
	

	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