/*! * \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 decoder.c * * \brief Interfaces implementation introduced in decoder system architecture * * \date 03/10/2009 Created * ************************************************************************************* */#include "codec_def.h"#include "decoder.h"#include "cpu.h"#include "au_parser.h"#include "get_intra_predictor.h"#include "rec_mb.h"#include "mc.h"#include "decode_mb_aux.h"#include "manage_dec_ref.h"#include "decoder_core.h"#include "deblocking.h"#include "expand_pic.h"#include "decode_slice.h"#include "error_concealment.h"#include "memory_align.h"#include "wels_decoder_thread.h" extern PPicture AllocPicture (PWelsDecoderContext pCtx, const int32_t kiPicWidth, const int32_t kiPicHeight); extern void FreePicture (PPicture pPic, CMemoryAlign* pMa); static int32_t CreatePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiSize, const int32_t kiPicWidth, const int32_t kiPicHeight) { PPicBuff pPicBuf = NULL; int32_t iPicIdx; if (kiSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicBuf->ppPic) { pPicBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } for (iPicIdx = 0; iPicIdx < kiSize; ++ iPicIdx) { PPicture pPic = AllocPicture (pCtx, kiPicWidth, kiPicHeight); if (NULL == pPic) { // init capacity first for free memory pPicBuf->iCapacity = iPicIdx; DestroyPicBuff (pCtx, &pPicBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } pPicBuf->ppPic[iPicIdx] = pPic; } // initialize context in queue pPicBuf->iCapacity = kiSize; pPicBuf->iCurrentIdx = 0; * ppPicBuf = pPicBuf; return ERR_NONE;} static int32_t IncreasePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiOldSize, const int32_t kiPicWidth, const int32_t kiPicHeight, const int32_t kiNewSize) { PPicBuff pPicOldBuf = *ppPicBuf; PPicBuff pPicNewBuf = NULL; int32_t iPicIdx; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicNewBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } // increase new PicBuf for (iPicIdx = kiOldSize; iPicIdx < kiNewSize; ++ iPicIdx) { PPicture pPic = AllocPicture (pCtx, kiPicWidth, kiPicHeight); if (NULL == pPic) { // Set maximum capacity as the new malloc memory at the tail pPicNewBuf->iCapacity = iPicIdx; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic[iPicIdx] = pPic; } // copy old PicBuf to new PicBuf memcpy (pPicNewBuf->ppPic, pPicOldBuf->ppPic, kiOldSize * sizeof (PPicture)); // initialize context in queue pPicNewBuf->iCapacity = kiNewSize; pPicNewBuf->iCurrentIdx = pPicOldBuf->iCurrentIdx; * ppPicBuf = pPicNewBuf; for (int32_t i = 0; i < pPicNewBuf->iCapacity; i++) { pPicNewBuf->ppPic[i]->bUsedAsRef = false; pPicNewBuf->ppPic[i]->bIsLongRef = false; pPicNewBuf->ppPic[i]->iRefCount = 0; pPicNewBuf->ppPic[i]->bIsComplete = false; }// remove old PicBuf if (pPicOldBuf->ppPic != NULL) { pMa->WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; pMa->WelsFree (pPicOldBuf, "pPicOldBuf"); return ERR_NONE;} static int32_t DecreasePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiOldSize, const int32_t kiPicWidth, const int32_t kiPicHeight, const int32_t kiNewSize) { PPicBuff pPicOldBuf = *ppPicBuf; PPicBuff pPicNewBuf = NULL; int32_t iPicIdx; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicNewBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } ResetReorderingPictureBuffers (pCtx->pPictReoderingStatus, pCtx->pPictInfoList, false); int32_t iPrevPicIdx; for (iPrevPicIdx = 0; iPrevPicIdx < kiOldSize; ++iPrevPicIdx) { if (pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb == pPicOldBuf->ppPic[iPrevPicIdx]) { break; } } int32_t iDelIdx; if (iPrevPicIdx < kiOldSize && iPrevPicIdx >= kiNewSize) { // found pPreviousDecodedPictureInDpb, pPicNewBuf->ppPic[0] = pPicOldBuf->ppPic[iPrevPicIdx]; pPicNewBuf->iCurrentIdx = 0; memcpy (pPicNewBuf->ppPic + 1, pPicOldBuf->ppPic, (kiNewSize - 1) * sizeof (PPicture)); iDelIdx = kiNewSize - 1; } else { memcpy (pPicNewBuf->ppPic, pPicOldBuf->ppPic, kiNewSize * sizeof (PPicture)); pPicNewBuf->iCurrentIdx = iPrevPicIdx < kiNewSize ? iPrevPicIdx : 0; iDelIdx = kiNewSize; } //update references due to allocation changes //all references' references have to be reset oss-buzz 14423 for (int32_t i = 0; i < kiNewSize; i++) { for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) { int32_t j = -1; while (++j < MAX_DPB_COUNT && pPicNewBuf->ppPic[i]->pRefPic[listIdx][j] != NULL) { pPicNewBuf->ppPic[i]->pRefPic[listIdx][j] = NULL; } } } for (iPicIdx = iDelIdx; iPicIdx < kiOldSize; iPicIdx++) { if (iPrevPicIdx != iPicIdx) { if (pPicOldBuf->ppPic[iPicIdx] != NULL) { FreePicture (pPicOldBuf->ppPic[iPicIdx], pMa); pPicOldBuf->ppPic[iPicIdx] = NULL; } } } // initialize context in queue pPicNewBuf->iCapacity = kiNewSize; * ppPicBuf = pPicNewBuf; for (int32_t i = 0; i < pPicNewBuf->iCapacity; i++) { pPicNewBuf->ppPic[i]->bUsedAsRef = false; pPicNewBuf->ppPic[i]->bIsLongRef = false; pPicNewBuf->ppPic[i]->iRefCount = 0; pPicNewBuf->ppPic[i]->bIsComplete = false; } // remove old PicBuf if (pPicOldBuf->ppPic != NULL) { pMa->WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; pMa->WelsFree (pPicOldBuf, "pPicOldBuf"); return ERR_NONE;} void DestroyPicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, CMemoryAlign* pMa) { PPicBuff pPicBuf; ResetReorderingPictureBuffers (pCtx->pPictReoderingStatus, pCtx->pPictInfoList, false); if (NULL == ppPicBuf || NULL == *ppPicBuf) return; pPicBuf = *ppPicBuf; while (pPicBuf->ppPic != NULL) { int32_t iPicIdx = 0; while (iPicIdx < pPicBuf->iCapacity) { PPicture pPic = pPicBuf->ppPic[iPicIdx]; if (pPic != NULL) { FreePicture (pPic, pMa); } ++ iPicIdx; } pMa->WelsFree (pPicBuf->ppPic, "pPicBuf->queue"); pPicBuf->ppPic = NULL; } pPicBuf->iCapacity = 0; pPicBuf->iCurrentIdx = 0; pMa->WelsFree (pPicBuf, "pPicBuf"); *ppPicBuf = NULL;} //reset picture reodering buffer listvoid ResetReorderingPictureBuffers (PPictReoderingStatus pPictReoderingStatus, PPictInfo pPictInfo, const bool *fullReset) { if (pPictReoderingStatus != NULL && pPictInfo != NULL) { int32_t pictInfoListCount = *fullReset ? 16 : (pPictReoderingStatus->iLargestBufferedPicIndex + 1); pPictReoderingStatus->iPictInfoIndex = 0; pPictReoderingStatus->iMinPOC = IMinInt32; pPictReoderingStatus->iNumOfPicts = 0; pPictReoderingStatus->iLastGOPRemainPicts = 0; pPictReoderingStatus->iLastWrittenPOC = IMinInt32; pPictReoderingStatus->iLargestBufferedPicIndex = 0; for (int32_t i = 0; i < pictInfoListCount; ++i) { pPictInfo[i].bLastGOP = false; pPictInfo[i].iPOC = IMinInt32; } }} /* * fill data fields in default for decoder context */void WelsDecoderDefaults (PWelsDecoderContext pCtx, SLogContext* pLogCtx) { int32_t iCpuCores = 1; pCtx->sLogCtx = *pLogCtx; pCtx->pArgDec = NULL; pCtx->bHaveGotMemory = false; // not ever request memory blocks for decoder context related pCtx->uiCpuFlag = 0; pCtx->bAuReadyFlag = 0; // au data is not ready pCtx->bCabacInited = false; pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; // alloc picture data when picture size is available pCtx->iLastImgWidthInPixel = 0; pCtx->iLastImgHeightInPixel = 0; pCtx->bFreezeOutput = true; pCtx->iFrameNum = -1; pCtx->pLastDecPicInfo->iPrevFrameNum = -1; pCtx->iErrorCode = ERR_NONE; pCtx->pDec = NULL; pCtx->pTempDec = NULL; WelsResetRefPic (pCtx); pCtx->iActiveFmoNum = 0; pCtx->pPicBuff = NULL; //pCtx->sSpsPpsCtx.bAvcBasedFlag = true; pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb = NULL; pCtx->pDecoderStatistics->iAvgLumaQp = -1; pCtx->pDecoderStatistics->iStatisticsLogInterval = 1000; pCtx->bUseScalingList = false; /*pCtx->sSpsPpsCtx.iSpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iSubSpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iPpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iPPSInvalidNum = 0; pCtx->sSpsPpsCtx.iPPSLastInvalidId = -1; pCtx->sSpsPpsCtx.iSPSInvalidNum = 0; pCtx->sSpsPpsCtx.iSPSLastInvalidId = -1; pCtx->sSpsPpsCtx.iSubSPSInvalidNum = 0; pCtx->sSpsPpsCtx.iSubSPSLastInvalidId = -1; */ pCtx->iFeedbackNalRefIdc = -1; //initialize pCtx->pLastDecPicInfo->iPrevPicOrderCntMsb = 0; pCtx->pLastDecPicInfo->iPrevPicOrderCntLsb = 0; } /** fill data fields in SPS and PPS default for decoder context*/void WelsDecoderSpsPpsDefaults (SWelsDecoderSpsPpsCTX *sSpsPpsCtx) { sSpsPpsCtx->bSpsExistAheadFlag = false; sSpsPpsCtx->bSubspsExistAheadFlag = false; sSpsPpsCtx->bPpsExistAheadFlag = false; sSpsPpsCtx->bAvcBasedFlag = true; sSpsPpsCtx->iSpsErrorIgnored = 0; sSpsPpsCtx->iSubSpsErrorIgnored = 0; sSpsPpsCtx->iPpsErrorIgnored = 0; sSpsPpsCtx->iPPSInvalidNum = 0; sSpsPpsCtx->iPPSLastInvalidId = -1; sSpsPpsCtx->iSPSInvalidNum = 0; sSpsPpsCtx->iSPSLastInvalidId = -1; sSpsPpsCtx->iSubSPSInvalidNum = 0; sSpsPpsCtx->iSubSPSLastInvalidId = -1; sSpsPpsCtx->iSeqId = -1;} /** fill last decoded picture info*/void WelsDecoderLastDecPicInfoDefaults (SWelsLastDecPicInfo *sLastDecPicInfo) { sLastDecPicInfo->iPrevPicOrderCntMsb = 0; sLastDecPicInfo->iPrevPicOrderCntLsb = 0; sLastDecPicInfo->pPreviousDecodedPictureInDpb = NULL; sLastDecPicInfo->iPrevFrameNum = -1; sLastDecPicInfo->bLastHasMmco5 = false; sLastDecPicInfo->uiDecodingTimeStamp = 0;} /*!* \brief copy SpsPps from one Ctx to another ctx for threaded code*/void CopySpsPps (PWelsDecoderContext pFromCtx, PWelsDecoderContext pToCtx) { pToCtx->sSpsPpsCtx = pFromCtx->sSpsPpsCtx; PAccessUnit pFromCurAu = pFromCtx->pAccessUnitList; PSps pTmpLayerSps[MAX_LAYER_NUM]; for (int i = 0; i < MAX_LAYER_NUM; i++) { pTmpLayerSps[i] = NULL; } // track the layer sps for the current au for (unsigned int i = pFromCurAu->uiStartPos; i <= pFromCurAu->uiEndPos; i++) { uint32_t uiDid = pFromCurAu->pNalUnitsList[i]->sNalHeaderExt.uiDependencyId; pTmpLayerSps[uiDid] = pFromCurAu->pNalUnitsList[i]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps; for (unsigned int j = 0; j < MAX_SPS_COUNT + 1; ++j) { if (&pFromCtx->sSpsPpsCtx.sSpsBuffer[j] == pTmpLayerSps[uiDid]) { pTmpLayerSps[uiDid] = &pToCtx->sSpsPpsCtx.sSpsBuffer[j]; break; } } } for (int i = 0; i < MAX_LAYER_NUM; i++) { if (pTmpLayerSps[i] != NULL) { pToCtx->sSpsPpsCtx.pActiveLayerSps[i] = pTmpLayerSps[i]; } }} /* * destory_mb_blocks */ /* * get size of reference picture list in target layer incoming, = (iNumRefFrames */static inline int32_t GetTargetRefListSize (PWelsDecoderContext pCtx) { int32_t iNumRefFrames; // +2 for EC MV Copy buffer exchange if ((pCtx == NULL) || (pCtx->pSps == NULL)) { iNumRefFrames = MAX_REF_PIC_COUNT + 2; } else { iNumRefFrames = pCtx->pSps->iNumRefFrames + 2; int32_t iThreadCount = GetThreadCount (pCtx); if (iThreadCount > 1) { iNumRefFrames = MAX_REF_PIC_COUNT; } } #ifdef LONG_TERM_REF //pic_queue size minimum set 2 if (iNumRefFrames < 2) { iNumRefFrames = 2; }#endif return iNumRefFrames;} /* * request memory blocks for decoder avc part */int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const int32_t kiMbHeight, bool *bReallocFlag) { const int32_t kiPicWidth = kiMbWidth << 4; const int32_t kiPicHeight = kiMbHeight << 4; int32_t iErr; int32_t iPicQueueSize; // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) *bReallocFlag = false; bool bNeedChangePicQueue = true; CMemoryAlign* pMa = pCtx->pMemAlign; WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiPicWidth <= 0 || kiPicHeight <= 0)) // Fixed the issue about different gop size over last, 5/17/2010 // get picture queue size currently iPicQueueSize = GetTargetRefListSize (pCtx); // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) pCtx->iPicQueueNumber = iPicQueueSize; if (pCtx->pPicBuff != NULL && pCtx->pPicBuff->iCapacity == iPicQueueSize) // comparing current picture queue size requested and previous allocation picture queue bNeedChangePicQueue = false; // HD based pic buffer need consider memory size consumed when switch from 720p to other lower size WELS_VERIFY_RETURN_IF (ERR_NONE, pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && (!bNeedChangePicQueue)) // have same scaled buffer // sync update pRefList if (GetThreadCount (pCtx) <= 1) { WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free } if (pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && pCtx->pPicBuff != NULL && pCtx->pPicBuff->iCapacity != iPicQueueSize) { // currently only active for LIST_0 due to have no B frames // Actually just need one memory allocation for the PicBuff. While it needs two pointer list (LIST_0 and LIST_1). WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory re-alloc for no resolution change (size = %d * %d), ref list size change from %d to %d", kiPicWidth, kiPicHeight, pCtx->pPicBuff->iCapacity, iPicQueueSize); if (pCtx->pPicBuff->iCapacity < iPicQueueSize) { iErr = IncreasePicBuff (pCtx, &pCtx->pPicBuff, pCtx->pPicBuff->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } else { iErr = DecreasePicBuff (pCtx, &pCtx->pPicBuff, pCtx->pPicBuff->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } } else { if (pCtx->bHaveGotMemory) WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO,Lines 1–500 of 1236. 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 decoder.c * * \brief Interfaces implementation introduced in decoder system architecture * * \date 03/10/2009 Created * ************************************************************************************* */ #include "codec_def.h" #include "decoder.h" #include "cpu.h" #include "au_parser.h" #include "get_intra_predictor.h" #include "rec_mb.h" #include "mc.h" #include "decode_mb_aux.h" #include "manage_dec_ref.h" #include "decoder_core.h" #include "deblocking.h" #include "expand_pic.h" #include "decode_slice.h" #include "error_concealment.h" #include "memory_align.h" #include "wels_decoder_thread.h" extern PPicture AllocPicture (PWelsDecoderContext pCtx, const int32_t kiPicWidth, const int32_t kiPicHeight); extern void FreePicture (PPicture pPic, CMemoryAlign* pMa); static int32_t CreatePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiSize, const int32_t kiPicWidth, const int32_t kiPicHeight) { PPicBuff pPicBuf = NULL; int32_t iPicIdx; if (kiSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicBuf->ppPic) { pPicBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } for (iPicIdx = 0; iPicIdx < kiSize; ++ iPicIdx) { PPicture pPic = AllocPicture (pCtx, kiPicWidth, kiPicHeight); if (NULL == pPic) { // init capacity first for free memory pPicBuf->iCapacity = iPicIdx; DestroyPicBuff (pCtx, &pPicBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } pPicBuf->ppPic[iPicIdx] = pPic; } // initialize context in queue pPicBuf->iCapacity = kiSize; pPicBuf->iCurrentIdx = 0; * ppPicBuf = pPicBuf; return ERR_NONE; } static int32_t IncreasePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiOldSize, const int32_t kiPicWidth, const int32_t kiPicHeight, const int32_t kiNewSize) { PPicBuff pPicOldBuf = *ppPicBuf; PPicBuff pPicNewBuf = NULL; int32_t iPicIdx; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicNewBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } // increase new PicBuf for (iPicIdx = kiOldSize; iPicIdx < kiNewSize; ++ iPicIdx) { PPicture pPic = AllocPicture (pCtx, kiPicWidth, kiPicHeight); if (NULL == pPic) { // Set maximum capacity as the new malloc memory at the tail pPicNewBuf->iCapacity = iPicIdx; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic[iPicIdx] = pPic; } // copy old PicBuf to new PicBuf memcpy (pPicNewBuf->ppPic, pPicOldBuf->ppPic, kiOldSize * sizeof (PPicture)); // initialize context in queue pPicNewBuf->iCapacity = kiNewSize; pPicNewBuf->iCurrentIdx = pPicOldBuf->iCurrentIdx; * ppPicBuf = pPicNewBuf; for (int32_t i = 0; i < pPicNewBuf->iCapacity; i++) { pPicNewBuf->ppPic[i]->bUsedAsRef = false; pPicNewBuf->ppPic[i]->bIsLongRef = false; pPicNewBuf->ppPic[i]->iRefCount = 0; pPicNewBuf->ppPic[i]->bIsComplete = false; } // remove old PicBuf if (pPicOldBuf->ppPic != NULL) { pMa->WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; pMa->WelsFree (pPicOldBuf, "pPicOldBuf"); return ERR_NONE; } static int32_t DecreasePicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, const int32_t kiOldSize, const int32_t kiPicWidth, const int32_t kiPicHeight, const int32_t kiNewSize) { PPicBuff pPicOldBuf = *ppPicBuf; PPicBuff pPicNewBuf = NULL; int32_t iPicIdx; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return ERR_INFO_INVALID_PARAM; } CMemoryAlign* pMa = pCtx->pMemAlign; pPicNewBuf = (PPicBuff)pMa->WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return ERR_INFO_OUT_OF_MEMORY; } pPicNewBuf->ppPic = (PPicture*)pMa->WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (pCtx, &pPicNewBuf, pMa); return ERR_INFO_OUT_OF_MEMORY; } ResetReorderingPictureBuffers (pCtx->pPictReoderingStatus, pCtx->pPictInfoList, false); int32_t iPrevPicIdx; for (iPrevPicIdx = 0; iPrevPicIdx < kiOldSize; ++iPrevPicIdx) { if (pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb == pPicOldBuf->ppPic[iPrevPicIdx]) { break; } } int32_t iDelIdx; if (iPrevPicIdx < kiOldSize && iPrevPicIdx >= kiNewSize) { // found pPreviousDecodedPictureInDpb, pPicNewBuf->ppPic[0] = pPicOldBuf->ppPic[iPrevPicIdx]; pPicNewBuf->iCurrentIdx = 0; memcpy (pPicNewBuf->ppPic + 1, pPicOldBuf->ppPic, (kiNewSize - 1) * sizeof (PPicture)); iDelIdx = kiNewSize - 1; } else { memcpy (pPicNewBuf->ppPic, pPicOldBuf->ppPic, kiNewSize * sizeof (PPicture)); pPicNewBuf->iCurrentIdx = iPrevPicIdx < kiNewSize ? iPrevPicIdx : 0; iDelIdx = kiNewSize; } //update references due to allocation changes //all references' references have to be reset oss-buzz 14423 for (int32_t i = 0; i < kiNewSize; i++) { for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) { int32_t j = -1; while (++j < MAX_DPB_COUNT && pPicNewBuf->ppPic[i]->pRefPic[listIdx][j] != NULL) { pPicNewBuf->ppPic[i]->pRefPic[listIdx][j] = NULL; } } } for (iPicIdx = iDelIdx; iPicIdx < kiOldSize; iPicIdx++) { if (iPrevPicIdx != iPicIdx) { if (pPicOldBuf->ppPic[iPicIdx] != NULL) { FreePicture (pPicOldBuf->ppPic[iPicIdx], pMa); pPicOldBuf->ppPic[iPicIdx] = NULL; } } } // initialize context in queue pPicNewBuf->iCapacity = kiNewSize; * ppPicBuf = pPicNewBuf; for (int32_t i = 0; i < pPicNewBuf->iCapacity; i++) { pPicNewBuf->ppPic[i]->bUsedAsRef = false; pPicNewBuf->ppPic[i]->bIsLongRef = false; pPicNewBuf->ppPic[i]->iRefCount = 0; pPicNewBuf->ppPic[i]->bIsComplete = false; } // remove old PicBuf if (pPicOldBuf->ppPic != NULL) { pMa->WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; pMa->WelsFree (pPicOldBuf, "pPicOldBuf"); return ERR_NONE; } void DestroyPicBuff (PWelsDecoderContext pCtx, PPicBuff* ppPicBuf, CMemoryAlign* pMa) { PPicBuff pPicBuf; ResetReorderingPictureBuffers (pCtx->pPictReoderingStatus, pCtx->pPictInfoList, false); if (NULL == ppPicBuf || NULL == *ppPicBuf) return; pPicBuf = *ppPicBuf; while (pPicBuf->ppPic != NULL) { int32_t iPicIdx = 0; while (iPicIdx < pPicBuf->iCapacity) { PPicture pPic = pPicBuf->ppPic[iPicIdx]; if (pPic != NULL) { FreePicture (pPic, pMa); } ++ iPicIdx; } pMa->WelsFree (pPicBuf->ppPic, "pPicBuf->queue"); pPicBuf->ppPic = NULL; } pPicBuf->iCapacity = 0; pPicBuf->iCurrentIdx = 0; pMa->WelsFree (pPicBuf, "pPicBuf"); *ppPicBuf = NULL; } //reset picture reodering buffer list void ResetReorderingPictureBuffers (PPictReoderingStatus pPictReoderingStatus, PPictInfo pPictInfo, const bool *fullReset) { if (pPictReoderingStatus != NULL && pPictInfo != NULL) { int32_t pictInfoListCount = *fullReset ? 16 : (pPictReoderingStatus->iLargestBufferedPicIndex + 1); pPictReoderingStatus->iPictInfoIndex = 0; pPictReoderingStatus->iMinPOC = IMinInt32; pPictReoderingStatus->iNumOfPicts = 0; pPictReoderingStatus->iLastGOPRemainPicts = 0; pPictReoderingStatus->iLastWrittenPOC = IMinInt32; pPictReoderingStatus->iLargestBufferedPicIndex = 0; for (int32_t i = 0; i < pictInfoListCount; ++i) { pPictInfo[i].bLastGOP = false; pPictInfo[i].iPOC = IMinInt32; } } } /* * fill data fields in default for decoder context */ void WelsDecoderDefaults (PWelsDecoderContext pCtx, SLogContext* pLogCtx) { int32_t iCpuCores = 1; pCtx->sLogCtx = *pLogCtx; pCtx->pArgDec = NULL; pCtx->bHaveGotMemory = false; // not ever request memory blocks for decoder context related pCtx->uiCpuFlag = 0; pCtx->bAuReadyFlag = 0; // au data is not ready pCtx->bCabacInited = false; pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; // alloc picture data when picture size is available pCtx->iLastImgWidthInPixel = 0; pCtx->iLastImgHeightInPixel = 0; pCtx->bFreezeOutput = true; pCtx->iFrameNum = -1; pCtx->pLastDecPicInfo->iPrevFrameNum = -1; pCtx->iErrorCode = ERR_NONE; pCtx->pDec = NULL; pCtx->pTempDec = NULL; WelsResetRefPic (pCtx); pCtx->iActiveFmoNum = 0; pCtx->pPicBuff = NULL; //pCtx->sSpsPpsCtx.bAvcBasedFlag = true; pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb = NULL; pCtx->pDecoderStatistics->iAvgLumaQp = -1; pCtx->pDecoderStatistics->iStatisticsLogInterval = 1000; pCtx->bUseScalingList = false; /*pCtx->sSpsPpsCtx.iSpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iSubSpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iPpsErrorIgnored = 0; pCtx->sSpsPpsCtx.iPPSInvalidNum = 0; pCtx->sSpsPpsCtx.iPPSLastInvalidId = -1; pCtx->sSpsPpsCtx.iSPSInvalidNum = 0; pCtx->sSpsPpsCtx.iSPSLastInvalidId = -1; pCtx->sSpsPpsCtx.iSubSPSInvalidNum = 0; pCtx->sSpsPpsCtx.iSubSPSLastInvalidId = -1; */ pCtx->iFeedbackNalRefIdc = -1; //initialize pCtx->pLastDecPicInfo->iPrevPicOrderCntMsb = 0; pCtx->pLastDecPicInfo->iPrevPicOrderCntLsb = 0; } /* * fill data fields in SPS and PPS default for decoder context */ void WelsDecoderSpsPpsDefaults (SWelsDecoderSpsPpsCTX *sSpsPpsCtx) { sSpsPpsCtx->bSpsExistAheadFlag = false; sSpsPpsCtx->bSubspsExistAheadFlag = false; sSpsPpsCtx->bPpsExistAheadFlag = false; sSpsPpsCtx->bAvcBasedFlag = true; sSpsPpsCtx->iSpsErrorIgnored = 0; sSpsPpsCtx->iSubSpsErrorIgnored = 0; sSpsPpsCtx->iPpsErrorIgnored = 0; sSpsPpsCtx->iPPSInvalidNum = 0; sSpsPpsCtx->iPPSLastInvalidId = -1; sSpsPpsCtx->iSPSInvalidNum = 0; sSpsPpsCtx->iSPSLastInvalidId = -1; sSpsPpsCtx->iSubSPSInvalidNum = 0; sSpsPpsCtx->iSubSPSLastInvalidId = -1; sSpsPpsCtx->iSeqId = -1; } /* * fill last decoded picture info */ void WelsDecoderLastDecPicInfoDefaults (SWelsLastDecPicInfo *sLastDecPicInfo) { sLastDecPicInfo->iPrevPicOrderCntMsb = 0; sLastDecPicInfo->iPrevPicOrderCntLsb = 0; sLastDecPicInfo->pPreviousDecodedPictureInDpb = NULL; sLastDecPicInfo->iPrevFrameNum = -1; sLastDecPicInfo->bLastHasMmco5 = false; sLastDecPicInfo->uiDecodingTimeStamp = 0; } /*! * \brief copy SpsPps from one Ctx to another ctx for threaded code */ void CopySpsPps (PWelsDecoderContext pFromCtx, PWelsDecoderContext pToCtx) { pToCtx->sSpsPpsCtx = pFromCtx->sSpsPpsCtx; PAccessUnit pFromCurAu = pFromCtx->pAccessUnitList; PSps pTmpLayerSps[MAX_LAYER_NUM]; for (int i = 0; i < MAX_LAYER_NUM; i++) { pTmpLayerSps[i] = NULL; } // track the layer sps for the current au for (unsigned int i = pFromCurAu->uiStartPos; i <= pFromCurAu->uiEndPos; i++) { uint32_t uiDid = pFromCurAu->pNalUnitsList[i]->sNalHeaderExt.uiDependencyId; pTmpLayerSps[uiDid] = pFromCurAu->pNalUnitsList[i]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps; for (unsigned int j = 0; j < MAX_SPS_COUNT + 1; ++j) { if (&pFromCtx->sSpsPpsCtx.sSpsBuffer[j] == pTmpLayerSps[uiDid]) { pTmpLayerSps[uiDid] = &pToCtx->sSpsPpsCtx.sSpsBuffer[j]; break; } } } for (int i = 0; i < MAX_LAYER_NUM; i++) { if (pTmpLayerSps[i] != NULL) { pToCtx->sSpsPpsCtx.pActiveLayerSps[i] = pTmpLayerSps[i]; } } } /* * destory_mb_blocks */ /* * get size of reference picture list in target layer incoming, = (iNumRefFrames */ static inline int32_t GetTargetRefListSize (PWelsDecoderContext pCtx) { int32_t iNumRefFrames; // +2 for EC MV Copy buffer exchange if ((pCtx == NULL) || (pCtx->pSps == NULL)) { iNumRefFrames = MAX_REF_PIC_COUNT + 2; } else { iNumRefFrames = pCtx->pSps->iNumRefFrames + 2; int32_t iThreadCount = GetThreadCount (pCtx); if (iThreadCount > 1) { iNumRefFrames = MAX_REF_PIC_COUNT; } } #ifdef LONG_TERM_REF //pic_queue size minimum set 2 if (iNumRefFrames < 2) { iNumRefFrames = 2; } #endif return iNumRefFrames; } /* * request memory blocks for decoder avc part */ int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const int32_t kiMbHeight, bool *bReallocFlag) { const int32_t kiPicWidth = kiMbWidth << 4; const int32_t kiPicHeight = kiMbHeight << 4; int32_t iErr; int32_t iPicQueueSize; // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) *bReallocFlag = false; bool bNeedChangePicQueue = true; CMemoryAlign* pMa = pCtx->pMemAlign; WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiPicWidth <= 0 || kiPicHeight <= 0)) // Fixed the issue about different gop size over last, 5/17/2010 // get picture queue size currently iPicQueueSize = GetTargetRefListSize (pCtx); // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) pCtx->iPicQueueNumber = iPicQueueSize; if (pCtx->pPicBuff != NULL && pCtx->pPicBuff->iCapacity == iPicQueueSize) // comparing current picture queue size requested and previous allocation picture queue bNeedChangePicQueue = false; // HD based pic buffer need consider memory size consumed when switch from 720p to other lower size WELS_VERIFY_RETURN_IF (ERR_NONE, pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && (!bNeedChangePicQueue)) // have same scaled buffer // sync update pRefList if (GetThreadCount (pCtx) <= 1) { WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free } if (pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && pCtx->pPicBuff != NULL && pCtx->pPicBuff->iCapacity != iPicQueueSize) { // currently only active for LIST_0 due to have no B frames // Actually just need one memory allocation for the PicBuff. While it needs two pointer list (LIST_0 and LIST_1). WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory re-alloc for no resolution change (size = %d * %d), ref list size change from %d to %d", kiPicWidth, kiPicHeight, pCtx->pPicBuff->iCapacity, iPicQueueSize); if (pCtx->pPicBuff->iCapacity < iPicQueueSize) { iErr = IncreasePicBuff (pCtx, &pCtx->pPicBuff, pCtx->pPicBuff->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } else { iErr = DecreasePicBuff (pCtx, &pCtx->pPicBuff, pCtx->pPicBuff->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } } else { if (pCtx->bHaveGotMemory) WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO,