ref: 80669ed0596a908f865e673b4f0625bb4f0db27b
dir: /codec/decoder/plus/src/welsDecoderExt.cpp/
/*! * \copy * Copyright (c) 2009-2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * 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 "mem_align.h" #include "utils.h" //#include "macros.h" #include "decoder.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 <sys/timeb.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 ***************************************************************************/ CWelsDecoder::CWelsDecoder (void_t) : m_pDecContext (NULL), m_pTrace (NULL) { #ifdef OUTPUT_BIT_STREAM str_t chFileName[1024] = { 0 }; //for .264 int iBufUsed = 0; int iBufLeft = 1023; str_t chFileNameSize[1024] = { 0 }; //for .len int iBufUsedSize = 0; int iBufLeftSize = 1023; #endif//OUTPUT_BIT_STREAM m_pTrace = CreateWelsTrace (Wels_Trace_Type); IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "CWelsDecoder::CWelsDecoder() entry"); #ifdef OUTPUT_BIT_STREAM SWelsTime sCurTime; WelsGetTimeOfDay (&sCurTime); iBufUsed += WelsSnprintf (chFileName, iBufLeft, "bs_0x%p_", (void_t*)this); iBufUsedSize += WelsSnprintf (chFileNameSize, iBufLeftSize, "size_0x%p_", (void_t*)this); iBufLeft -= iBufUsed; if (iBufLeft > iBufUsed) { iBufUsed += WelsStrftime (&chFileName[iBufUsed], iBufLeft, "%y%m%d%H%M%S", &sCurTime); iBufLeft -= iBufUsed; } iBufLeftSize -= iBufUsedSize; if (iBufLeftSize > iBufUsedSize) { iBufUsedSize += WelsStrftime (&chFileNameSize[iBufUsedSize], iBufLeftSize, "%y%m%d%H%M%S", &sCurTime); iBufLeftSize -= iBufUsedSize; } if (iBufLeft > iBufUsed) { iBufUsed += WelsSnprintf (&chFileName[iBufUsed], iBufLeft, ".%03.3u.264", WelsGetMillsecond (&sCurTime)); iBufLeft -= iBufUsed; } if (iBufLeftSize > iBufUsedSize) { iBufUsedSize += WelsSnprintf (&chFileNameSize[iBufUsedSize], iBufLeftSize, ".%03.3u.len", WelsGetMillsecond (&sCurTime)); iBufLeftSize -= iBufUsedSize; } 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() { IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "CWelsDecoder::~CWelsDecoder()"); 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 (NULL != m_pTrace) { delete m_pTrace; m_pTrace = NULL; } } long CWelsDecoder::Initialize (void_t* pParam, const INIT_TYPE keInitType) { if (pParam == NULL || keInitType != INIT_TYPE_PARAMETER_BASED) { IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "CWelsDecoder::Initialize(), invalid input argument."); return cmInitParaError; } // H.264 decoder initialization,including memory allocation,then open it ready to decode InitDecoder(); DecoderConfigParam (m_pDecContext, pParam); return cmResultSuccess; } long CWelsDecoder::Uninitialize() { UninitDecoder(); return ERR_NONE; } void_t CWelsDecoder::UninitDecoder (void_t) { if (NULL == m_pDecContext) return; IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "into CWelsDecoder::uninit_decoder().."); WelsEndDecoder (m_pDecContext); if (NULL != m_pDecContext) { WelsFree (m_pDecContext, "m_pDecContext"); m_pDecContext = NULL; } IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "left CWelsDecoder::uninit_decoder().."); } // the return value of this function is not suitable, it need report failure info to upper layer. void_t CWelsDecoder::InitDecoder (void_t) { IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "CWelsDecoder::init_decoder().."); m_pDecContext = (PWelsDecoderContext)WelsMalloc (sizeof (SWelsDecoderContext), "m_pDecContext"); WelsInitDecoder (m_pDecContext, m_pTrace, IWelsTrace::WelsTrace); IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "CWelsDecoder::init_decoder().. left"); } /* * Set Option */ long CWelsDecoder::SetOption (DECODER_OPTION eOptID, void_t* pOption) { int iVal = 0; if (m_pDecContext == NULL) return dsInitialOptExpected; if (eOptID == DECODER_OPTION_DATAFORMAT) { // Set color space of decoding output frame if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); // is_rgb return DecoderSetCsp (m_pDecContext, iVal); } else if (eOptID == DECODER_OPTION_END_OF_STREAM) { // Indicate bit-stream of the final frame to be decoded if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); // boolean value for whether enabled End Of Stream flag m_pDecContext->bEndOfStreamFlag = iVal ? true : false; return cmResultSuccess; } else if (eOptID == DECODER_OPTION_MODE) { if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); m_pDecContext->iSetMode = iVal; if (iVal == SW_MODE) { m_pDecContext->iDecoderOutputProperty = BUFFER_HOST; } else { #if !defined(__APPLE__) m_pDecContext->iDecoderOutputProperty = BUFFER_DEVICE; #else m_pDecContext->iDecoderOutputProperty = BUFFER_HOST;//BUFFER_HOST;//BUFFER_DEVICE; #endif } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_OUTPUT_PROPERTY) { if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); if (m_pDecContext->iSetMode != SW_MODE) m_pDecContext->iDecoderOutputProperty = iVal; } return cmInitParaError; } /* * Get Option */ long CWelsDecoder::GetOption (DECODER_OPTION eOptID, void_t* pOption) { int iVal = 0; if (m_pDecContext == NULL) return cmInitExpected; if (pOption == NULL) return cmInitParaError; if (DECODER_OPTION_DATAFORMAT == eOptID) { iVal = m_pDecContext->iOutputColorFormat; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_END_OF_STREAM == eOptID) { iVal = m_pDecContext->bEndOfStreamFlag; * ((int*)pOption) = iVal; return cmResultSuccess; } #ifdef LONG_TERM_REF else if (DECODER_OPTION_IDR_PIC_ID == eOptID) { iVal = m_pDecContext->uiCurIdrPicId; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_FRAME_NUM == eOptID) { iVal = m_pDecContext->iFrameNum; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKING_FLAG == eOptID) { iVal = m_pDecContext->bCurAuContainLtrMarkSeFlag; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKED_FRAME_NUM == eOptID) { iVal = m_pDecContext->iFrameNumOfAuMarkedLtr; * ((int*)pOption) = iVal; return cmResultSuccess; } #endif else if (DECODER_OPTION_VCL_NAL == eOptID) { //feedback whether or not have VCL NAL in current AU iVal = m_pDecContext->iFeedbackVclNalInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_TEMPORAL_ID == eOptID) { //if have VCL NAL in current AU, then feedback the temporal ID iVal = m_pDecContext->iFeedbackTidInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_MODE == eOptID) { if (pOption == NULL) return cmInitParaError; iVal = m_pDecContext->iSetMode; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_DEVICE_INFO == eOptID) { if (pOption == NULL) return cmInitParaError; return cmResultSuccess; } return cmInitParaError; } DECODING_STATE CWelsDecoder::DecodeFrame (const unsigned char* kpSrc, const int kiSrcLen, void_t** ppDst, SBufferInfo* pDstInfo) { if (kiSrcLen > 0 && kpSrc != NULL) { #ifdef OUTPUT_BIT_STREAM if (m_pFBS) { WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS); WelsFflush (m_pFBS); } if (m_pFBSSize) { WelsFwrite (&kiSrcLen, sizeof (int), 1, m_pFBSSize); WelsFflush (m_pFBSSize); } #endif//OUTPUT_BIT_STREAM m_pDecContext->bEndOfStreamFlag = false; } else { //For application MODE, the error detection should be added for safe. //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL. m_pDecContext->bEndOfStreamFlag = true; } ppDst[0] = ppDst[1] = ppDst[2] = NULL; m_pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding. m_pDecContext->iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL; //initialize memset (pDstInfo, 0, sizeof (SBufferInfo)); pDstInfo->eBufferProperty = (EBufferProperty)m_pDecContext->iDecoderOutputProperty; #ifdef LONG_TERM_REF m_pDecContext->bReferenceLostAtT0Flag = false; //initialize for LTR m_pDecContext->bCurAuContainLtrMarkSeFlag = false; m_pDecContext->iFrameNumOfAuMarkedLtr = 0; m_pDecContext->iFrameNum = -1; //initialize #endif m_pDecContext->iFeedbackTidInAu = -1; //initialize WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, (unsigned char**)ppDst, pDstInfo); //iErrorCode has been modified in this function pDstInfo->eWorkMode = (EDecodeMode)m_pDecContext->iDecoderMode; if (m_pDecContext->iErrorCode) { ENalUnitType eNalType = NAL_UNIT_UNSPEC_0; //for NBR, IDR frames are expected to decode as followed if error decoding an IDR currently eNalType = m_pDecContext->sCurNalHead.eNalUnitType; //for AVC bitstream (excluding AVC with temporal scalability, including TP), as long as error occur, SHOULD notify upper layer key frame loss. if ((IS_PARAM_SETS_NALS (eNalType) || NAL_UNIT_CODED_SLICE_IDR == eNalType) || (VIDEO_BITSTREAM_AVC == m_pDecContext->eVideoType)) { #ifdef LONG_TERM_REF m_pDecContext->bParamSetsLostFlag = true; #else m_pDecContext->bReferenceLostAtT0Flag = true; #endif ResetParameterSetsState (m_pDecContext); //initial SPS&PPS ready flag } IWelsTrace::WelsVTrace (m_pTrace, IWelsTrace::WELS_LOG_INFO, "decode failed, failure type:%d \n", m_pDecContext->iErrorCode); return (DECODING_STATE)m_pDecContext->iErrorCode; } return dsErrorFree; } DECODING_STATE CWelsDecoder::DecodeFrame (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, int* pStride, int& iWidth, int& iHeight) { DECODING_STATE eDecState = dsErrorFree; SBufferInfo DstInfo; memset (&DstInfo, 0, sizeof (SBufferInfo)); DstInfo.UsrData.sSystemBuffer.iStride[0] = pStride[0]; DstInfo.UsrData.sSystemBuffer.iStride[1] = pStride[1]; DstInfo.UsrData.sSystemBuffer.iWidth = iWidth; DstInfo.UsrData.sSystemBuffer.iHeight = iHeight; DstInfo.eBufferProperty = BUFFER_HOST; eDecState = DecodeFrame (kpSrc, kiSrcLen, (void_t**)ppDst, &DstInfo); if (eDecState == dsErrorFree) { pStride[0] = DstInfo.UsrData.sSystemBuffer.iStride[0]; pStride[1] = DstInfo.UsrData.sSystemBuffer.iStride[1]; iWidth = DstInfo.UsrData.sSystemBuffer.iWidth; iHeight = DstInfo.UsrData.sSystemBuffer.iHeight; } return eDecState; } DECODING_STATE CWelsDecoder::DecodeFrameEx (const unsigned char* kpSrc, const int kiSrcLen, unsigned char* pDst, int iDstStride, int& iDstLen, int& iWidth, int& iHeight, int& iColorFormat) { DECODING_STATE state = dsErrorFree; return state; } } // namespace WelsDec using namespace WelsDec; /* WINAPI is indeed in prefix due to sync to application layer callings!! */ /* * CreateDecoder * @return: success in return 0, otherwise failed. */ long CreateDecoder (ISVCDecoder** ppDecoder) { if (NULL == ppDecoder) { return ERR_INVALID_PARAMETERS; } *ppDecoder = new CWelsDecoder(); if (NULL == *ppDecoder) { return ERR_MALLOC_FAILED; } return ERR_NONE; } /* * DestroyDecoder */ void_t DestroyDecoder (ISVCDecoder* pDecoder) { if (NULL != pDecoder) { delete (CWelsDecoder*)pDecoder; } }