/*! * \brief configure decoder parameters */ int32_t DecoderConfigParam (PWelsDecoderContext pCtx, const SDecodingParam* kpParam) { if (NULL == pCtx || NULL == kpParam) return 1; pCtx->pParam = (SDecodingParam*)WelsMallocz (sizeof (SDecodingParam), "SDecodingParam"); if (NULL == pCtx->pParam) return 1; memcpy (pCtx->pParam, kpParam, sizeof (SDecodingParam)); pCtx->eOutputColorFormat = pCtx->pParam->eOutputColorFormat; if (!pCtx->bParseOnly) { int32_t iRet = DecoderSetCsp (pCtx, pCtx->pParam->eOutputColorFormat); if (iRet) return iRet; } pCtx->eErrorConMethod = pCtx->pParam->eEcActiveIdc; if (pCtx->bParseOnly) //parse only, disable EC method pCtx->eErrorConMethod = ERROR_CON_DISABLE; InitErrorCon (pCtx); if (VIDEO_BITSTREAM_SVC == pCtx->pParam->sVideoProperty.eVideoBsType || VIDEO_BITSTREAM_AVC == pCtx->pParam->sVideoProperty.eVideoBsType) { pCtx->eVideoType = pCtx->pParam->sVideoProperty.eVideoBsType; } else { pCtx->eVideoType = VIDEO_BITSTREAM_DEFAULT; } WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "eVideoType: %d", pCtx->eVideoType); return 0; }
// the return value of this function is not suitable, it need report failure info to upper layer. int32_t CWelsDecoder::InitDecoder (const SDecodingParam* pParam) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::init_decoder(), openh264 codec version = %s, ParseOnly = %d", VERSION_NUMBER, (int32_t)pParam->bParseOnly); //reset decoder context if (m_pDecContext) //free UninitDecoder(); m_pDecContext = (PWelsDecoderContext)WelsMallocz (sizeof (SWelsDecoderContext), "m_pDecContext"); if (NULL == m_pDecContext) return cmMallocMemeError; int32_t iCacheLineSize = 16; // on chip cache line size in byte m_pDecContext->pMemAlign = new CMemoryAlign (iCacheLineSize); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == m_pDecContext->pMemAlign), UninitDecoder()) //fill in default value into context WelsDecoderDefaults (m_pDecContext, &m_pWelsTrace->m_sLogCtx); //check param and update decoder context m_pDecContext->pParam = (SDecodingParam*) m_pDecContext->pMemAlign->WelsMallocz (sizeof (SDecodingParam), "SDecodingParam"); WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == m_pDecContext->pParam), UninitDecoder()); int32_t iRet = DecoderConfigParam (m_pDecContext, pParam); WELS_VERIFY_RETURN_IFNEQ (iRet, cmResultSuccess); //init decoder WELS_VERIFY_RETURN_PROC_IF (cmInitParaError, WelsInitDecoder (m_pDecContext, &m_pWelsTrace->m_sLogCtx), UninitDecoder()) return cmResultSuccess; }
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 = 0; if (kiSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return 1; } pPicBuf = (PPicBuff)WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicBuf) { return 1; } pPicBuf->ppPic = (PPicture*)WelsMallocz (kiSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicBuf->ppPic) { pPicBuf->iCapacity = 0; DestroyPicBuff (&pPicBuf); return 1; } 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 (&pPicBuf); return 1; } pPicBuf->ppPic[iPicIdx] = pPic; } // initialize context in queue pPicBuf->iCapacity = kiSize; pPicBuf->iCurrentIdx = 0; * ppPicBuf = pPicBuf; return 0; }
// the return value of this function is not suitable, it need report failure info to upper layer. int32_t CWelsDecoder::InitDecoder (const bool bParseOnly) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::init_decoder(), openh264 codec version = %s", VERSION_NUMBER); if (m_pDecContext) //free UninitDecoder(); m_pDecContext = (PWelsDecoderContext)WelsMallocz (sizeof (SWelsDecoderContext), "m_pDecContext"); if (NULL == m_pDecContext) return cmMallocMemeError; return WelsInitDecoder (m_pDecContext, bParseOnly, &m_pWelsTrace->m_sLogCtx); }
/* * request memory blocks for decoder avc part */ int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const int32_t kiMbHeight) { const int32_t kiPicWidth = kiMbWidth << 4; const int32_t kiPicHeight = kiMbHeight << 4; int32_t iErr = ERR_NONE; int32_t iListIdx = 0; //, mb_blocks = 0; int32_t iPicQueueSize = 0; // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) bool bNeedChangePicQueue = true; 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[LIST_0] != NULL && pCtx->pPicBuff[LIST_0]->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 WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free if (pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && pCtx->pPicBuff[LIST_0] != NULL && pCtx->pPicBuff[LIST_0]->iCapacity != iPicQueueSize) { // currently only active for LIST_0 due to have no B frames 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[LIST_0]->iCapacity, iPicQueueSize); if (pCtx->pPicBuff[LIST_0]->iCapacity < iPicQueueSize) { iErr = IncreasePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], pCtx->pPicBuff[LIST_0]->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } else { iErr = DecreasePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], pCtx->pPicBuff[LIST_0]->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } } else { if (pCtx->bHaveGotMemory) WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory re-alloc for resolution change, size change from %d * %d to %d * %d, ref list size change from %d to %d", pCtx->iImgWidthInPixel, pCtx->iImgHeightInPixel, kiPicWidth, kiPicHeight, pCtx->pPicBuff[LIST_0]->iCapacity, iPicQueueSize); else WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory alloc size = %d * %d, ref list size = %d", kiPicWidth, kiPicHeight, iPicQueueSize); // for Recycled_Pic_Queue for (iListIdx = LIST_0; iListIdx < LIST_A; ++ iListIdx) { PPicBuff* ppPic = &pCtx->pPicBuff[iListIdx]; if (NULL != ppPic && NULL != *ppPic) { DestroyPicBuff (ppPic); } } pCtx->pPreviousDecodedPictureInDpb = NULL; // currently only active for LIST_0 due to have no B frames iErr = CreatePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], iPicQueueSize, kiPicWidth, kiPicHeight); } if (iErr != ERR_NONE) return iErr; pCtx->iImgWidthInPixel = kiPicWidth; // target width of image to be reconstruted while decoding pCtx->iImgHeightInPixel = kiPicHeight; // target height of image to be reconstruted while decoding pCtx->bHaveGotMemory = true; // global memory for decoder context related is requested pCtx->pDec = NULL; // need prefetch a new pic due to spatial size changed if (pCtx->pCabacDecEngine == NULL) pCtx->pCabacDecEngine = (SWelsCabacDecEngine*) WelsMallocz (sizeof (SWelsCabacDecEngine), "pCtx->pCabacDecEngine"); 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 = 0; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return 1; } pPicNewBuf = (PPicBuff)WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return 1; } pPicNewBuf->ppPic = (PPicture*)WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (&pPicNewBuf); return 1; } int32_t iPrevPicIdx = -1; for (iPrevPicIdx = 0; iPrevPicIdx < kiOldSize; ++iPrevPicIdx) { if (pCtx->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; } for (iPicIdx = iDelIdx; iPicIdx < kiOldSize; iPicIdx++) { if (iPrevPicIdx != iPicIdx) { if (pPicOldBuf->ppPic[iPicIdx] != NULL) { FreePicture (pPicOldBuf->ppPic[iPicIdx]); 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]->uiRefCount = 0; pPicNewBuf->ppPic[i]->bAvailableFlag = true; pPicNewBuf->ppPic[i]->bIsComplete = false; } // remove old PicBuf if (pPicOldBuf->ppPic != NULL) { WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; WelsFree (pPicOldBuf, "pPicOldBuf"); pPicOldBuf = NULL; return 0; }
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 = 0; if (kiOldSize <= 0 || kiNewSize <= 0 || kiPicWidth <= 0 || kiPicHeight <= 0) { return 1; } pPicNewBuf = (PPicBuff)WelsMallocz (sizeof (SPicBuff), "PPicBuff"); if (NULL == pPicNewBuf) { return 1; } pPicNewBuf->ppPic = (PPicture*)WelsMallocz (kiNewSize * sizeof (PPicture), "PPicture*"); if (NULL == pPicNewBuf->ppPic) { pPicNewBuf->iCapacity = 0; DestroyPicBuff (&pPicNewBuf); return 1; } // 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 (&pPicNewBuf); return 1; } 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]->uiRefCount = 0; pPicNewBuf->ppPic[i]->bAvailableFlag = true; pPicNewBuf->ppPic[i]->bIsComplete = false; } // remove old PicBuf if (pPicOldBuf->ppPic != NULL) { WelsFree (pPicOldBuf->ppPic, "pPicOldBuf->queue"); pPicOldBuf->ppPic = NULL; } pPicOldBuf->iCapacity = 0; pPicOldBuf->iCurrentIdx = 0; WelsFree (pPicOldBuf, "pPicOldBuf"); pPicOldBuf = NULL; return 0; }