/*! * \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. * * * welsDecoderExt.cpp * * Abstract * Cisco OpenH264 decoder extension utilization * * History * 3/12/2009 Created * * ************************************************************************///#include <assert.h>#include "welsDecoderExt.h"#include "welsCodecTrace.h"#include "codec_def.h"#include "typedefs.h"#include "memory_align.h"#include "utils.h"#include "version.h" //#include "macros.h"#include "decoder.h"#include "decoder_core.h"#include "manage_dec_ref.h"#include "error_concealment.h" #include "measure_time.h"extern "C" {#include "decoder_core.h"#include "manage_dec_ref.h"}#include "error_code.h"#include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms#include <time.h>#if defined(_WIN32) /*&& defined(_DEBUG)*/ #include <windows.h>#include <stdio.h>#include <stdarg.h>#include <sys/types.h>#include <malloc.h>#else#include <sys/time.h>#endif namespace WelsDec { //////////////////////////////////////////////////////////////////////// Construction/Destruction////////////////////////////////////////////////////////////////////// /**************************************************************************** Description:* class CWelsDecoder constructor function, do initialization and* alloc memory required** Input parameters: none** return: none***************************************************************************/DECLARE_PROCTHREAD (pThrProcInit, p) { SWelsDecThreadInfo* sThreadInfo = (SWelsDecThreadInfo*)p;#if defined(WIN32) _alloca (WELS_DEC_MAX_THREAD_STACK_SIZE * (sThreadInfo->uiThrNum + 1));#endif return sThreadInfo->pThrProcMain (p);} static DECODING_STATE ConstructAccessUnit (CWelsDecoder* pWelsDecoder, PWelsDecoderThreadCTX pThrCtx) { int iRet = dsErrorFree; //WelsMutexLock (&pWelsDecoder->m_csDecoder); if (pThrCtx->pCtx->pLastThreadCtx != NULL) { PWelsDecoderThreadCTX pLastThreadCtx = (PWelsDecoderThreadCTX) (pThrCtx->pCtx->pLastThreadCtx); WAIT_EVENT (&pLastThreadCtx->sSliceDecodeStart, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&pLastThreadCtx->sSliceDecodeStart); } pThrCtx->pDec = NULL; if (GetThreadCount (pThrCtx->pCtx) > 1) { RESET_EVENT (&pThrCtx->sSliceDecodeFinish); } iRet |= pWelsDecoder->DecodeFrame2WithCtx (pThrCtx->pCtx, NULL, 0, pThrCtx->ppDst, &pThrCtx->sDstInfo); //WelsMutexUnlock (&pWelsDecoder->m_csDecoder); return (DECODING_STATE)iRet;} DECLARE_PROCTHREAD (pThrProcFrame, p) { SWelsDecoderThreadCTX* pThrCtx = (SWelsDecoderThreadCTX*)p; while (1) { RELEASE_SEMAPHORE (pThrCtx->sThreadInfo.sIsBusy); RELEASE_SEMAPHORE (&pThrCtx->sThreadInfo.sIsIdle); WAIT_SEMAPHORE (&pThrCtx->sThreadInfo.sIsActivated, WELS_DEC_THREAD_WAIT_INFINITE); if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_RUN) { CWelsDecoder* pWelsDecoder = (CWelsDecoder*)pThrCtx->threadCtxOwner; ConstructAccessUnit (pWelsDecoder, pThrCtx); } else if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_ABORT) { break; } } return 0;} CWelsDecoder::CWelsDecoder (void) : m_pWelsTrace (NULL), m_uiDecodeTimeStamp (0), m_bIsBaseline (false), m_iCpuCount (1), m_iThreadCount (0), m_iCtxCount (1), m_pPicBuff (NULL), m_bParamSetsLostFlag (false), m_bFreezeOutput (false), m_DecCtxActiveCount (0), m_pDecThrCtx (NULL), m_pLastDecThrCtx (NULL), m_iLastBufferedIdx (0) {#ifdef OUTPUT_BIT_STREAM char chFileName[1024] = { 0 }; //for .264 int iBufUsed = 0; int iBufLeft = 1023; int iCurUsed; char chFileNameSize[1024] = { 0 }; //for .len int iBufUsedSize = 0; int iBufLeftSize = 1023; int iCurUsedSize;#endif//OUTPUT_BIT_STREAM m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace != NULL) { m_pWelsTrace->SetCodecInstance (this); m_pWelsTrace->SetTraceLevel (WELS_LOG_ERROR); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::CWelsDecoder() entry"); } ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); m_iCpuCount = GetCPUCount(); if (m_iCpuCount > WELS_DEC_MAX_NUM_CPU) { m_iCpuCount = WELS_DEC_MAX_NUM_CPU; } m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); for (int32_t i = 0; i < WELS_DEC_MAX_NUM_CPU; ++i) { m_pDecThrCtxActive[i] = NULL; }#ifdef OUTPUT_BIT_STREAM SWelsTime sCurTime; WelsGetTimeOfDay (&sCurTime); iCurUsed = WelsSnprintf (chFileName, iBufLeft, "bs_0x%p_", (void*)this); iCurUsedSize = WelsSnprintf (chFileNameSize, iBufLeftSize, "size_0x%p_", (void*)this); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; if (iBufLeft > 0) { iCurUsed = WelsStrftime (&chFileName[iBufUsed], iBufLeft, "%y%m%d%H%M%S", &sCurTime); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; } iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; if (iBufLeftSize > 0) { iCurUsedSize = WelsStrftime (&chFileNameSize[iBufUsedSize], iBufLeftSize, "%y%m%d%H%M%S", &sCurTime); iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; } if (iBufLeft > 0) { iCurUsed = WelsSnprintf (&chFileName[iBufUsed], iBufLeft, ".%03.3u.264", WelsGetMillisecond (&sCurTime)); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; } if (iBufLeftSize > 0) { iCurUsedSize = WelsSnprintf (&chFileNameSize[iBufUsedSize], iBufLeftSize, ".%03.3u.len", WelsGetMillisecond (&sCurTime)); iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; } m_pFBS = WelsFopen (chFileName, "wb"); m_pFBSSize = WelsFopen (chFileNameSize, "wb");#endif//OUTPUT_BIT_STREAM} /**************************************************************************** Description:* class CWelsDecoder destructor function, destroy allocced memory** Input parameters: none** return: none***************************************************************************/CWelsDecoder::~CWelsDecoder() { if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::~CWelsDecoder()"); } CloseDecoderThreads(); UninitDecoder(); #ifdef OUTPUT_BIT_STREAM if (m_pFBS) { WelsFclose (m_pFBS); m_pFBS = NULL; } if (m_pFBSSize) { WelsFclose (m_pFBSSize); m_pFBSSize = NULL; }#endif//OUTPUT_BIT_STREAM if (m_pWelsTrace != NULL) { delete m_pWelsTrace; m_pWelsTrace = NULL; } if (m_pDecThrCtx != NULL) { delete[] m_pDecThrCtx; m_pDecThrCtx = NULL; }} long CWelsDecoder::Initialize (const SDecodingParam* pParam) { int iRet = ERR_NONE; if (m_pWelsTrace == NULL) { return cmMallocMemeError; } if (pParam == NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsDecoder::Initialize(), invalid input argument."); return cmInitParaError; } // H.264 decoder initialization,including memory allocation,then open it ready to decode iRet = InitDecoder (pParam); if (iRet) return iRet; return cmResultSuccess;} long CWelsDecoder::Uninitialize() { UninitDecoder(); return ERR_NONE;} void CWelsDecoder::UninitDecoder (void) { for (int32_t i = 0; i < m_iCtxCount; ++i) { if (m_pDecThrCtx[i].pCtx != NULL) { if (i > 0) { WelsResetRefPicWithoutUnRef (m_pDecThrCtx[i].pCtx); } UninitDecoderCtx (m_pDecThrCtx[i].pCtx); } }} void CWelsDecoder::OpenDecoderThreads() { if (m_iThreadCount >= 1) { m_uiDecodeTimeStamp = 0; CREATE_SEMAPHORE (&m_sIsBusy, m_iThreadCount, m_iThreadCount, NULL); WelsMutexInit (&m_csDecoder); CREATE_EVENT (&m_sBufferingEvent, 1, 0, NULL); SET_EVENT (&m_sBufferingEvent); CREATE_EVENT (&m_sReleaseBufferEvent, 1, 0, NULL); SET_EVENT (&m_sReleaseBufferEvent); for (int32_t i = 0; i < m_iThreadCount; ++i) { m_pDecThrCtx[i].sThreadInfo.uiThrMaxNum = m_iThreadCount; m_pDecThrCtx[i].sThreadInfo.uiThrNum = i; m_pDecThrCtx[i].sThreadInfo.uiThrStackSize = WELS_DEC_MAX_THREAD_STACK_SIZE; m_pDecThrCtx[i].sThreadInfo.pThrProcMain = pThrProcFrame; m_pDecThrCtx[i].sThreadInfo.sIsBusy = &m_sIsBusy; m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_RUN; m_pDecThrCtx[i].threadCtxOwner = this; m_pDecThrCtx[i].kpSrc = NULL; m_pDecThrCtx[i].kiSrcLen = 0; m_pDecThrCtx[i].ppDst = NULL; m_pDecThrCtx[i].pDec = NULL; CREATE_EVENT (&m_pDecThrCtx[i].sImageReady, 1, 0, NULL); CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart, 1, 0, NULL); CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish, 1, 0, NULL); CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, 0, 1, NULL); CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated, 0, 1, NULL); CREATE_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle, pThrProcInit, (void*) (& (m_pDecThrCtx[i]))); } }}void CWelsDecoder::CloseDecoderThreads() { if (m_iThreadCount >= 1) { for (int32_t i = 0; i < m_iThreadCount; i++) { //waiting the completion begun slices WAIT_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_ABORT; RELEASE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); WAIT_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle); CLOSE_EVENT (&m_pDecThrCtx[i].sImageReady); CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart); CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish); CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle); CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); } WelsMutexDestroy (&m_csDecoder); CLOSE_EVENT (&m_sBufferingEvent); CLOSE_EVENT (&m_sReleaseBufferEvent); CLOSE_SEMAPHORE (&m_sIsBusy); }} void CWelsDecoder::UninitDecoderCtx (PWelsDecoderContext& pCtx) { if (pCtx != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::UninitDecoderCtx(), openh264 codec version = %s.", VERSION_NUMBER); WelsEndDecoder (pCtx); if (pCtx->pMemAlign != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::UninitDecoder(), verify memory usage (%d bytes) after free..", pCtx->pMemAlign->WelsGetMemoryUsage()); delete pCtx->pMemAlign; pCtx->pMemAlign = NULL; } if (NULL != pCtx) { WelsFree (pCtx, "m_pDecContext"); pCtx = NULL; } if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = NULL; }} // 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); if (m_iThreadCount >= 1 && pParam->bParseOnly) { m_iThreadCount = 0; } OpenDecoderThreads(); //reset decoder context memset (&m_sDecoderStatistics, 0, sizeof (SDecoderStatistics)); memset (&m_sLastDecPicInfo, 0, sizeof (SWelsLastDecPicInfo)); memset (&m_sVlcTable, 0, sizeof (SVlcTable)); UninitDecoder(); WelsDecoderLastDecPicInfoDefaults (m_sLastDecPicInfo); for (int32_t i = 0; i < m_iCtxCount; ++i) { InitDecoderCtx (m_pDecThrCtx[i].pCtx, pParam); if (m_iThreadCount >= 1) { m_pDecThrCtx[i].pCtx->pThreadCtx = &m_pDecThrCtx[i]; } } m_bParamSetsLostFlag = false; m_bFreezeOutput = false; return cmResultSuccess;} // the return value of this function is not suitable, it need report failure info to upper layer.int32_t CWelsDecoder::InitDecoderCtx (PWelsDecoderContext& pCtx, 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 UninitDecoderCtx (pCtx); pCtx = (PWelsDecoderContext)WelsMallocz (sizeof (SWelsDecoderContext), "m_pDecContext"); if (NULL == pCtx) return cmMallocMemeError; int32_t iCacheLineSize = 16; // on chip cache line size in byte pCtx->pMemAlign = new CMemoryAlign (iCacheLineSize); WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pMemAlign), UninitDecoderCtx (pCtx)) if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = pCtx; //fill in default value into context pCtx->pLastDecPicInfo = &m_sLastDecPicInfo; pCtx->pDecoderStatistics = &m_sDecoderStatistics; pCtx->pVlcTable = &m_sVlcTable; pCtx->pPictInfoList = m_sPictInfoList; pCtx->pPictReoderingStatus = &m_sReoderingStatus; pCtx->pCsDecoder = &m_csDecoder; WelsDecoderDefaults (pCtx, &m_pWelsTrace->m_sLogCtx); WelsDecoderSpsPpsDefaults (pCtx->sSpsPpsCtx); //check param and update decoder context pCtx->pParam = (SDecodingParam*)pCtx->pMemAlign->WelsMallocz (sizeof (SDecodingParam), "SDecodingParam"); WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pParam), UninitDecoderCtx (pCtx)); int32_t iRet = DecoderConfigParam (pCtx, pParam); WELS_VERIFY_RETURN_IFNEQ (iRet, cmResultSuccess); //init decoder WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, WelsInitDecoder (pCtx, &m_pWelsTrace->m_sLogCtx), UninitDecoderCtx (pCtx)) pCtx->pPicBuff = NULL; return cmResultSuccess;} int32_t CWelsDecoder::ResetDecoder (PWelsDecoderContext& pCtx) { // TBC: need to be modified when context and trace point are null if (m_iThreadCount >= 1) { ThreadResetDecoder (pCtx); } else { if (pCtx != NULL && m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", pCtx->iErrorCode); SDecodingParam sPrevParam; memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); WELS_VERIFY_RETURN_PROC_IF (cmInitParaError, InitDecoderCtx (pCtx, &sPrevParam), UninitDecoderCtx (pCtx)); } else if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); } ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, false); } return ERR_INFO_UNINIT;} int32_t CWelsDecoder::ThreadResetDecoder (PWelsDecoderContext& pCtx) { // TBC: need to be modified when context and trace point are null SDecodingParam sPrevParam; if (pCtx != NULL && m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", pCtx->iErrorCode); memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); CloseDecoderThreads(); UninitDecoder(); InitDecoder (&sPrevParam); } else if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); } return ERR_INFO_UNINIT;} /* * Set Option */long CWelsDecoder::SetOption (DECODER_OPTION eOptID, void* pOption) { int iVal = 0; if (eOptID == DECODER_OPTION_NUM_OF_THREADS) { if (pOption != NULL) { int32_t threadCount = * ((int32_t*)pOption); if (threadCount < 0) threadCount = 0; if (threadCount > m_iCpuCount) { threadCount = m_iCpuCount; } if (threadCount > 3) { threadCount = 3; } if (threadCount != m_iThreadCount) { m_iThreadCount = threadCount; if (m_pDecThrCtx != NULL) { delete [] m_pDecThrCtx; m_iCtxCount = m_iThreadCount == 0 ? 1 : m_iThreadCount; m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); } } } return cmResultSuccess; } for (int32_t i = 0; i < m_iCtxCount; ++i) {Lines 1–500 of 1506. 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. * * * welsDecoderExt.cpp * * Abstract * Cisco OpenH264 decoder extension utilization * * History * 3/12/2009 Created * * ************************************************************************/ //#include <assert.h> #include "welsDecoderExt.h" #include "welsCodecTrace.h" #include "codec_def.h" #include "typedefs.h" #include "memory_align.h" #include "utils.h" #include "version.h" //#include "macros.h" #include "decoder.h" #include "decoder_core.h" #include "manage_dec_ref.h" #include "error_concealment.h" #include "measure_time.h" extern "C" { #include "decoder_core.h" #include "manage_dec_ref.h" } #include "error_code.h" #include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms #include <time.h> #if defined(_WIN32) /*&& defined(_DEBUG)*/ #include <windows.h> #include <stdio.h> #include <stdarg.h> #include <sys/types.h> #include <malloc.h> #else #include <sys/time.h> #endif namespace WelsDec { ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// /*************************************************************************** * Description: * class CWelsDecoder constructor function, do initialization and * alloc memory required * * Input parameters: none * * return: none ***************************************************************************/ DECLARE_PROCTHREAD (pThrProcInit, p) { SWelsDecThreadInfo* sThreadInfo = (SWelsDecThreadInfo*)p; #if defined(WIN32) _alloca (WELS_DEC_MAX_THREAD_STACK_SIZE * (sThreadInfo->uiThrNum + 1)); #endif return sThreadInfo->pThrProcMain (p); } static DECODING_STATE ConstructAccessUnit (CWelsDecoder* pWelsDecoder, PWelsDecoderThreadCTX pThrCtx) { int iRet = dsErrorFree; //WelsMutexLock (&pWelsDecoder->m_csDecoder); if (pThrCtx->pCtx->pLastThreadCtx != NULL) { PWelsDecoderThreadCTX pLastThreadCtx = (PWelsDecoderThreadCTX) (pThrCtx->pCtx->pLastThreadCtx); WAIT_EVENT (&pLastThreadCtx->sSliceDecodeStart, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&pLastThreadCtx->sSliceDecodeStart); } pThrCtx->pDec = NULL; if (GetThreadCount (pThrCtx->pCtx) > 1) { RESET_EVENT (&pThrCtx->sSliceDecodeFinish); } iRet |= pWelsDecoder->DecodeFrame2WithCtx (pThrCtx->pCtx, NULL, 0, pThrCtx->ppDst, &pThrCtx->sDstInfo); //WelsMutexUnlock (&pWelsDecoder->m_csDecoder); return (DECODING_STATE)iRet; } DECLARE_PROCTHREAD (pThrProcFrame, p) { SWelsDecoderThreadCTX* pThrCtx = (SWelsDecoderThreadCTX*)p; while (1) { RELEASE_SEMAPHORE (pThrCtx->sThreadInfo.sIsBusy); RELEASE_SEMAPHORE (&pThrCtx->sThreadInfo.sIsIdle); WAIT_SEMAPHORE (&pThrCtx->sThreadInfo.sIsActivated, WELS_DEC_THREAD_WAIT_INFINITE); if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_RUN) { CWelsDecoder* pWelsDecoder = (CWelsDecoder*)pThrCtx->threadCtxOwner; ConstructAccessUnit (pWelsDecoder, pThrCtx); } else if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_ABORT) { break; } } return 0; } CWelsDecoder::CWelsDecoder (void) : m_pWelsTrace (NULL), m_uiDecodeTimeStamp (0), m_bIsBaseline (false), m_iCpuCount (1), m_iThreadCount (0), m_iCtxCount (1), m_pPicBuff (NULL), m_bParamSetsLostFlag (false), m_bFreezeOutput (false), m_DecCtxActiveCount (0), m_pDecThrCtx (NULL), m_pLastDecThrCtx (NULL), m_iLastBufferedIdx (0) { #ifdef OUTPUT_BIT_STREAM char chFileName[1024] = { 0 }; //for .264 int iBufUsed = 0; int iBufLeft = 1023; int iCurUsed; char chFileNameSize[1024] = { 0 }; //for .len int iBufUsedSize = 0; int iBufLeftSize = 1023; int iCurUsedSize; #endif//OUTPUT_BIT_STREAM m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace != NULL) { m_pWelsTrace->SetCodecInstance (this); m_pWelsTrace->SetTraceLevel (WELS_LOG_ERROR); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::CWelsDecoder() entry"); } ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); m_iCpuCount = GetCPUCount(); if (m_iCpuCount > WELS_DEC_MAX_NUM_CPU) { m_iCpuCount = WELS_DEC_MAX_NUM_CPU; } m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); for (int32_t i = 0; i < WELS_DEC_MAX_NUM_CPU; ++i) { m_pDecThrCtxActive[i] = NULL; } #ifdef OUTPUT_BIT_STREAM SWelsTime sCurTime; WelsGetTimeOfDay (&sCurTime); iCurUsed = WelsSnprintf (chFileName, iBufLeft, "bs_0x%p_", (void*)this); iCurUsedSize = WelsSnprintf (chFileNameSize, iBufLeftSize, "size_0x%p_", (void*)this); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; if (iBufLeft > 0) { iCurUsed = WelsStrftime (&chFileName[iBufUsed], iBufLeft, "%y%m%d%H%M%S", &sCurTime); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; } iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; if (iBufLeftSize > 0) { iCurUsedSize = WelsStrftime (&chFileNameSize[iBufUsedSize], iBufLeftSize, "%y%m%d%H%M%S", &sCurTime); iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; } if (iBufLeft > 0) { iCurUsed = WelsSnprintf (&chFileName[iBufUsed], iBufLeft, ".%03.3u.264", WelsGetMillisecond (&sCurTime)); iBufUsed += iCurUsed; iBufLeft -= iCurUsed; } if (iBufLeftSize > 0) { iCurUsedSize = WelsSnprintf (&chFileNameSize[iBufUsedSize], iBufLeftSize, ".%03.3u.len", WelsGetMillisecond (&sCurTime)); iBufUsedSize += iCurUsedSize; iBufLeftSize -= iCurUsedSize; } m_pFBS = WelsFopen (chFileName, "wb"); m_pFBSSize = WelsFopen (chFileNameSize, "wb"); #endif//OUTPUT_BIT_STREAM } /*************************************************************************** * Description: * class CWelsDecoder destructor function, destroy allocced memory * * Input parameters: none * * return: none ***************************************************************************/ CWelsDecoder::~CWelsDecoder() { if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::~CWelsDecoder()"); } CloseDecoderThreads(); UninitDecoder(); #ifdef OUTPUT_BIT_STREAM if (m_pFBS) { WelsFclose (m_pFBS); m_pFBS = NULL; } if (m_pFBSSize) { WelsFclose (m_pFBSSize); m_pFBSSize = NULL; } #endif//OUTPUT_BIT_STREAM if (m_pWelsTrace != NULL) { delete m_pWelsTrace; m_pWelsTrace = NULL; } if (m_pDecThrCtx != NULL) { delete[] m_pDecThrCtx; m_pDecThrCtx = NULL; } } long CWelsDecoder::Initialize (const SDecodingParam* pParam) { int iRet = ERR_NONE; if (m_pWelsTrace == NULL) { return cmMallocMemeError; } if (pParam == NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsDecoder::Initialize(), invalid input argument."); return cmInitParaError; } // H.264 decoder initialization,including memory allocation,then open it ready to decode iRet = InitDecoder (pParam); if (iRet) return iRet; return cmResultSuccess; } long CWelsDecoder::Uninitialize() { UninitDecoder(); return ERR_NONE; } void CWelsDecoder::UninitDecoder (void) { for (int32_t i = 0; i < m_iCtxCount; ++i) { if (m_pDecThrCtx[i].pCtx != NULL) { if (i > 0) { WelsResetRefPicWithoutUnRef (m_pDecThrCtx[i].pCtx); } UninitDecoderCtx (m_pDecThrCtx[i].pCtx); } } } void CWelsDecoder::OpenDecoderThreads() { if (m_iThreadCount >= 1) { m_uiDecodeTimeStamp = 0; CREATE_SEMAPHORE (&m_sIsBusy, m_iThreadCount, m_iThreadCount, NULL); WelsMutexInit (&m_csDecoder); CREATE_EVENT (&m_sBufferingEvent, 1, 0, NULL); SET_EVENT (&m_sBufferingEvent); CREATE_EVENT (&m_sReleaseBufferEvent, 1, 0, NULL); SET_EVENT (&m_sReleaseBufferEvent); for (int32_t i = 0; i < m_iThreadCount; ++i) { m_pDecThrCtx[i].sThreadInfo.uiThrMaxNum = m_iThreadCount; m_pDecThrCtx[i].sThreadInfo.uiThrNum = i; m_pDecThrCtx[i].sThreadInfo.uiThrStackSize = WELS_DEC_MAX_THREAD_STACK_SIZE; m_pDecThrCtx[i].sThreadInfo.pThrProcMain = pThrProcFrame; m_pDecThrCtx[i].sThreadInfo.sIsBusy = &m_sIsBusy; m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_RUN; m_pDecThrCtx[i].threadCtxOwner = this; m_pDecThrCtx[i].kpSrc = NULL; m_pDecThrCtx[i].kiSrcLen = 0; m_pDecThrCtx[i].ppDst = NULL; m_pDecThrCtx[i].pDec = NULL; CREATE_EVENT (&m_pDecThrCtx[i].sImageReady, 1, 0, NULL); CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart, 1, 0, NULL); CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish, 1, 0, NULL); CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, 0, 1, NULL); CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated, 0, 1, NULL); CREATE_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle, pThrProcInit, (void*) (& (m_pDecThrCtx[i]))); } } } void CWelsDecoder::CloseDecoderThreads() { if (m_iThreadCount >= 1) { for (int32_t i = 0; i < m_iThreadCount; i++) { //waiting the completion begun slices WAIT_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_ABORT; RELEASE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); WAIT_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle); CLOSE_EVENT (&m_pDecThrCtx[i].sImageReady); CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart); CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish); CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle); CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); } WelsMutexDestroy (&m_csDecoder); CLOSE_EVENT (&m_sBufferingEvent); CLOSE_EVENT (&m_sReleaseBufferEvent); CLOSE_SEMAPHORE (&m_sIsBusy); } } void CWelsDecoder::UninitDecoderCtx (PWelsDecoderContext& pCtx) { if (pCtx != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::UninitDecoderCtx(), openh264 codec version = %s.", VERSION_NUMBER); WelsEndDecoder (pCtx); if (pCtx->pMemAlign != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::UninitDecoder(), verify memory usage (%d bytes) after free..", pCtx->pMemAlign->WelsGetMemoryUsage()); delete pCtx->pMemAlign; pCtx->pMemAlign = NULL; } if (NULL != pCtx) { WelsFree (pCtx, "m_pDecContext"); pCtx = NULL; } if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = NULL; } } // 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); if (m_iThreadCount >= 1 && pParam->bParseOnly) { m_iThreadCount = 0; } OpenDecoderThreads(); //reset decoder context memset (&m_sDecoderStatistics, 0, sizeof (SDecoderStatistics)); memset (&m_sLastDecPicInfo, 0, sizeof (SWelsLastDecPicInfo)); memset (&m_sVlcTable, 0, sizeof (SVlcTable)); UninitDecoder(); WelsDecoderLastDecPicInfoDefaults (m_sLastDecPicInfo); for (int32_t i = 0; i < m_iCtxCount; ++i) { InitDecoderCtx (m_pDecThrCtx[i].pCtx, pParam); if (m_iThreadCount >= 1) { m_pDecThrCtx[i].pCtx->pThreadCtx = &m_pDecThrCtx[i]; } } m_bParamSetsLostFlag = false; m_bFreezeOutput = false; return cmResultSuccess; } // the return value of this function is not suitable, it need report failure info to upper layer. int32_t CWelsDecoder::InitDecoderCtx (PWelsDecoderContext& pCtx, 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 UninitDecoderCtx (pCtx); pCtx = (PWelsDecoderContext)WelsMallocz (sizeof (SWelsDecoderContext), "m_pDecContext"); if (NULL == pCtx) return cmMallocMemeError; int32_t iCacheLineSize = 16; // on chip cache line size in byte pCtx->pMemAlign = new CMemoryAlign (iCacheLineSize); WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pMemAlign), UninitDecoderCtx (pCtx)) if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = pCtx; //fill in default value into context pCtx->pLastDecPicInfo = &m_sLastDecPicInfo; pCtx->pDecoderStatistics = &m_sDecoderStatistics; pCtx->pVlcTable = &m_sVlcTable; pCtx->pPictInfoList = m_sPictInfoList; pCtx->pPictReoderingStatus = &m_sReoderingStatus; pCtx->pCsDecoder = &m_csDecoder; WelsDecoderDefaults (pCtx, &m_pWelsTrace->m_sLogCtx); WelsDecoderSpsPpsDefaults (pCtx->sSpsPpsCtx); //check param and update decoder context pCtx->pParam = (SDecodingParam*)pCtx->pMemAlign->WelsMallocz (sizeof (SDecodingParam), "SDecodingParam"); WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pParam), UninitDecoderCtx (pCtx)); int32_t iRet = DecoderConfigParam (pCtx, pParam); WELS_VERIFY_RETURN_IFNEQ (iRet, cmResultSuccess); //init decoder WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, WelsInitDecoder (pCtx, &m_pWelsTrace->m_sLogCtx), UninitDecoderCtx (pCtx)) pCtx->pPicBuff = NULL; return cmResultSuccess; } int32_t CWelsDecoder::ResetDecoder (PWelsDecoderContext& pCtx) { // TBC: need to be modified when context and trace point are null if (m_iThreadCount >= 1) { ThreadResetDecoder (pCtx); } else { if (pCtx != NULL && m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", pCtx->iErrorCode); SDecodingParam sPrevParam; memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); WELS_VERIFY_RETURN_PROC_IF (cmInitParaError, InitDecoderCtx (pCtx, &sPrevParam), UninitDecoderCtx (pCtx)); } else if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); } ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, false); } return ERR_INFO_UNINIT; } int32_t CWelsDecoder::ThreadResetDecoder (PWelsDecoderContext& pCtx) { // TBC: need to be modified when context and trace point are null SDecodingParam sPrevParam; if (pCtx != NULL && m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", pCtx->iErrorCode); memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); CloseDecoderThreads(); UninitDecoder(); InitDecoder (&sPrevParam); } else if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); } return ERR_INFO_UNINIT; } /* * Set Option */ long CWelsDecoder::SetOption (DECODER_OPTION eOptID, void* pOption) { int iVal = 0; if (eOptID == DECODER_OPTION_NUM_OF_THREADS) { if (pOption != NULL) { int32_t threadCount = * ((int32_t*)pOption); if (threadCount < 0) threadCount = 0; if (threadCount > m_iCpuCount) { threadCount = m_iCpuCount; } if (threadCount > 3) { threadCount = 3; } if (threadCount != m_iThreadCount) { m_iThreadCount = threadCount; if (m_pDecThrCtx != NULL) { delete [] m_pDecThrCtx; m_iCtxCount = m_iThreadCount == 0 ? 1 : m_iThreadCount; m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); } } } return cmResultSuccess; } for (int32_t i = 0; i < m_iCtxCount; ++i) {