ref: 063709c92e8bafe467d384f564afbdc6b66eb39a
dir: /codec/decoder/core/src/au_parser.cpp/
/*!
* \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