Ethan HuggInitial Commit70e5e6212 years agoHistory
1027 lines · 34.7 KB · C++
RawDownload
/*!
 * \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;	

Lines 1–500 of 1027.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t