/*! * \copy * Copyright (c) 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. * * decoder_core.c: Wels decoder framework core implementation */ #include "decoder_core.h"#include "error_code.h"#include "memmgr_nal_unit.h"#include "au_parser.h"#include "decode_slice.h"#include "manage_dec_ref.h"#include "expand_pic.h"#include "decoder.h"#include "decode_mb_aux.h"#include "mem_align.h"#include "error_concealment.h" namespace WelsDec { static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t** ppDst, int32_t* pDstLen, int32_t* pWidth, int32_t* pHeight, SBufferInfo* pDstInfo) { PDqLayer pCurDq = pCtx->pCurDqLayer; PPicture pPic = pCtx->pDec; const int32_t kiWidth = pCurDq->iMbWidth << 4; const int32_t kiHeight = pCurDq->iMbHeight << 4; const int32_t kiTotalNumMbInCurLayer = pCurDq->iMbWidth * pCurDq->iMbHeight; bool bFrameCompleteFlag = true; if (pCtx->iTotalNumMbRec != kiTotalNumMbInCurLayer) { WelsLog (pCtx, WELS_LOG_WARNING, "DecodeFrameConstruction():::iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d \n", pCtx->iTotalNumMbRec, kiTotalNumMbInCurLayer, pCurDq->iMbWidth, pCurDq->iMbHeight); bFrameCompleteFlag = false; //return later after output buffer is done }#ifdef NO_WAITING_AU pCtx->iTotalNumMbRec = 0;#endif if (pCtx->bNewSeqBegin) { memcpy (& (pCtx->sFrameCrop), & (pCurDq->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.pSps->sFrameCrop), sizeof (SPosOffset)); //confirmed_safe_unsafe_usage#ifdef LONG_TERM_REF pCtx->bParamSetsLostFlag = false;#else pCtx->bReferenceLostAtT0Flag = false; // need initialize it due new seq, 6/4/2010#endif //LONG_TERM_REF WelsLog (pCtx, WELS_LOG_INFO, "DecodeFrameConstruction()::::output first frame of new sequence, %d x %d, crop_left:%d, crop_right:%d, crop_top:%d, crop_bottom:%d.\n", kiWidth, kiHeight, pCtx->sFrameCrop.iLeftOffset, pCtx->sFrameCrop.iRightOffset, pCtx->sFrameCrop.iTopOffset, pCtx->sFrameCrop.iBottomOffset); } //////output:::normal path ppDst[0] = pPic->pData[0]; ppDst[1] = pPic->pData[1]; ppDst[2] = pPic->pData[2]; *pDstLen = pPic->iLinesize[0]; * (pDstLen + 1) = pPic->iLinesize[1]; *pWidth = kiWidth; *pHeight = kiHeight; pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420; pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2; pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2; pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0]; pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1]; ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2; ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; pDstInfo->iBufferStatus = 1; if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete pDstInfo->iBufferStatus = (int32_t) bFrameCompleteFlag; if (!bFrameCompleteFlag) { pCtx->iErrorCode |= dsBitstreamError; return -1; } return 0;} inline bool CheckSliceNeedReconstruct (uint8_t uiLayerDqId, uint8_t uiTargetDqId) { return (uiLayerDqId == uiTargetDqId); // target layer} inline uint8_t GetTargetDqId (uint8_t uiTargetDqId, SDecodingParam* psParam) { uint8_t uiRequiredDqId = psParam ? psParam->uiTargetDqLayer : (uint8_t)255; return WELS_MIN (uiTargetDqId, uiRequiredDqId);} inline void HandleReferenceLostL0 (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if (0 == pCurNal->sNalHeaderExt.uiTemporalId) { pCtx->bReferenceLostAtT0Flag = true; } if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) {#ifndef LONG_TERM_REF if (pCtx->bReferenceLostAtT0Flag) { ResetParameterSetsState (pCtx); }#endif } pCtx->iErrorCode |= dsBitstreamError;} inline void HandleReferenceLost (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if ((0 == pCurNal->sNalHeaderExt.uiTemporalId) || (1 == pCurNal->sNalHeaderExt.uiTemporalId)) { pCtx->bReferenceLostAtT0Flag = true; } if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) {#ifndef LONG_TERM_REF if (pCtx->bReferenceLostAtT0Flag) { ResetParameterSetsState (pCtx); }#endif } pCtx->iErrorCode |= dsRefLost;} inline int32_t WelsDecodeConstructSlice (PWelsDecoderContext pCtx, PNalUnit pCurNal) { int32_t iRet = WelsTargetSliceConstruction (pCtx); if (iRet) { HandleReferenceLostL0 (pCtx, pCurNal); } return iRet;} /* * Predeclared function routines .. */int32_t ParseRefPicListReordering (PBitStringAux pBs, PSliceHeader pSh) { int32_t iList = 0; const ESliceType keSt = pSh->eSliceType; PRefPicListReorderSyn pRefPicListReordering = &pSh->pRefPicListReordering; PSps pSps = pSh->pSps; uint32_t uiCode; if (keSt == I_SLICE || keSt == SI_SLICE) return ERR_NONE; // Common syntaxs for P or B slices: list0, list1 followed if B slices used. do { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //ref_pic_list_modification_flag_l0 pRefPicListReordering->bRefPicListReorderingFlag[iList] = !!uiCode; if (pRefPicListReordering->bRefPicListReorderingFlag[iList]) { int32_t iIdx = 0; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //modification_of_pic_nums_idc const uint32_t kuiIdc = uiCode; //Fixed the referrence list reordering crash issue.(fault kIdc value > 3 case)--- if ((iIdx >= MAX_REF_PIC_COUNT) || (kuiIdc > 3)) { return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); } pRefPicListReordering->sReorderingSyn[iList][iIdx].uiReorderingOfPicNumsIdc = kuiIdc; if (kuiIdc == 3) break; if (iIdx >= pSh->uiRefCount[iList] || iIdx >= MAX_REF_PIC_COUNT) return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); if (kuiIdc == 0 || kuiIdc == 1) { // abs_diff_pic_num_minus1 should be in range 0 to MaxPicNum-1, MaxPicNum is derived as // 2^(4+log2_max_frame_num_minus4) WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //abs_diff_pic_num_minus1 WELS_CHECK_SE_UPPER_ERROR_NOLOG (uiCode, (uint32_t) (1 << pSps->uiLog2MaxFrameNum), "abs_diff_pic_num_minus1", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING)); pRefPicListReordering->sReorderingSyn[iList][iIdx].uiAbsDiffPicNumMinus1 = uiCode; // uiAbsDiffPicNumMinus1 } else if (kuiIdc == 2) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num pRefPicListReordering->sReorderingSyn[iList][iIdx].uiLongTermPicNum = uiCode; } ++ iIdx; } while (true); } if (keSt != B_SLICE) break; ++ iList; } while (iList < LIST_A); return ERR_NONE;} int32_t ParseDecRefPicMarking (PWelsDecoderContext pCtx, PBitStringAux pBs, PSliceHeader pSh, PSps pSps, const bool kbIdrFlag) { PRefPicMarking const kpRefMarking = &pSh->sRefMarking; uint32_t uiCode; if (kbIdrFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //no_output_of_prior_pics_flag kpRefMarking->bNoOutputOfPriorPicsFlag = !!uiCode; WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //long_term_reference_flag kpRefMarking->bLongTermRefFlag = !!uiCode; } else { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_ref_pic_marking_mode_flag kpRefMarking->bAdaptiveRefPicMarkingModeFlag = !!uiCode; if (kpRefMarking->bAdaptiveRefPicMarkingModeFlag) { int32_t iIdx = 0; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //memory_management_control_operation const int32_t kiMmco = uiCode; kpRefMarking->sMmcoRef[iIdx].uiMmcoType = kiMmco; if (kiMmco == MMCO_END) break; if (kiMmco == MMCO_SHORT2UNUSED || kiMmco == MMCO_SHORT2LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //difference_of_pic_nums_minus1 kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum = 1 + uiCode; kpRefMarking->sMmcoRef[iIdx].iShortFrameNum = (pSh->iFrameNum - kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum) & (( 1 << pSps->uiLog2MaxFrameNum) - 1); } else if (kiMmco == MMCO_LONG2UNUSED) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num kpRefMarking->sMmcoRef[iIdx].uiLongTermPicNum = uiCode; } if (kiMmco == MMCO_SHORT2LONG || kiMmco == MMCO_LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_frame_idx kpRefMarking->sMmcoRef[iIdx].iLongTermFrameIdx = uiCode; } else if (kiMmco == MMCO_SET_MAX_LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //max_long_term_frame_idx_plus1 kpRefMarking->sMmcoRef[iIdx].iMaxLongTermFrameIdx = -1 + uiCode; } ++ iIdx; } while (iIdx < MAX_MMCO_COUNT); } } return ERR_NONE;} bool FillDefaultSliceHeaderExt (PSliceHeaderExt pShExt, PNalUnitHeaderExt pNalExt) { if (pShExt == NULL || pNalExt == NULL) return false; if (pNalExt->iNoInterLayerPredFlag || pNalExt->uiQualityId > 0) pShExt->bBasePredWeightTableFlag = false; else pShExt->bBasePredWeightTableFlag = true; pShExt->uiRefLayerDqId = (uint8_t) - 1; pShExt->uiDisableInterLayerDeblockingFilterIdc = 0; pShExt->iInterLayerSliceAlphaC0Offset = 0; pShExt->iInterLayerSliceBetaOffset = 0; pShExt->bConstrainedIntraResamplingFlag = false; pShExt->uiRefLayerChromaPhaseXPlus1Flag = 0; pShExt->uiRefLayerChromaPhaseYPlus1 = 1; //memset(&pShExt->sScaledRefLayer, 0, sizeof(SPosOffset)); pShExt->iScaledRefLayerPicWidthInSampleLuma = pShExt->sSliceHeader.iMbWidth << 4; pShExt->iScaledRefLayerPicHeightInSampleLuma = pShExt->sSliceHeader.iMbHeight << 4; pShExt->bSliceSkipFlag = false; pShExt->bAdaptiveBaseModeFlag = false; pShExt->bDefaultBaseModeFlag = false; pShExt->bAdaptiveMotionPredFlag = false; pShExt->bDefaultMotionPredFlag = false; pShExt->bAdaptiveResidualPredFlag = false; pShExt->bDefaultResidualPredFlag = false; pShExt->bTCoeffLevelPredFlag = false; pShExt->uiScanIdxStart = 0; pShExt->uiScanIdxEnd = 15; return true;} /* * WelsInitMemory * Memory request for new introduced data * Especially for: * rbsp_au_buffer, cur_dq_layer_ptr and ref_dq_layer_ptr in MB info cache. * return: * 0 - success; otherwise returned error_no defined in error_no.h.*/int32_t WelsInitMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) { return ERR_INFO_INVALID_PTR; } if (MemInitNalList (&pCtx->pAccessUnitList, MAX_NAL_UNIT_NUM_IN_AU) != 0) return ERR_INFO_OUT_OF_MEMORY; if ((pCtx->sRawData.pHead = static_cast<uint8_t*> (WelsMalloc (MAX_ACCESS_UNIT_CAPACITY, "pCtx->sRawData->pHead"))) == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead; pCtx->sRawData.pEnd = pCtx->sRawData.pHead + MAX_ACCESS_UNIT_CAPACITY; pCtx->uiTargetDqId = (uint8_t) - 1; pCtx->bEndOfStreamFlag = false; pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; return ERR_NONE;} /* * WelsFreeMemory * Free memory introduced in WelsInitMemory at destruction of decoder. * */void WelsFreeMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) return; if (NULL != pCtx->pParam) { WelsFree (pCtx->pParam, "pCtx->pParam"); pCtx->pParam = NULL; } MemFreeNalList (&pCtx->pAccessUnitList); if (pCtx->sRawData.pHead) { WelsFree (pCtx->sRawData.pHead, "pCtx->sRawData->pHead"); } pCtx->sRawData.pHead = NULL; pCtx->sRawData.pEnd = NULL; pCtx->sRawData.pStartPos = NULL; pCtx->sRawData.pCurPos = NULL;} /* * DecodeNalHeaderExt * Trigger condition: NAL_UNIT_TYPE = NAL_UNIT_PREFIX or NAL_UNIT_CODED_SLICE_EXT * Parameter: * pNal: target NALUnit ptr * pSrc: NAL Unit bitstream */void DecodeNalHeaderExt (PNalUnit pNal, uint8_t* pSrc) { PNalUnitHeaderExt pHeaderExt = &pNal->sNalHeaderExt; uint8_t uiCurByte = *pSrc; pHeaderExt->bIdrFlag = !! (uiCurByte & 0x40); pHeaderExt->uiPriorityId = uiCurByte & 0x3F; uiCurByte = * (++pSrc); pHeaderExt->iNoInterLayerPredFlag = uiCurByte >> 7; pHeaderExt->uiDependencyId = (uiCurByte & 0x70) >> 4; pHeaderExt->uiQualityId = uiCurByte & 0x0F; uiCurByte = * (++pSrc); pHeaderExt->uiTemporalId = uiCurByte >> 5; pHeaderExt->bUseRefBasePicFlag = !! (uiCurByte & 0x10); pHeaderExt->bDiscardableFlag = !! (uiCurByte & 0x08); pHeaderExt->bOutputFlag = !! (uiCurByte & 0x04); pHeaderExt->uiReservedThree2Bits = uiCurByte & 0x03; pHeaderExt->uiLayerDqId = (pHeaderExt->uiDependencyId << 4) | pHeaderExt->uiQualityId;} #define SLICE_HEADER_IDR_PIC_ID_MAX 65535#define SLICE_HEADER_REDUNDANT_PIC_CNT_MAX 127#define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MIN -12#define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MAX 12#define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MIN -12#define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MAX 12#define MAX_NUM_REF_IDX_L0_ACTIVE_MINUS1 15/* * decode_slice_header_avc * Parse slice header of bitstream in avc for storing data structure */int32_t ParseSliceHeaderSyntaxs (PWelsDecoderContext pCtx, PBitStringAux pBs, const bool kbExtensionFlag) { PNalUnit const kpCurNal = pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum - 1]; PNalUnitHeaderExt pNalHeaderExt = NULL; PSliceHeader pSliceHead = NULL; PSliceHeaderExt pSliceHeadExt = NULL; PSubsetSps pSubsetSps = NULL; PSps pSps = NULL; PPps pPps = NULL; ENalUnitType eNalType = static_cast<ENalUnitType> (0); int32_t iPpsId = 0; int32_t iRet = ERR_NONE; uint8_t uiSliceType = 0; uint8_t uiQualityId = BASE_QUALITY_ID; bool bIdrFlag = false; bool bSgChangeCycleInvolved = false; // involved slice group change cycle ? uint32_t uiCode; int32_t iCode; if (kpCurNal == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pNalHeaderExt = &kpCurNal->sNalHeaderExt; pSliceHead = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; eNalType = pNalHeaderExt->sNalUnitHeader.eNalUnitType; pSliceHeadExt = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt; if (pSliceHeadExt) { SRefBasePicMarking sBaseMarking; const bool kbStoreRefBaseFlag = pSliceHeadExt->bStoreRefBasePicFlag; memcpy (&sBaseMarking, &pSliceHeadExt->sRefBasePicMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage memset (pSliceHeadExt, 0, sizeof (SSliceHeaderExt)); pSliceHeadExt->bStoreRefBasePicFlag = kbStoreRefBaseFlag; memcpy (&pSliceHeadExt->sRefBasePicMarking, &sBaseMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage } kpCurNal->sNalData.sVclNal.bSliceHeaderExtFlag = kbExtensionFlag; // first_mb_in_slice WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //first_mb_in_slice pSliceHead->iFirstMbInSlice = uiCode; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //slice_type uiSliceType = uiCode; if (uiSliceType > 9) { WelsLog (pCtx, WELS_LOG_WARNING, "slice type too large (%d) at first_mb(%d)\n", uiSliceType, pSliceHead->iFirstMbInSlice); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (uiSliceType > 4) uiSliceType -= 5; if (B_SLICE == uiSliceType) { WelsLog (pCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(): B slice not supported.\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_BIPRED); } if ((NAL_UNIT_CODED_SLICE_IDR == eNalType) && (I_SLICE != uiSliceType)) { WelsLog (pCtx, WELS_LOG_WARNING, "Invalid slice type(%d) in IDR picture. \n", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (kbExtensionFlag) { if (uiSliceType > 2) { WelsLog (pCtx, WELS_LOG_WARNING, "Invalid slice type(%d).\n", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } } pSliceHead->eSliceType = static_cast <ESliceType> (uiSliceType); WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_parameter_set_id iPpsId = uiCode; if (iPpsId >= MAX_PPS_COUNT) { WelsLog (pCtx, WELS_LOG_WARNING, "iPpsId out of range\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_PPS_ID_OVERFLOW); } //add check PPS available here if (pCtx->bPpsAvailFlags[iPpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "PPS id is invalid!\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_PPS_ID); } pPps = &pCtx->sPpsBuffer[iPpsId]; if (pPps->uiNumSliceGroups == 0) { WelsLog (pCtx, WELS_LOG_WARNING, "non existing PPS referenced\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_NO_PARAM_SETS); } if (kbExtensionFlag) { pSubsetSps = &pCtx->sSubsetSpsBuffer[pPps->iSpsId]; pSps = &pSubsetSps->sSps; if (pCtx->bSubspsAvailFlags[pPps->iSpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "SPS id is invalid!\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SPS_ID); } } else { if (pCtx->bSpsAvailFlags[pPps->iSpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "SPS id is invalid!\n");Lines 1–500 of 1948. Load more
/*! * \copy * Copyright (c) 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. * * decoder_core.c: Wels decoder framework core implementation */ #include "decoder_core.h" #include "error_code.h" #include "memmgr_nal_unit.h" #include "au_parser.h" #include "decode_slice.h" #include "manage_dec_ref.h" #include "expand_pic.h" #include "decoder.h" #include "decode_mb_aux.h" #include "mem_align.h" #include "error_concealment.h" namespace WelsDec { static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t** ppDst, int32_t* pDstLen, int32_t* pWidth, int32_t* pHeight, SBufferInfo* pDstInfo) { PDqLayer pCurDq = pCtx->pCurDqLayer; PPicture pPic = pCtx->pDec; const int32_t kiWidth = pCurDq->iMbWidth << 4; const int32_t kiHeight = pCurDq->iMbHeight << 4; const int32_t kiTotalNumMbInCurLayer = pCurDq->iMbWidth * pCurDq->iMbHeight; bool bFrameCompleteFlag = true; if (pCtx->iTotalNumMbRec != kiTotalNumMbInCurLayer) { WelsLog (pCtx, WELS_LOG_WARNING, "DecodeFrameConstruction():::iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d \n", pCtx->iTotalNumMbRec, kiTotalNumMbInCurLayer, pCurDq->iMbWidth, pCurDq->iMbHeight); bFrameCompleteFlag = false; //return later after output buffer is done } #ifdef NO_WAITING_AU pCtx->iTotalNumMbRec = 0; #endif if (pCtx->bNewSeqBegin) { memcpy (& (pCtx->sFrameCrop), & (pCurDq->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.pSps->sFrameCrop), sizeof (SPosOffset)); //confirmed_safe_unsafe_usage #ifdef LONG_TERM_REF pCtx->bParamSetsLostFlag = false; #else pCtx->bReferenceLostAtT0Flag = false; // need initialize it due new seq, 6/4/2010 #endif //LONG_TERM_REF WelsLog (pCtx, WELS_LOG_INFO, "DecodeFrameConstruction()::::output first frame of new sequence, %d x %d, crop_left:%d, crop_right:%d, crop_top:%d, crop_bottom:%d.\n", kiWidth, kiHeight, pCtx->sFrameCrop.iLeftOffset, pCtx->sFrameCrop.iRightOffset, pCtx->sFrameCrop.iTopOffset, pCtx->sFrameCrop.iBottomOffset); } //////output:::normal path ppDst[0] = pPic->pData[0]; ppDst[1] = pPic->pData[1]; ppDst[2] = pPic->pData[2]; *pDstLen = pPic->iLinesize[0]; * (pDstLen + 1) = pPic->iLinesize[1]; *pWidth = kiWidth; *pHeight = kiHeight; pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420; pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2; pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2; pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0]; pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1]; ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2; ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; pDstInfo->iBufferStatus = 1; if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete pDstInfo->iBufferStatus = (int32_t) bFrameCompleteFlag; if (!bFrameCompleteFlag) { pCtx->iErrorCode |= dsBitstreamError; return -1; } return 0; } inline bool CheckSliceNeedReconstruct (uint8_t uiLayerDqId, uint8_t uiTargetDqId) { return (uiLayerDqId == uiTargetDqId); // target layer } inline uint8_t GetTargetDqId (uint8_t uiTargetDqId, SDecodingParam* psParam) { uint8_t uiRequiredDqId = psParam ? psParam->uiTargetDqLayer : (uint8_t)255; return WELS_MIN (uiTargetDqId, uiRequiredDqId); } inline void HandleReferenceLostL0 (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if (0 == pCurNal->sNalHeaderExt.uiTemporalId) { pCtx->bReferenceLostAtT0Flag = true; } if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) { #ifndef LONG_TERM_REF if (pCtx->bReferenceLostAtT0Flag) { ResetParameterSetsState (pCtx); } #endif } pCtx->iErrorCode |= dsBitstreamError; } inline void HandleReferenceLost (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if ((0 == pCurNal->sNalHeaderExt.uiTemporalId) || (1 == pCurNal->sNalHeaderExt.uiTemporalId)) { pCtx->bReferenceLostAtT0Flag = true; } if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) { #ifndef LONG_TERM_REF if (pCtx->bReferenceLostAtT0Flag) { ResetParameterSetsState (pCtx); } #endif } pCtx->iErrorCode |= dsRefLost; } inline int32_t WelsDecodeConstructSlice (PWelsDecoderContext pCtx, PNalUnit pCurNal) { int32_t iRet = WelsTargetSliceConstruction (pCtx); if (iRet) { HandleReferenceLostL0 (pCtx, pCurNal); } return iRet; } /* * Predeclared function routines .. */ int32_t ParseRefPicListReordering (PBitStringAux pBs, PSliceHeader pSh) { int32_t iList = 0; const ESliceType keSt = pSh->eSliceType; PRefPicListReorderSyn pRefPicListReordering = &pSh->pRefPicListReordering; PSps pSps = pSh->pSps; uint32_t uiCode; if (keSt == I_SLICE || keSt == SI_SLICE) return ERR_NONE; // Common syntaxs for P or B slices: list0, list1 followed if B slices used. do { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //ref_pic_list_modification_flag_l0 pRefPicListReordering->bRefPicListReorderingFlag[iList] = !!uiCode; if (pRefPicListReordering->bRefPicListReorderingFlag[iList]) { int32_t iIdx = 0; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //modification_of_pic_nums_idc const uint32_t kuiIdc = uiCode; //Fixed the referrence list reordering crash issue.(fault kIdc value > 3 case)--- if ((iIdx >= MAX_REF_PIC_COUNT) || (kuiIdc > 3)) { return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); } pRefPicListReordering->sReorderingSyn[iList][iIdx].uiReorderingOfPicNumsIdc = kuiIdc; if (kuiIdc == 3) break; if (iIdx >= pSh->uiRefCount[iList] || iIdx >= MAX_REF_PIC_COUNT) return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); if (kuiIdc == 0 || kuiIdc == 1) { // abs_diff_pic_num_minus1 should be in range 0 to MaxPicNum-1, MaxPicNum is derived as // 2^(4+log2_max_frame_num_minus4) WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //abs_diff_pic_num_minus1 WELS_CHECK_SE_UPPER_ERROR_NOLOG (uiCode, (uint32_t) (1 << pSps->uiLog2MaxFrameNum), "abs_diff_pic_num_minus1", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING)); pRefPicListReordering->sReorderingSyn[iList][iIdx].uiAbsDiffPicNumMinus1 = uiCode; // uiAbsDiffPicNumMinus1 } else if (kuiIdc == 2) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num pRefPicListReordering->sReorderingSyn[iList][iIdx].uiLongTermPicNum = uiCode; } ++ iIdx; } while (true); } if (keSt != B_SLICE) break; ++ iList; } while (iList < LIST_A); return ERR_NONE; } int32_t ParseDecRefPicMarking (PWelsDecoderContext pCtx, PBitStringAux pBs, PSliceHeader pSh, PSps pSps, const bool kbIdrFlag) { PRefPicMarking const kpRefMarking = &pSh->sRefMarking; uint32_t uiCode; if (kbIdrFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //no_output_of_prior_pics_flag kpRefMarking->bNoOutputOfPriorPicsFlag = !!uiCode; WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //long_term_reference_flag kpRefMarking->bLongTermRefFlag = !!uiCode; } else { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_ref_pic_marking_mode_flag kpRefMarking->bAdaptiveRefPicMarkingModeFlag = !!uiCode; if (kpRefMarking->bAdaptiveRefPicMarkingModeFlag) { int32_t iIdx = 0; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //memory_management_control_operation const int32_t kiMmco = uiCode; kpRefMarking->sMmcoRef[iIdx].uiMmcoType = kiMmco; if (kiMmco == MMCO_END) break; if (kiMmco == MMCO_SHORT2UNUSED || kiMmco == MMCO_SHORT2LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //difference_of_pic_nums_minus1 kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum = 1 + uiCode; kpRefMarking->sMmcoRef[iIdx].iShortFrameNum = (pSh->iFrameNum - kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum) & (( 1 << pSps->uiLog2MaxFrameNum) - 1); } else if (kiMmco == MMCO_LONG2UNUSED) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num kpRefMarking->sMmcoRef[iIdx].uiLongTermPicNum = uiCode; } if (kiMmco == MMCO_SHORT2LONG || kiMmco == MMCO_LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_frame_idx kpRefMarking->sMmcoRef[iIdx].iLongTermFrameIdx = uiCode; } else if (kiMmco == MMCO_SET_MAX_LONG) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //max_long_term_frame_idx_plus1 kpRefMarking->sMmcoRef[iIdx].iMaxLongTermFrameIdx = -1 + uiCode; } ++ iIdx; } while (iIdx < MAX_MMCO_COUNT); } } return ERR_NONE; } bool FillDefaultSliceHeaderExt (PSliceHeaderExt pShExt, PNalUnitHeaderExt pNalExt) { if (pShExt == NULL || pNalExt == NULL) return false; if (pNalExt->iNoInterLayerPredFlag || pNalExt->uiQualityId > 0) pShExt->bBasePredWeightTableFlag = false; else pShExt->bBasePredWeightTableFlag = true; pShExt->uiRefLayerDqId = (uint8_t) - 1; pShExt->uiDisableInterLayerDeblockingFilterIdc = 0; pShExt->iInterLayerSliceAlphaC0Offset = 0; pShExt->iInterLayerSliceBetaOffset = 0; pShExt->bConstrainedIntraResamplingFlag = false; pShExt->uiRefLayerChromaPhaseXPlus1Flag = 0; pShExt->uiRefLayerChromaPhaseYPlus1 = 1; //memset(&pShExt->sScaledRefLayer, 0, sizeof(SPosOffset)); pShExt->iScaledRefLayerPicWidthInSampleLuma = pShExt->sSliceHeader.iMbWidth << 4; pShExt->iScaledRefLayerPicHeightInSampleLuma = pShExt->sSliceHeader.iMbHeight << 4; pShExt->bSliceSkipFlag = false; pShExt->bAdaptiveBaseModeFlag = false; pShExt->bDefaultBaseModeFlag = false; pShExt->bAdaptiveMotionPredFlag = false; pShExt->bDefaultMotionPredFlag = false; pShExt->bAdaptiveResidualPredFlag = false; pShExt->bDefaultResidualPredFlag = false; pShExt->bTCoeffLevelPredFlag = false; pShExt->uiScanIdxStart = 0; pShExt->uiScanIdxEnd = 15; return true; } /* * WelsInitMemory * Memory request for new introduced data * Especially for: * rbsp_au_buffer, cur_dq_layer_ptr and ref_dq_layer_ptr in MB info cache. * return: * 0 - success; otherwise returned error_no defined in error_no.h. */ int32_t WelsInitMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) { return ERR_INFO_INVALID_PTR; } if (MemInitNalList (&pCtx->pAccessUnitList, MAX_NAL_UNIT_NUM_IN_AU) != 0) return ERR_INFO_OUT_OF_MEMORY; if ((pCtx->sRawData.pHead = static_cast<uint8_t*> (WelsMalloc (MAX_ACCESS_UNIT_CAPACITY, "pCtx->sRawData->pHead"))) == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead; pCtx->sRawData.pEnd = pCtx->sRawData.pHead + MAX_ACCESS_UNIT_CAPACITY; pCtx->uiTargetDqId = (uint8_t) - 1; pCtx->bEndOfStreamFlag = false; pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; return ERR_NONE; } /* * WelsFreeMemory * Free memory introduced in WelsInitMemory at destruction of decoder. * */ void WelsFreeMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) return; if (NULL != pCtx->pParam) { WelsFree (pCtx->pParam, "pCtx->pParam"); pCtx->pParam = NULL; } MemFreeNalList (&pCtx->pAccessUnitList); if (pCtx->sRawData.pHead) { WelsFree (pCtx->sRawData.pHead, "pCtx->sRawData->pHead"); } pCtx->sRawData.pHead = NULL; pCtx->sRawData.pEnd = NULL; pCtx->sRawData.pStartPos = NULL; pCtx->sRawData.pCurPos = NULL; } /* * DecodeNalHeaderExt * Trigger condition: NAL_UNIT_TYPE = NAL_UNIT_PREFIX or NAL_UNIT_CODED_SLICE_EXT * Parameter: * pNal: target NALUnit ptr * pSrc: NAL Unit bitstream */ void DecodeNalHeaderExt (PNalUnit pNal, uint8_t* pSrc) { PNalUnitHeaderExt pHeaderExt = &pNal->sNalHeaderExt; uint8_t uiCurByte = *pSrc; pHeaderExt->bIdrFlag = !! (uiCurByte & 0x40); pHeaderExt->uiPriorityId = uiCurByte & 0x3F; uiCurByte = * (++pSrc); pHeaderExt->iNoInterLayerPredFlag = uiCurByte >> 7; pHeaderExt->uiDependencyId = (uiCurByte & 0x70) >> 4; pHeaderExt->uiQualityId = uiCurByte & 0x0F; uiCurByte = * (++pSrc); pHeaderExt->uiTemporalId = uiCurByte >> 5; pHeaderExt->bUseRefBasePicFlag = !! (uiCurByte & 0x10); pHeaderExt->bDiscardableFlag = !! (uiCurByte & 0x08); pHeaderExt->bOutputFlag = !! (uiCurByte & 0x04); pHeaderExt->uiReservedThree2Bits = uiCurByte & 0x03; pHeaderExt->uiLayerDqId = (pHeaderExt->uiDependencyId << 4) | pHeaderExt->uiQualityId; } #define SLICE_HEADER_IDR_PIC_ID_MAX 65535 #define SLICE_HEADER_REDUNDANT_PIC_CNT_MAX 127 #define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MIN -12 #define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MAX 12 #define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MIN -12 #define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MAX 12 #define MAX_NUM_REF_IDX_L0_ACTIVE_MINUS1 15 /* * decode_slice_header_avc * Parse slice header of bitstream in avc for storing data structure */ int32_t ParseSliceHeaderSyntaxs (PWelsDecoderContext pCtx, PBitStringAux pBs, const bool kbExtensionFlag) { PNalUnit const kpCurNal = pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum - 1]; PNalUnitHeaderExt pNalHeaderExt = NULL; PSliceHeader pSliceHead = NULL; PSliceHeaderExt pSliceHeadExt = NULL; PSubsetSps pSubsetSps = NULL; PSps pSps = NULL; PPps pPps = NULL; ENalUnitType eNalType = static_cast<ENalUnitType> (0); int32_t iPpsId = 0; int32_t iRet = ERR_NONE; uint8_t uiSliceType = 0; uint8_t uiQualityId = BASE_QUALITY_ID; bool bIdrFlag = false; bool bSgChangeCycleInvolved = false; // involved slice group change cycle ? uint32_t uiCode; int32_t iCode; if (kpCurNal == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pNalHeaderExt = &kpCurNal->sNalHeaderExt; pSliceHead = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; eNalType = pNalHeaderExt->sNalUnitHeader.eNalUnitType; pSliceHeadExt = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt; if (pSliceHeadExt) { SRefBasePicMarking sBaseMarking; const bool kbStoreRefBaseFlag = pSliceHeadExt->bStoreRefBasePicFlag; memcpy (&sBaseMarking, &pSliceHeadExt->sRefBasePicMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage memset (pSliceHeadExt, 0, sizeof (SSliceHeaderExt)); pSliceHeadExt->bStoreRefBasePicFlag = kbStoreRefBaseFlag; memcpy (&pSliceHeadExt->sRefBasePicMarking, &sBaseMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage } kpCurNal->sNalData.sVclNal.bSliceHeaderExtFlag = kbExtensionFlag; // first_mb_in_slice WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //first_mb_in_slice pSliceHead->iFirstMbInSlice = uiCode; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //slice_type uiSliceType = uiCode; if (uiSliceType > 9) { WelsLog (pCtx, WELS_LOG_WARNING, "slice type too large (%d) at first_mb(%d)\n", uiSliceType, pSliceHead->iFirstMbInSlice); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (uiSliceType > 4) uiSliceType -= 5; if (B_SLICE == uiSliceType) { WelsLog (pCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(): B slice not supported.\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_BIPRED); } if ((NAL_UNIT_CODED_SLICE_IDR == eNalType) && (I_SLICE != uiSliceType)) { WelsLog (pCtx, WELS_LOG_WARNING, "Invalid slice type(%d) in IDR picture. \n", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (kbExtensionFlag) { if (uiSliceType > 2) { WelsLog (pCtx, WELS_LOG_WARNING, "Invalid slice type(%d).\n", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } } pSliceHead->eSliceType = static_cast <ESliceType> (uiSliceType); WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_parameter_set_id iPpsId = uiCode; if (iPpsId >= MAX_PPS_COUNT) { WelsLog (pCtx, WELS_LOG_WARNING, "iPpsId out of range\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_PPS_ID_OVERFLOW); } //add check PPS available here if (pCtx->bPpsAvailFlags[iPpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "PPS id is invalid!\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_PPS_ID); } pPps = &pCtx->sPpsBuffer[iPpsId]; if (pPps->uiNumSliceGroups == 0) { WelsLog (pCtx, WELS_LOG_WARNING, "non existing PPS referenced\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_NO_PARAM_SETS); } if (kbExtensionFlag) { pSubsetSps = &pCtx->sSubsetSpsBuffer[pPps->iSpsId]; pSps = &pSubsetSps->sSps; if (pCtx->bSubspsAvailFlags[pPps->iSpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "SPS id is invalid!\n"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SPS_ID); } } else { if (pCtx->bSpsAvailFlags[pPps->iSpsId] == false) { WelsLog (pCtx, WELS_LOG_ERROR, "SPS id is invalid!\n");