/*!
* \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. Load more
/*! * \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;