/*! * \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 #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 #if defined(WIN32) /*&& defined(_DEBUG)*/ #include #include #include #include #include #else #include #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::Unintialize() { 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; pDecoder = NULL; } }