/*!
* \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();
}
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();
}
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->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.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 Initialize((void *)&sConfig, INIT_TYPE_CONFIG_BASED);
}
int CWelsH264SVCEncoder::Initialize(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
#endif//_MSC_VER
#endif //__GNUC__
strcpy(pCfg->sTracePath, fpath); // confirmed_safe_unsafe_usage
Lines 1–500 of 1255. 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(); } 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(); } 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->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.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 Initialize((void *)&sConfig, INIT_TYPE_CONFIG_BASED); } int CWelsH264SVCEncoder::Initialize(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 #endif//_MSC_VER #endif //__GNUC__ strcpy(pCfg->sTracePath, fpath); // confirmed_safe_unsafe_usage