/*! * \copy * Copyright (c) 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. * */ #include <assert.h>#include "welsEncoderExt.h"#include "welsCodecTrace.h"#include "typedefs.h"#include "wels_const.h"#include "utils.h"#include "macros.h" #include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms#include "ref_list_mgr_svc.h" #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 WelsSVCEnc { /* * CWelsH264SVCEncoder class implementation */CWelsH264SVCEncoder::CWelsH264SVCEncoder() : m_pEncContext (NULL),#if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) m_pWelsTrace (NULL),#endif m_pSrcPicList (NULL), m_iSrcListSize (0), m_iMaxPicWidth (0), m_iMaxPicHeight (0), m_iCspInternal (0), m_bInitialFlag (FALSE) {#ifdef REC_FRAME_COUNT int32_t m_uiCountFrameNum = 0;#endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM str_t strStreamFileName[1024] = { 0 }; //for .264 int32_t iBufferUsed = 0; int32_t iBufferLeft = 1023; str_t strLenFileName[1024] = { 0 }; //for .len int32_t iBufferUsedSize = 0; int32_t iBufferLeftSize = 1023;#endif//OUTPUT_BIT_STREAM #ifdef OUTPUT_BIT_STREAM time_t tTime; #if defined( _WIN32 )#if defined(_MSC_VER)#if _MSC_VER>=1500 struct tm tTimeNow;#else struct tm* tTimeNow;#endif//_MSC_VER>=1500#endif//_MSC_VER struct _timeb tTimeb; time (&tTime);#if defined(_MSC_VER)#if _MSC_VER>=1500 LOCALTIME (&tTimeNow, &tTime);#else tTimeNow = LOCALTIME (&tTime); if (NULL == tTimeNow) return;#endif//_MSC_VER>=1500#endif//_MSC_VER FTIME (&tTimeb);#elif defined( __GNUC__ ) struct tm* tTimeNow; struct timeval tTimev; time (&tTime); tTimeNow = (struct tm*)localtime (&tTime); gettimeofday (&tTimev, NULL);#endif//WIN32 #ifdef _WIN32#if defined(_MSC_VER)#if _MSC_VER>=1500 iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, iBufferLeft, "enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, iBufferLeftSize, "enc_size_0x%p_", (void*)this);#else iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, "enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, "enc_size_0x%p_", (void*)this);#endif//_MSC_VER>=1500#endif//_MSC_VER#else iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, "/tmp/enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, "/tmp/enc_size_0x%p", (void*)this);#endif//WIN32 iBufferLeft -= iBufferUsed; if (iBufferLeft > iBufferUsed) {#if defined(_GNUC__) iBufferUsed += strftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S", tTimeNow);#else#if defined(_MSC_VER) iBufferUsed += strftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S",#if _MSC_VER>=1500 & tTimeNow#else tTimeNow#endif//_MSC_VER>=1500 );#endif//_MSC_VER#endif//__GNUC__ iBufferLeft -= iBufferUsed; } iBufferLeftSize -= iBufferUsedSize; if (iBufferLeftSize > iBufferUsedSize) {#if defined(_GNUC__) iBufferUsedSize += strftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S", tTimeNow);#else#if defined(_MSC_VER) iBufferUsedSize += strftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S",#if _MSC_VER>=1500 & tTimeNow#else tTimeNow#endif//_MSC_VER>=1500 );#endif//_MSC_VER#endif//__GNUC__ iBufferLeftSize -= iBufferUsedSize; } if (iBufferLeft > iBufferUsed) {#ifdef _WIN32#if defined(_MSC_VER)#if _MSC_VER>=1500 iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, iBufferLeft, ".%03.3u.264", tTimeb.millitm);#else iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", tTimeb.millitm);#endif//_MSC_VER>=1500#endif//_MSC_VER#else iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", tTimev.tv_usec / 1000);#endif//WIN32 iBufferLeft -= iBufferUsed; } if (iBufferLeftSize > iBufferUsedSize) {#ifdef _WIN32#if defined(_MSC_VER)#if _MSC_VER>=1500 iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, iBufferLeftSize, ".%03.3u.len", tTimeb.millitm);#else iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", tTimeb.millitm);#endif//_MSC_VER>=1500#endif//_MSC_VER#else iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", tTimev.tv_usec / 1000);#endif//WIN32 iBufferLeftSize -= iBufferUsedSize; } #if defined(__GNUC__) m_pFileBs = FOPEN (strStreamFileName, "wb"); m_pFileBsSize = FOPEN (strLenFileName, "wb");#else#if defined(_MSC_VER)#if _MSC_VER>=1500 FOPEN (&m_pFileBs, strStreamFileName, "wb"); FOPEN (&m_pFileBsSize, strLenFileName, "wb");#else m_pFileBs = FOPEN (strStreamFileName, "wb"); m_pFileBsSize = FOPEN (strLenFileName, "wb");#endif//_MSC_VER>=1500#endif//_MSC_VER#endif//__GNUC__ m_bSwitch = FALSE; m_iSwitchTimes = 0;#endif//OUTPUT_BIT_STREAM InitEncoder(); XMMREG_PROTECT_INIT(CWelsH264SVCEncoder);} CWelsH264SVCEncoder::~CWelsH264SVCEncoder() { WelsLog (NULL, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder()\n");#if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) if (m_pWelsTrace != NULL) { delete m_pWelsTrace; m_pWelsTrace = NULL; }#endif#ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder(), m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal);#endif #ifdef REC_FRAME_COUNT m_uiCountFrameNum = 0;#endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM if (m_pFileBs) { fclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { fclose (m_pFileBsSize); m_pFileBsSize = NULL; } m_bSwitch = FALSE; m_iSwitchTimes = 0;#endif//OUTPUT_BIT_STREAM Uninitialize(); XMMREG_PROTECT_UNINIT(CWelsH264SVCEncoder);} void CWelsH264SVCEncoder::InitEncoder (void) {#if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) #ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder, m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal);#endif m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace != NULL) { const int32_t iWelsTraceExistingFlag = m_pWelsTrace->WelsTraceModuleIsExist(); if (iWelsTraceExistingFlag) { m_pWelsTrace->SetTraceLevel (WELS_LOG_DEFAULT); WelsSetLogCallback (welsCodecTrace::CODEC_TRACE); } } // initialization WelsSetLogLevel (WELS_LOG_DEFAULT); // no output, WELS_LOG_QUIET#endif} /* Interfaces override from ISVCEncoder */ /* * SVC Encoder Initialization */int CWelsH264SVCEncoder::Initialize (SVCEncodingParam* argv, const INIT_TYPE iInitType) { if (INIT_TYPE_PARAMETER_BASED != iInitType || NULL == argv) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInitType= %d, argv= 0x%p\n", iInitType, (void*)argv); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (m_pEncContext, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d\n", m_bInitialFlag); Uninitialize(); } SVCEncodingParam sEncodingParam; SWelsSvcCodingParam sConfig (true); memcpy (&sEncodingParam, argv, sizeof (SVCEncodingParam)); // confirmed_safe_unsafe_usage #ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::Initialize, m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal); WelsLog (m_pEncContext, WELS_LOG_INFO, "coding_param->iPicWidth= %d;coding_param->iPicHeight= %d;coding_param->iTargetBitrate= %d;coding_param->iRCMode= %d;coding_param->iTemporalLayerNum= %d;coding_param->iSpatialLayerNum= %d;coding_param->fFrameRate= %.6ff;coding_param->iInputCsp= %d;coding_param->iKeyPicCodingMode= %d;coding_param->uiIntraPeriod= %d;coding_param->bEnableSpsPpsIdAddition = %d;coding_param->bPrefixNalAddingCtrl = %d;coding_param->bEnableDenoise= %d;coding_param->bEnableBackgroundDetection= %d;coding_param->bEnableAdaptiveQuant= %d;coding_param->bEnableFrameSkip= %d;coding_param->bEnableCropPic= %d;coding_param->bEnableLongTermReference= %d;coding_param->iLtrMarkPeriod= %d;\n", sEncodingParam.iPicWidth, sEncodingParam.iPicHeight, sEncodingParam.iTargetBitrate, sEncodingParam.iRCMode, sEncodingParam.iTemporalLayerNum, sEncodingParam.iSpatialLayerNum, sEncodingParam.fFrameRate, sEncodingParam.iInputCsp, sEncodingParam.iKeyPicCodingMode, sEncodingParam.iIntraPeriod, sEncodingParam.bEnableSpsPpsIdAddition, sEncodingParam.bPrefixNalAddingCtrl, sEncodingParam.bEnableDenoise, sEncodingParam.bEnableBackgroundDetection, sEncodingParam.bEnableAdaptiveQuant, sEncodingParam.bEnableFrameSkip, sEncodingParam.bEnableCropPic, sEncodingParam.bEnableLongTermReference, sEncodingParam.iLtrMarkPeriod); int32_t i = 0; while (i < sEncodingParam.iSpatialLayerNum) { SSpatialLayerConfig* spatial_cfg = &sEncodingParam.sSpatialLayers[i]; WelsLog (m_pEncContext, WELS_LOG_INFO, "coding_param->sSpatialLayers[%d]: .iVideoWidth= %d; .iVideoHeight= %d; .fFrameRate= %.6ff; .iQualityLayerNum= %d; .iSpatialBitrate= %d; .iCgsSnrRefined= %d; .iInterSpatialLayerPredFlag= %d; .sSliceCfg.uiSliceMode= %d; .sSliceCfg.sSliceArgument.uiSliceNum= %d; .sSliceCfg.sSliceArgument.uiSliceSizeConstraint= %d;\n", i, spatial_cfg->iVideoWidth, spatial_cfg->iVideoHeight, spatial_cfg->fFrameRate, spatial_cfg->iQualityLayerNum, spatial_cfg->iSpatialBitrate, spatial_cfg->iCgsSnrRefined, spatial_cfg->iInterSpatialLayerPredFlag, spatial_cfg->sSliceCfg.uiSliceMode, spatial_cfg->sSliceCfg.sSliceArgument.uiSliceNum, spatial_cfg->sSliceCfg.sSliceArgument.uiSliceSizeConstraint ); ++ i; }#endif//REC_FRAME_COUNT // Convert SVCEncodingParam into WelsSVCParamConfig here.. if (sConfig.ParamTranscode (sEncodingParam, true)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), parameter_translation failed.\n"); Uninitialize(); return cmInitParaError; } m_iSrcListSize = 1; return Initialize2 ((void*)&sConfig, INIT_TYPE_CONFIG_BASED);} int CWelsH264SVCEncoder::Initialize2 (void* argv, const INIT_TYPE iInitType) { if (INIT_TYPE_CONFIG_BASED != iInitType || NULL == argv) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInitType= %d, argv= 0x%p.\n", iInitType, (void*)argv); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (m_pEncContext, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d.\n", m_bInitialFlag); Uninitialize(); } SWelsSvcCodingParam* pCfg = static_cast<SWelsSvcCodingParam*> (argv); const int32_t iColorspace = pCfg->iInputCsp; if (0 == iColorspace) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInputCsp= %d.\n", iColorspace); Uninitialize(); return cmInitParaError; } // Check valid parameters const int32_t iNumOfLayers = pCfg->iNumDependencyLayer; if (iNumOfLayers < 1 || iNumOfLayers > MAX_DEPENDENCY_LAYER) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iNumDependencyLayer= %d, valid at range of [1, %d].\n", iNumOfLayers, MAX_DEPENDENCY_LAYER); Uninitialize(); return cmInitParaError; } if (pCfg->iNumTemporalLayer < 1) pCfg->iNumTemporalLayer = 1; if (pCfg->iNumTemporalLayer > MAX_TEMPORAL_LEVEL) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iNumTemporalLayer= %d, valid at range of [1, %d].\n", pCfg->iNumTemporalLayer, MAX_TEMPORAL_LEVEL); Uninitialize(); return cmInitParaError; } // assert( cfg.uiGopSize >= 1 && ( cfg.uiIntraPeriod && (cfg.uiIntraPeriod % cfg.uiGopSize) == 0) ); if (pCfg->uiGopSize < 1 || pCfg->uiGopSize > MAX_GOP_SIZE) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d].\n", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (!WELS_POWER2_IF (pCfg->uiGopSize)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d] and yield to power of 2.\n", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (pCfg->uiIntraPeriod && pCfg->uiIntraPeriod < pCfg->uiGopSize) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d.\n", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if ((pCfg->uiIntraPeriod && (pCfg->uiIntraPeriod & (pCfg->uiGopSize - 1)) != 0)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d also multiple of it.\n", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } // Fine tune num_ref_num if (pCfg->bEnableLongTermReference) { pCfg->iLTRRefNum = LONG_TERM_REF_NUM; } else { pCfg->iLTRRefNum = 0; } pCfg->iNumRefFrame = ((pCfg->uiGopSize >> 1) > 1) ? ((pCfg->uiGopSize >> 1) + pCfg->iLTRRefNum) : (MIN_REF_PIC_COUNT + pCfg->iLTRRefNum); pCfg->iNumRefFrame = WELS_CLIP3 (pCfg->iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM); if (pCfg->uiLtrMarkPeriod == 0) { pCfg->uiLtrMarkPeriod = 30; } const int32_t kiDecStages = WELS_LOG2 (pCfg->uiGopSize); pCfg->iInputCsp = iColorspace; pCfg->iNumTemporalLayer = (int8_t) (1 + kiDecStages); pCfg->iLoopFilterAlphaC0Offset = WELS_CLIP3 (pCfg->iLoopFilterAlphaC0Offset, -6, 6); pCfg->iLoopFilterBetaOffset = WELS_CLIP3 (pCfg->iLoopFilterBetaOffset, -6, 6); // m_pSrcPicList = (SSourcePicture **)WelsMalloc( pCfg->iNumDependencyLayer * sizeof(SSourcePicture *), "m_pSrcPicList" ); // prefer use new/delete pair due encoder intialization stage not start yet for CacheLineSize not detection here (16 or 64 not matched) m_pSrcPicList = new SSourcePicture* [iNumOfLayers]; if (NULL == m_pSrcPicList) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), pOut of memory due m_pSrcPicList memory request.\n"); Uninitialize(); return cmMallocMemeError; } // decide property list size between INIT_TYPE_PARAMETER_BASED/INIT_TYPE_CONFIG_BASED m_iMaxPicWidth = pCfg->iActualPicWidth; m_iMaxPicHeight = pCfg->iActualPicHeight; m_iSrcListSize = iNumOfLayers; for (int32_t i = 0; i < m_iSrcListSize; ++ i) {// m_pSrcPicList[i] = (SSourcePicture *)WelsMalloc( sizeof(SSourcePicture), "m_pSrcPicList[]" ); // prefer use new/delete pair due encoder intialization stage not start yet for CacheLineSize not detection here (16 or 64 not matched) m_pSrcPicList[i] = new SSourcePicture; if (NULL == m_pSrcPicList[i]) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), pOut of memory due m_pSrcPicList[%d] memory request.\n", i); Uninitialize(); m_iSrcListSize = 0; return cmMallocMemeError; } InitPic (m_pSrcPicList[i], iColorspace, m_iMaxPicWidth, m_iMaxPicHeight); } #if defined(OUTPUT_BIT_STREAM) || defined(ENABLE_TRACE_FILE) str_t fpath[MAX_FNAME_LEN] = {0};#if defined(__GNUC__) SNPRINTF (fpath, MAX_FNAME_LEN, "/tmp/"); // confirmed_safe_unsafe_usage #else//__GNUC__ #if defined (_MSC_VER)#if _MSC_VER>=1500 SNPRINTF (fpath, MAX_FNAME_LEN, MAX_FNAME_LEN, ".\\"); // confirmed_safe_unsafe_usage#else SNPRINTF (fpath, MAX_FNAME_LEN, ".\\"); // confirmed_safe_unsafe_usage#endif//_MSC_VER>=1500Lines 1–500 of 1234. Load more
/*! * \copy * Copyright (c) 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. * */ #include <assert.h> #include "welsEncoderExt.h" #include "welsCodecTrace.h" #include "typedefs.h" #include "wels_const.h" #include "utils.h" #include "macros.h" #include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms #include "ref_list_mgr_svc.h" #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 WelsSVCEnc { /* * CWelsH264SVCEncoder class implementation */ CWelsH264SVCEncoder::CWelsH264SVCEncoder() : m_pEncContext (NULL), #if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) m_pWelsTrace (NULL), #endif m_pSrcPicList (NULL), m_iSrcListSize (0), m_iMaxPicWidth (0), m_iMaxPicHeight (0), m_iCspInternal (0), m_bInitialFlag (FALSE) { #ifdef REC_FRAME_COUNT int32_t m_uiCountFrameNum = 0; #endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM str_t strStreamFileName[1024] = { 0 }; //for .264 int32_t iBufferUsed = 0; int32_t iBufferLeft = 1023; str_t strLenFileName[1024] = { 0 }; //for .len int32_t iBufferUsedSize = 0; int32_t iBufferLeftSize = 1023; #endif//OUTPUT_BIT_STREAM #ifdef OUTPUT_BIT_STREAM time_t tTime; #if defined( _WIN32 ) #if defined(_MSC_VER) #if _MSC_VER>=1500 struct tm tTimeNow; #else struct tm* tTimeNow; #endif//_MSC_VER>=1500 #endif//_MSC_VER struct _timeb tTimeb; time (&tTime); #if defined(_MSC_VER) #if _MSC_VER>=1500 LOCALTIME (&tTimeNow, &tTime); #else tTimeNow = LOCALTIME (&tTime); if (NULL == tTimeNow) return; #endif//_MSC_VER>=1500 #endif//_MSC_VER FTIME (&tTimeb); #elif defined( __GNUC__ ) struct tm* tTimeNow; struct timeval tTimev; time (&tTime); tTimeNow = (struct tm*)localtime (&tTime); gettimeofday (&tTimev, NULL); #endif//WIN32 #ifdef _WIN32 #if defined(_MSC_VER) #if _MSC_VER>=1500 iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, iBufferLeft, "enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, iBufferLeftSize, "enc_size_0x%p_", (void*)this); #else iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, "enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, "enc_size_0x%p_", (void*)this); #endif//_MSC_VER>=1500 #endif//_MSC_VER #else iBufferUsed += SNPRINTF (strStreamFileName, iBufferLeft, "/tmp/enc_bs_0x%p_", (void*)this); iBufferUsedSize += SNPRINTF (strLenFileName, iBufferLeftSize, "/tmp/enc_size_0x%p", (void*)this); #endif//WIN32 iBufferLeft -= iBufferUsed; if (iBufferLeft > iBufferUsed) { #if defined(_GNUC__) iBufferUsed += strftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S", tTimeNow); #else #if defined(_MSC_VER) iBufferUsed += strftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S", #if _MSC_VER>=1500 & tTimeNow #else tTimeNow #endif//_MSC_VER>=1500 ); #endif//_MSC_VER #endif//__GNUC__ iBufferLeft -= iBufferUsed; } iBufferLeftSize -= iBufferUsedSize; if (iBufferLeftSize > iBufferUsedSize) { #if defined(_GNUC__) iBufferUsedSize += strftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S", tTimeNow); #else #if defined(_MSC_VER) iBufferUsedSize += strftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S", #if _MSC_VER>=1500 & tTimeNow #else tTimeNow #endif//_MSC_VER>=1500 ); #endif//_MSC_VER #endif//__GNUC__ iBufferLeftSize -= iBufferUsedSize; } if (iBufferLeft > iBufferUsed) { #ifdef _WIN32 #if defined(_MSC_VER) #if _MSC_VER>=1500 iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, iBufferLeft, ".%03.3u.264", tTimeb.millitm); #else iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", tTimeb.millitm); #endif//_MSC_VER>=1500 #endif//_MSC_VER #else iBufferUsed += SNPRINTF (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", tTimev.tv_usec / 1000); #endif//WIN32 iBufferLeft -= iBufferUsed; } if (iBufferLeftSize > iBufferUsedSize) { #ifdef _WIN32 #if defined(_MSC_VER) #if _MSC_VER>=1500 iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, iBufferLeftSize, ".%03.3u.len", tTimeb.millitm); #else iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", tTimeb.millitm); #endif//_MSC_VER>=1500 #endif//_MSC_VER #else iBufferUsedSize += SNPRINTF (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", tTimev.tv_usec / 1000); #endif//WIN32 iBufferLeftSize -= iBufferUsedSize; } #if defined(__GNUC__) m_pFileBs = FOPEN (strStreamFileName, "wb"); m_pFileBsSize = FOPEN (strLenFileName, "wb"); #else #if defined(_MSC_VER) #if _MSC_VER>=1500 FOPEN (&m_pFileBs, strStreamFileName, "wb"); FOPEN (&m_pFileBsSize, strLenFileName, "wb"); #else m_pFileBs = FOPEN (strStreamFileName, "wb"); m_pFileBsSize = FOPEN (strLenFileName, "wb"); #endif//_MSC_VER>=1500 #endif//_MSC_VER #endif//__GNUC__ m_bSwitch = FALSE; m_iSwitchTimes = 0; #endif//OUTPUT_BIT_STREAM InitEncoder(); XMMREG_PROTECT_INIT(CWelsH264SVCEncoder); } CWelsH264SVCEncoder::~CWelsH264SVCEncoder() { WelsLog (NULL, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder()\n"); #if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) if (m_pWelsTrace != NULL) { delete m_pWelsTrace; m_pWelsTrace = NULL; } #endif #ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder(), m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal); #endif #ifdef REC_FRAME_COUNT m_uiCountFrameNum = 0; #endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM if (m_pFileBs) { fclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { fclose (m_pFileBsSize); m_pFileBsSize = NULL; } m_bSwitch = FALSE; m_iSwitchTimes = 0; #endif//OUTPUT_BIT_STREAM Uninitialize(); XMMREG_PROTECT_UNINIT(CWelsH264SVCEncoder); } void CWelsH264SVCEncoder::InitEncoder (void) { #if defined(_WIN32)||defined(_MACH_PLATFORM)||defined(__GNUC__) #ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder, m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal); #endif m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace != NULL) { const int32_t iWelsTraceExistingFlag = m_pWelsTrace->WelsTraceModuleIsExist(); if (iWelsTraceExistingFlag) { m_pWelsTrace->SetTraceLevel (WELS_LOG_DEFAULT); WelsSetLogCallback (welsCodecTrace::CODEC_TRACE); } } // initialization WelsSetLogLevel (WELS_LOG_DEFAULT); // no output, WELS_LOG_QUIET #endif } /* Interfaces override from ISVCEncoder */ /* * SVC Encoder Initialization */ int CWelsH264SVCEncoder::Initialize (SVCEncodingParam* argv, const INIT_TYPE iInitType) { if (INIT_TYPE_PARAMETER_BASED != iInitType || NULL == argv) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInitType= %d, argv= 0x%p\n", iInitType, (void*)argv); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (m_pEncContext, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d\n", m_bInitialFlag); Uninitialize(); } SVCEncodingParam sEncodingParam; SWelsSvcCodingParam sConfig (true); memcpy (&sEncodingParam, argv, sizeof (SVCEncodingParam)); // confirmed_safe_unsafe_usage #ifdef REC_FRAME_COUNT WelsLog (m_pEncContext, WELS_LOG_INFO, "CWelsH264SVCEncoder::Initialize, m_uiCountFrameNum= %d, m_iCspInternal= 0x%x\n", m_uiCountFrameNum, m_iCspInternal); WelsLog (m_pEncContext, WELS_LOG_INFO, "coding_param->iPicWidth= %d;coding_param->iPicHeight= %d;coding_param->iTargetBitrate= %d;coding_param->iRCMode= %d;coding_param->iTemporalLayerNum= %d;coding_param->iSpatialLayerNum= %d;coding_param->fFrameRate= %.6ff;coding_param->iInputCsp= %d;coding_param->iKeyPicCodingMode= %d;coding_param->uiIntraPeriod= %d;coding_param->bEnableSpsPpsIdAddition = %d;coding_param->bPrefixNalAddingCtrl = %d;coding_param->bEnableDenoise= %d;coding_param->bEnableBackgroundDetection= %d;coding_param->bEnableAdaptiveQuant= %d;coding_param->bEnableFrameSkip= %d;coding_param->bEnableCropPic= %d;coding_param->bEnableLongTermReference= %d;coding_param->iLtrMarkPeriod= %d;\n", sEncodingParam.iPicWidth, sEncodingParam.iPicHeight, sEncodingParam.iTargetBitrate, sEncodingParam.iRCMode, sEncodingParam.iTemporalLayerNum, sEncodingParam.iSpatialLayerNum, sEncodingParam.fFrameRate, sEncodingParam.iInputCsp, sEncodingParam.iKeyPicCodingMode, sEncodingParam.iIntraPeriod, sEncodingParam.bEnableSpsPpsIdAddition, sEncodingParam.bPrefixNalAddingCtrl, sEncodingParam.bEnableDenoise, sEncodingParam.bEnableBackgroundDetection, sEncodingParam.bEnableAdaptiveQuant, sEncodingParam.bEnableFrameSkip, sEncodingParam.bEnableCropPic, sEncodingParam.bEnableLongTermReference, sEncodingParam.iLtrMarkPeriod); int32_t i = 0; while (i < sEncodingParam.iSpatialLayerNum) { SSpatialLayerConfig* spatial_cfg = &sEncodingParam.sSpatialLayers[i]; WelsLog (m_pEncContext, WELS_LOG_INFO, "coding_param->sSpatialLayers[%d]: .iVideoWidth= %d; .iVideoHeight= %d; .fFrameRate= %.6ff; .iQualityLayerNum= %d; .iSpatialBitrate= %d; .iCgsSnrRefined= %d; .iInterSpatialLayerPredFlag= %d; .sSliceCfg.uiSliceMode= %d; .sSliceCfg.sSliceArgument.uiSliceNum= %d; .sSliceCfg.sSliceArgument.uiSliceSizeConstraint= %d;\n", i, spatial_cfg->iVideoWidth, spatial_cfg->iVideoHeight, spatial_cfg->fFrameRate, spatial_cfg->iQualityLayerNum, spatial_cfg->iSpatialBitrate, spatial_cfg->iCgsSnrRefined, spatial_cfg->iInterSpatialLayerPredFlag, spatial_cfg->sSliceCfg.uiSliceMode, spatial_cfg->sSliceCfg.sSliceArgument.uiSliceNum, spatial_cfg->sSliceCfg.sSliceArgument.uiSliceSizeConstraint ); ++ i; } #endif//REC_FRAME_COUNT // Convert SVCEncodingParam into WelsSVCParamConfig here.. if (sConfig.ParamTranscode (sEncodingParam, true)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), parameter_translation failed.\n"); Uninitialize(); return cmInitParaError; } m_iSrcListSize = 1; return Initialize2 ((void*)&sConfig, INIT_TYPE_CONFIG_BASED); } int CWelsH264SVCEncoder::Initialize2 (void* argv, const INIT_TYPE iInitType) { if (INIT_TYPE_CONFIG_BASED != iInitType || NULL == argv) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInitType= %d, argv= 0x%p.\n", iInitType, (void*)argv); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (m_pEncContext, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d.\n", m_bInitialFlag); Uninitialize(); } SWelsSvcCodingParam* pCfg = static_cast<SWelsSvcCodingParam*> (argv); const int32_t iColorspace = pCfg->iInputCsp; if (0 == iColorspace) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iInputCsp= %d.\n", iColorspace); Uninitialize(); return cmInitParaError; } // Check valid parameters const int32_t iNumOfLayers = pCfg->iNumDependencyLayer; if (iNumOfLayers < 1 || iNumOfLayers > MAX_DEPENDENCY_LAYER) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iNumDependencyLayer= %d, valid at range of [1, %d].\n", iNumOfLayers, MAX_DEPENDENCY_LAYER); Uninitialize(); return cmInitParaError; } if (pCfg->iNumTemporalLayer < 1) pCfg->iNumTemporalLayer = 1; if (pCfg->iNumTemporalLayer > MAX_TEMPORAL_LEVEL) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iNumTemporalLayer= %d, valid at range of [1, %d].\n", pCfg->iNumTemporalLayer, MAX_TEMPORAL_LEVEL); Uninitialize(); return cmInitParaError; } // assert( cfg.uiGopSize >= 1 && ( cfg.uiIntraPeriod && (cfg.uiIntraPeriod % cfg.uiGopSize) == 0) ); if (pCfg->uiGopSize < 1 || pCfg->uiGopSize > MAX_GOP_SIZE) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d].\n", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (!WELS_POWER2_IF (pCfg->uiGopSize)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d] and yield to power of 2.\n", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (pCfg->uiIntraPeriod && pCfg->uiIntraPeriod < pCfg->uiGopSize) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d.\n", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if ((pCfg->uiIntraPeriod && (pCfg->uiIntraPeriod & (pCfg->uiGopSize - 1)) != 0)) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d also multiple of it.\n", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } // Fine tune num_ref_num if (pCfg->bEnableLongTermReference) { pCfg->iLTRRefNum = LONG_TERM_REF_NUM; } else { pCfg->iLTRRefNum = 0; } pCfg->iNumRefFrame = ((pCfg->uiGopSize >> 1) > 1) ? ((pCfg->uiGopSize >> 1) + pCfg->iLTRRefNum) : (MIN_REF_PIC_COUNT + pCfg->iLTRRefNum); pCfg->iNumRefFrame = WELS_CLIP3 (pCfg->iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM); if (pCfg->uiLtrMarkPeriod == 0) { pCfg->uiLtrMarkPeriod = 30; } const int32_t kiDecStages = WELS_LOG2 (pCfg->uiGopSize); pCfg->iInputCsp = iColorspace; pCfg->iNumTemporalLayer = (int8_t) (1 + kiDecStages); pCfg->iLoopFilterAlphaC0Offset = WELS_CLIP3 (pCfg->iLoopFilterAlphaC0Offset, -6, 6); pCfg->iLoopFilterBetaOffset = WELS_CLIP3 (pCfg->iLoopFilterBetaOffset, -6, 6); // m_pSrcPicList = (SSourcePicture **)WelsMalloc( pCfg->iNumDependencyLayer * sizeof(SSourcePicture *), "m_pSrcPicList" ); // prefer use new/delete pair due encoder intialization stage not start yet for CacheLineSize not detection here (16 or 64 not matched) m_pSrcPicList = new SSourcePicture* [iNumOfLayers]; if (NULL == m_pSrcPicList) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), pOut of memory due m_pSrcPicList memory request.\n"); Uninitialize(); return cmMallocMemeError; } // decide property list size between INIT_TYPE_PARAMETER_BASED/INIT_TYPE_CONFIG_BASED m_iMaxPicWidth = pCfg->iActualPicWidth; m_iMaxPicHeight = pCfg->iActualPicHeight; m_iSrcListSize = iNumOfLayers; for (int32_t i = 0; i < m_iSrcListSize; ++ i) { // m_pSrcPicList[i] = (SSourcePicture *)WelsMalloc( sizeof(SSourcePicture), "m_pSrcPicList[]" ); // prefer use new/delete pair due encoder intialization stage not start yet for CacheLineSize not detection here (16 or 64 not matched) m_pSrcPicList[i] = new SSourcePicture; if (NULL == m_pSrcPicList[i]) { WelsLog (m_pEncContext, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), pOut of memory due m_pSrcPicList[%d] memory request.\n", i); Uninitialize(); m_iSrcListSize = 0; return cmMallocMemeError; } InitPic (m_pSrcPicList[i], iColorspace, m_iMaxPicWidth, m_iMaxPicHeight); } #if defined(OUTPUT_BIT_STREAM) || defined(ENABLE_TRACE_FILE) str_t fpath[MAX_FNAME_LEN] = {0}; #if defined(__GNUC__) SNPRINTF (fpath, MAX_FNAME_LEN, "/tmp/"); // confirmed_safe_unsafe_usage #else//__GNUC__ #if defined (_MSC_VER) #if _MSC_VER>=1500 SNPRINTF (fpath, MAX_FNAME_LEN, MAX_FNAME_LEN, ".\\"); // confirmed_safe_unsafe_usage #else SNPRINTF (fpath, MAX_FNAME_LEN, ".\\"); // confirmed_safe_unsafe_usage #endif//_MSC_VER>=1500