/*! * \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 "version.h"#include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms#include "ref_list_mgr_svc.h"#include "codec_ver.h" #include <time.h>#include <measure_time.h>#if defined(_WIN32) /*&& defined(_DEBUG)*/ #include <windows.h>#include <stdio.h>#include <stdarg.h>#include <sys/types.h>#else#include <sys/time.h>#endif namespace WelsEnc { /* * CWelsH264SVCEncoder class implementation */CWelsH264SVCEncoder::CWelsH264SVCEncoder() : m_pEncContext (NULL), m_pWelsTrace (NULL), 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 char strStreamFileName[1024] = { 0 }; //for .264 int32_t iBufferUsed = 0; int32_t iBufferLeft = 1023; int32_t iCurUsed; char strLenFileName[1024] = { 0 }; //for .len int32_t iBufferUsedSize = 0; int32_t iBufferLeftSize = 1023; int32_t iCurUsedSize;#endif//OUTPUT_BIT_STREAM #ifdef OUTPUT_BIT_STREAM SWelsTime tTime; WelsGetTimeOfDay (&tTime); iCurUsed = WelsSnprintf (strStreamFileName, iBufferLeft, "enc_bs_0x%p_", (void*)this); iCurUsedSize = WelsSnprintf (strLenFileName, iBufferLeftSize, "enc_size_0x%p_", (void*)this); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; if (iBufferLeft > 0) { iCurUsed = WelsStrftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S", &tTime); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; } iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; if (iBufferLeftSize > 0) { iCurUsedSize = WelsStrftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S", &tTime); iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; } if (iBufferLeft > 0) { iCurUsed = WelsSnprintf (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", WelsGetMillisecond (&tTime)); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; } if (iBufferLeftSize > 0) { iCurUsedSize = WelsSnprintf (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", WelsGetMillisecond (&tTime)); iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; } m_pFileBs = WelsFopen (strStreamFileName, "wb"); m_pFileBsSize = WelsFopen (strLenFileName, "wb"); m_bSwitch = false; m_iSwitchTimes = 0;#endif//OUTPUT_BIT_STREAM InitEncoder();} CWelsH264SVCEncoder::~CWelsH264SVCEncoder() { if (m_pWelsTrace) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder()"); } #ifdef REC_FRAME_COUNT m_uiCountFrameNum = 0;#endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM if (m_pFileBs) { WelsFclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { WelsFclose (m_pFileBsSize); m_pFileBsSize = NULL; } m_bSwitch = false; m_iSwitchTimes = 0;#endif//OUTPUT_BIT_STREAM Uninitialize(); if (m_pWelsTrace) { delete m_pWelsTrace; m_pWelsTrace = NULL; }} void CWelsH264SVCEncoder::InitEncoder (void) { m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace == NULL) { return; } m_pWelsTrace->SetCodecInstance (this);} /* Interfaces override from ISVCEncoder */ int CWelsH264SVCEncoder::GetDefaultParams (SEncParamExt* argv) { SWelsSvcCodingParam::FillDefault (*argv); return cmResultSuccess;} /* * SVC Encoder Initialization */int CWelsH264SVCEncoder::Initialize (const SEncParamBase* argv) { if (m_pWelsTrace == NULL) { return cmMallocMemeError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder(), openh264 codec version = %s", VERSION_NUMBER); if (NULL == argv) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid argv= 0x%p", argv); return cmInitParaError; } SWelsSvcCodingParam sConfig; // Convert SEncParamBase into WelsSVCParamConfig here.. if (sConfig.ParamBaseTranscode (*argv)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), parameter_translation failed."); TraceParamInfo (&sConfig); Uninitialize(); return cmInitParaError; } return InitializeInternal (&sConfig);} int CWelsH264SVCEncoder::InitializeExt (const SEncParamExt* argv) { if (m_pWelsTrace == NULL) { return cmMallocMemeError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder(), openh264 codec version = %s", VERSION_NUMBER); if (NULL == argv) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::InitializeExt(), invalid argv= 0x%p", argv); return cmInitParaError; } SWelsSvcCodingParam sConfig; // Convert SEncParamExt into WelsSVCParamConfig here.. if (sConfig.ParamTranscode (*argv)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::InitializeExt(), parameter_translation failed."); TraceParamInfo (&sConfig); Uninitialize(); return cmInitParaError; } return InitializeInternal (&sConfig);} int CWelsH264SVCEncoder::InitializeInternal (SWelsSvcCodingParam* pCfg) { if (NULL == pCfg) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid argv= 0x%p.", pCfg); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d.", m_bInitialFlag); Uninitialize(); } // Check valid parameters const int32_t iNumOfLayers = pCfg->iSpatialLayerNum; if (iNumOfLayers < 1 || iNumOfLayers > MAX_DEPENDENCY_LAYER) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iSpatialLayerNum= %d, valid at range of [1, %d].", iNumOfLayers, MAX_DEPENDENCY_LAYER); Uninitialize(); return cmInitParaError; } if (pCfg->iTemporalLayerNum < 1) pCfg->iTemporalLayerNum = 1; if (pCfg->iTemporalLayerNum > MAX_TEMPORAL_LEVEL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iTemporalLayerNum= %d, valid at range of [1, %d].", pCfg->iTemporalLayerNum, 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_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d].", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (!WELS_POWER2_IF (pCfg->uiGopSize)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d] and yield to power of 2.", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (pCfg->uiIntraPeriod && pCfg->uiIntraPeriod < pCfg->uiGopSize) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d.", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if ((pCfg->uiIntraPeriod && (pCfg->uiIntraPeriod & (pCfg->uiGopSize - 1)) != 0)) { WelsLog (&m_pWelsTrace->m_sLogCtx, 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.", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { if (pCfg->bEnableLongTermReference) { pCfg->iLTRRefNum = LONG_TERM_REF_NUM_SCREEN; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) pCfg->iNumRefFrame = WELS_MAX (1, WELS_LOG2 (pCfg->uiGopSize)) + pCfg->iLTRRefNum; } else { pCfg->iLTRRefNum = 0; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) pCfg->iNumRefFrame = WELS_MAX (1, pCfg->uiGopSize >> 1); } } else { pCfg->iLTRRefNum = pCfg->bEnableLongTermReference ? LONG_TERM_REF_NUM : 0; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) { 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_CAMERA); } } if (pCfg->iLtrMarkPeriod == 0) { pCfg->iLtrMarkPeriod = 30; } const int32_t kiDecStages = WELS_LOG2 (pCfg->uiGopSize); pCfg->iTemporalLayerNum = (int8_t) (1 + kiDecStages); pCfg->iLoopFilterAlphaC0Offset = WELS_CLIP3 (pCfg->iLoopFilterAlphaC0Offset, -6, 6); pCfg->iLoopFilterBetaOffset = WELS_CLIP3 (pCfg->iLoopFilterBetaOffset, -6, 6); // decide property list size between INIT_TYPE_PARAMETER_BASED/INIT_TYPE_CONFIG_BASED m_iMaxPicWidth = pCfg->iPicWidth; m_iMaxPicHeight = pCfg->iPicHeight; TraceParamInfo (pCfg); if (WelsInitEncoderExt (&m_pEncContext, pCfg, &m_pWelsTrace->m_sLogCtx, NULL)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), WelsInitEncoderExt failed."); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_DEBUG, "Problematic Input Base Param: iUsageType=%d, Resolution=%dx%d, FR=%f, TLayerNum=%d, DLayerNum=%d", pCfg->iUsageType, pCfg->iPicWidth, pCfg->iPicHeight, pCfg->fMaxFrameRate, pCfg->iTemporalLayerNum, pCfg->iSpatialLayerNum); Uninitialize(); return cmInitParaError; } m_bInitialFlag = true; return cmResultSuccess;} /* * SVC Encoder Uninitialization */int32_t CWelsH264SVCEncoder::Uninitialize() { if (!m_bInitialFlag) { return 0; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::Uninitialize(), openh264 codec version = %s.", VERSION_NUMBER); if (NULL != m_pEncContext) { WelsUninitEncoderExt (&m_pEncContext); m_pEncContext = NULL; } m_bInitialFlag = false; return 0;} /* * SVC core encoding */int CWelsH264SVCEncoder::EncodeFrame (const SSourcePicture* kpSrcPic, SFrameBSInfo* pBsInfo) { if (! (kpSrcPic && m_bInitialFlag && pBsInfo)) { return cmInitParaError; } if (kpSrcPic->iColorFormat != videoFormatI420) return cmInitParaError; const int32_t kiEncoderReturn = EncodeFrameInternal (kpSrcPic, pBsInfo); if (kiEncoderReturn != cmResultSuccess) return kiEncoderReturn; #ifdef REC_FRAME_COUNT ++ m_uiCountFrameNum; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::EncodeFrame(), m_uiCountFrameNum= %d,", m_uiCountFrameNum);#endif//REC_FRAME_COUNT #ifdef DUMP_SRC_PICTURE DumpSrcPicture (pSrc);#endif // DUMP_SRC_PICTURE return kiEncoderReturn;} int CWelsH264SVCEncoder ::EncodeFrameInternal (const SSourcePicture* pSrcPic, SFrameBSInfo* pBsInfo) { const int64_t kiBeforeFrameUs = WelsTime(); const int32_t kiEncoderReturn = WelsEncoderEncodeExt (m_pEncContext, pBsInfo, pSrcPic); const int64_t kiCurrentFrameMs = (WelsTime() - kiBeforeFrameUs) / 1000; if (kiEncoderReturn == ENC_RETURN_MEMALLOCERR) { WelsUninitEncoderExt (&m_pEncContext); return cmMallocMemeError; } else if ((kiEncoderReturn != ENC_RETURN_SUCCESS) && (kiEncoderReturn == ENC_RETURN_CORRECTED)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "unexpected return(%d) from EncodeFrameInternal()!", kiEncoderReturn); return cmUnkonwReason; } UpdateStatistics (pSrcPic->uiTimeStamp, pBsInfo->eFrameType, pBsInfo->iFrameSizeInBytes, kiCurrentFrameMs); ///////////////////for test#ifdef OUTPUT_BIT_STREAM if (pBsInfo->eFrameType != videoFrameTypeInvalid && pBsInfo->eFrameType != videoFrameTypeSkip) { SLayerBSInfo* pLayer = NULL; int32_t i = 0, j = 0, iCurLayerBits = 0, total_bits = 0; if (m_bSwitch) { if (m_pFileBs) { WelsFclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { WelsFclose (m_pFileBsSize); m_pFileBsSize = NULL; } char strStreamFileName[128] = {0}; WelsSnprintf (strStreamFileName, 128, "adj%d_w%d.264", m_iSwitchTimes, m_pEncContext->pSvcParam->iPicWidth); m_pFileBs = WelsFopen (strStreamFileName, "wb"); WelsSnprintf (strStreamFileName, 128, "adj%d_w%d_size.iLen", m_iSwitchTimes, m_pEncContext->pSvcParam->iPicWidth); m_pFileBsSize = WelsFopen (strStreamFileName, "wb"); m_bSwitch = false; } for (i = 0; i < pBsInfo->iLayerNum; i++) { pLayer = &pBsInfo->sLayerInfo[i]; iCurLayerBits = 0; for (j = 0; j < pLayer->iNalCount; j++) { iCurLayerBits += pLayer->pNalLengthInByte[j]; } total_bits += iCurLayerBits; if (m_pFileBs != NULL) WelsFwrite (pLayer->pBsBuf, 1, iCurLayerBits, m_pFileBs); } if (m_pFileBsSize != NULL) WelsFwrite (&total_bits, sizeof (int32_t), 1, m_pFileBsSize); }#endif //OUTPUT_BIT_STREAM#ifdef DUMP_SRC_PICTURE DumpSrcPicture (pSrcPicList[0]->pData[0]);#endif // DUMP_SRC_PICTURE return cmResultSuccess; } int CWelsH264SVCEncoder::EncodeParameterSets (SFrameBSInfo* pBsInfo) { return WelsEncoderEncodeParameterSets (m_pEncContext, pBsInfo);} /* * Force key frame */int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR) { if (! (m_pEncContext && m_bInitialFlag)) { return 1; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::ForceIntraFrame(), bIDR= %d", bIDR); ForceCodingIDR (m_pEncContext); m_pEncContext->sEncoderStatistics.uiIDRReqNum++; return 0;}void CWelsH264SVCEncoder::TraceParamInfo (SEncParamExt* pParam) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "iUsageType = %d,iPicWidth= %d;iPicHeight= %d;iTargetBitrate= %d;iMaxBitrate= %d;iRCMode= %d;iPaddingFlag= %d;iTemporalLayerNum= %d;iSpatialLayerNum= %d;fFrameRate= %.6ff;uiIntraPeriod= %d;" "eSpsPpsIdStrategy = %d;bPrefixNalAddingCtrl = %d;bEnableDenoise= %d;bEnableBackgroundDetection= %d;bEnableAdaptiveQuant= %d;bEnableFrameSkip= %d;bEnableLongTermReference= %d;iLtrMarkPeriod= %d;" "iComplexityMode = %d;iNumRefFrame = %d;iEntropyCodingModeFlag = %d;uiMaxNalSize = %d;iLTRRefNum = %d;iMultipleThreadIdc = %d;iLoopFilterDisableIdc = %d (offset(alpha/beta): %d,%d)", pParam->iUsageType, pParam->iPicWidth, pParam->iPicHeight, pParam->iTargetBitrate, pParam->iMaxBitrate, pParam->iRCMode, pParam->iPaddingFlag, pParam->iTemporalLayerNum, pParam->iSpatialLayerNum,Lines 1–500 of 1318. 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 "version.h" #include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms #include "ref_list_mgr_svc.h" #include "codec_ver.h" #include <time.h> #include <measure_time.h> #if defined(_WIN32) /*&& defined(_DEBUG)*/ #include <windows.h> #include <stdio.h> #include <stdarg.h> #include <sys/types.h> #else #include <sys/time.h> #endif namespace WelsEnc { /* * CWelsH264SVCEncoder class implementation */ CWelsH264SVCEncoder::CWelsH264SVCEncoder() : m_pEncContext (NULL), m_pWelsTrace (NULL), 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 char strStreamFileName[1024] = { 0 }; //for .264 int32_t iBufferUsed = 0; int32_t iBufferLeft = 1023; int32_t iCurUsed; char strLenFileName[1024] = { 0 }; //for .len int32_t iBufferUsedSize = 0; int32_t iBufferLeftSize = 1023; int32_t iCurUsedSize; #endif//OUTPUT_BIT_STREAM #ifdef OUTPUT_BIT_STREAM SWelsTime tTime; WelsGetTimeOfDay (&tTime); iCurUsed = WelsSnprintf (strStreamFileName, iBufferLeft, "enc_bs_0x%p_", (void*)this); iCurUsedSize = WelsSnprintf (strLenFileName, iBufferLeftSize, "enc_size_0x%p_", (void*)this); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; if (iBufferLeft > 0) { iCurUsed = WelsStrftime (&strStreamFileName[iBufferUsed], iBufferLeft, "%y%m%d%H%M%S", &tTime); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; } iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; if (iBufferLeftSize > 0) { iCurUsedSize = WelsStrftime (&strLenFileName[iBufferUsedSize], iBufferLeftSize, "%y%m%d%H%M%S", &tTime); iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; } if (iBufferLeft > 0) { iCurUsed = WelsSnprintf (&strStreamFileName[iBufferUsed], iBufferLeft, ".%03.3u.264", WelsGetMillisecond (&tTime)); iBufferUsed += iCurUsed; iBufferLeft -= iCurUsed; } if (iBufferLeftSize > 0) { iCurUsedSize = WelsSnprintf (&strLenFileName[iBufferUsedSize], iBufferLeftSize, ".%03.3u.len", WelsGetMillisecond (&tTime)); iBufferUsedSize += iCurUsedSize; iBufferLeftSize -= iCurUsedSize; } m_pFileBs = WelsFopen (strStreamFileName, "wb"); m_pFileBsSize = WelsFopen (strLenFileName, "wb"); m_bSwitch = false; m_iSwitchTimes = 0; #endif//OUTPUT_BIT_STREAM InitEncoder(); } CWelsH264SVCEncoder::~CWelsH264SVCEncoder() { if (m_pWelsTrace) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::~CWelsH264SVCEncoder()"); } #ifdef REC_FRAME_COUNT m_uiCountFrameNum = 0; #endif//REC_FRAME_COUNT #ifdef OUTPUT_BIT_STREAM if (m_pFileBs) { WelsFclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { WelsFclose (m_pFileBsSize); m_pFileBsSize = NULL; } m_bSwitch = false; m_iSwitchTimes = 0; #endif//OUTPUT_BIT_STREAM Uninitialize(); if (m_pWelsTrace) { delete m_pWelsTrace; m_pWelsTrace = NULL; } } void CWelsH264SVCEncoder::InitEncoder (void) { m_pWelsTrace = new welsCodecTrace(); if (m_pWelsTrace == NULL) { return; } m_pWelsTrace->SetCodecInstance (this); } /* Interfaces override from ISVCEncoder */ int CWelsH264SVCEncoder::GetDefaultParams (SEncParamExt* argv) { SWelsSvcCodingParam::FillDefault (*argv); return cmResultSuccess; } /* * SVC Encoder Initialization */ int CWelsH264SVCEncoder::Initialize (const SEncParamBase* argv) { if (m_pWelsTrace == NULL) { return cmMallocMemeError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder(), openh264 codec version = %s", VERSION_NUMBER); if (NULL == argv) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid argv= 0x%p", argv); return cmInitParaError; } SWelsSvcCodingParam sConfig; // Convert SEncParamBase into WelsSVCParamConfig here.. if (sConfig.ParamBaseTranscode (*argv)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), parameter_translation failed."); TraceParamInfo (&sConfig); Uninitialize(); return cmInitParaError; } return InitializeInternal (&sConfig); } int CWelsH264SVCEncoder::InitializeExt (const SEncParamExt* argv) { if (m_pWelsTrace == NULL) { return cmMallocMemeError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::InitEncoder(), openh264 codec version = %s", VERSION_NUMBER); if (NULL == argv) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::InitializeExt(), invalid argv= 0x%p", argv); return cmInitParaError; } SWelsSvcCodingParam sConfig; // Convert SEncParamExt into WelsSVCParamConfig here.. if (sConfig.ParamTranscode (*argv)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::InitializeExt(), parameter_translation failed."); TraceParamInfo (&sConfig); Uninitialize(); return cmInitParaError; } return InitializeInternal (&sConfig); } int CWelsH264SVCEncoder::InitializeInternal (SWelsSvcCodingParam* pCfg) { if (NULL == pCfg) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid argv= 0x%p.", pCfg); return cmInitParaError; } if (m_bInitialFlag) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsH264SVCEncoder::Initialize(), reinitialize, m_bInitialFlag= %d.", m_bInitialFlag); Uninitialize(); } // Check valid parameters const int32_t iNumOfLayers = pCfg->iSpatialLayerNum; if (iNumOfLayers < 1 || iNumOfLayers > MAX_DEPENDENCY_LAYER) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iSpatialLayerNum= %d, valid at range of [1, %d].", iNumOfLayers, MAX_DEPENDENCY_LAYER); Uninitialize(); return cmInitParaError; } if (pCfg->iTemporalLayerNum < 1) pCfg->iTemporalLayerNum = 1; if (pCfg->iTemporalLayerNum > MAX_TEMPORAL_LEVEL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid iTemporalLayerNum= %d, valid at range of [1, %d].", pCfg->iTemporalLayerNum, 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_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d].", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (!WELS_POWER2_IF (pCfg->uiGopSize)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiGopSize= %d, valid at range of [1, %d] and yield to power of 2.", pCfg->uiGopSize, MAX_GOP_SIZE); Uninitialize(); return cmInitParaError; } if (pCfg->uiIntraPeriod && pCfg->uiIntraPeriod < pCfg->uiGopSize) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), invalid uiIntraPeriod= %d, valid in case it equals to 0 for unlimited intra period or exceeds specified uiGopSize= %d.", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if ((pCfg->uiIntraPeriod && (pCfg->uiIntraPeriod & (pCfg->uiGopSize - 1)) != 0)) { WelsLog (&m_pWelsTrace->m_sLogCtx, 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.", pCfg->uiIntraPeriod, pCfg->uiGopSize); Uninitialize(); return cmInitParaError; } if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { if (pCfg->bEnableLongTermReference) { pCfg->iLTRRefNum = LONG_TERM_REF_NUM_SCREEN; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) pCfg->iNumRefFrame = WELS_MAX (1, WELS_LOG2 (pCfg->uiGopSize)) + pCfg->iLTRRefNum; } else { pCfg->iLTRRefNum = 0; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) pCfg->iNumRefFrame = WELS_MAX (1, pCfg->uiGopSize >> 1); } } else { pCfg->iLTRRefNum = pCfg->bEnableLongTermReference ? LONG_TERM_REF_NUM : 0; if (pCfg->iNumRefFrame == AUTO_REF_PIC_COUNT) { 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_CAMERA); } } if (pCfg->iLtrMarkPeriod == 0) { pCfg->iLtrMarkPeriod = 30; } const int32_t kiDecStages = WELS_LOG2 (pCfg->uiGopSize); pCfg->iTemporalLayerNum = (int8_t) (1 + kiDecStages); pCfg->iLoopFilterAlphaC0Offset = WELS_CLIP3 (pCfg->iLoopFilterAlphaC0Offset, -6, 6); pCfg->iLoopFilterBetaOffset = WELS_CLIP3 (pCfg->iLoopFilterBetaOffset, -6, 6); // decide property list size between INIT_TYPE_PARAMETER_BASED/INIT_TYPE_CONFIG_BASED m_iMaxPicWidth = pCfg->iPicWidth; m_iMaxPicHeight = pCfg->iPicHeight; TraceParamInfo (pCfg); if (WelsInitEncoderExt (&m_pEncContext, pCfg, &m_pWelsTrace->m_sLogCtx, NULL)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::Initialize(), WelsInitEncoderExt failed."); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_DEBUG, "Problematic Input Base Param: iUsageType=%d, Resolution=%dx%d, FR=%f, TLayerNum=%d, DLayerNum=%d", pCfg->iUsageType, pCfg->iPicWidth, pCfg->iPicHeight, pCfg->fMaxFrameRate, pCfg->iTemporalLayerNum, pCfg->iSpatialLayerNum); Uninitialize(); return cmInitParaError; } m_bInitialFlag = true; return cmResultSuccess; } /* * SVC Encoder Uninitialization */ int32_t CWelsH264SVCEncoder::Uninitialize() { if (!m_bInitialFlag) { return 0; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::Uninitialize(), openh264 codec version = %s.", VERSION_NUMBER); if (NULL != m_pEncContext) { WelsUninitEncoderExt (&m_pEncContext); m_pEncContext = NULL; } m_bInitialFlag = false; return 0; } /* * SVC core encoding */ int CWelsH264SVCEncoder::EncodeFrame (const SSourcePicture* kpSrcPic, SFrameBSInfo* pBsInfo) { if (! (kpSrcPic && m_bInitialFlag && pBsInfo)) { return cmInitParaError; } if (kpSrcPic->iColorFormat != videoFormatI420) return cmInitParaError; const int32_t kiEncoderReturn = EncodeFrameInternal (kpSrcPic, pBsInfo); if (kiEncoderReturn != cmResultSuccess) return kiEncoderReturn; #ifdef REC_FRAME_COUNT ++ m_uiCountFrameNum; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::EncodeFrame(), m_uiCountFrameNum= %d,", m_uiCountFrameNum); #endif//REC_FRAME_COUNT #ifdef DUMP_SRC_PICTURE DumpSrcPicture (pSrc); #endif // DUMP_SRC_PICTURE return kiEncoderReturn; } int CWelsH264SVCEncoder ::EncodeFrameInternal (const SSourcePicture* pSrcPic, SFrameBSInfo* pBsInfo) { const int64_t kiBeforeFrameUs = WelsTime(); const int32_t kiEncoderReturn = WelsEncoderEncodeExt (m_pEncContext, pBsInfo, pSrcPic); const int64_t kiCurrentFrameMs = (WelsTime() - kiBeforeFrameUs) / 1000; if (kiEncoderReturn == ENC_RETURN_MEMALLOCERR) { WelsUninitEncoderExt (&m_pEncContext); return cmMallocMemeError; } else if ((kiEncoderReturn != ENC_RETURN_SUCCESS) && (kiEncoderReturn == ENC_RETURN_CORRECTED)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "unexpected return(%d) from EncodeFrameInternal()!", kiEncoderReturn); return cmUnkonwReason; } UpdateStatistics (pSrcPic->uiTimeStamp, pBsInfo->eFrameType, pBsInfo->iFrameSizeInBytes, kiCurrentFrameMs); ///////////////////for test #ifdef OUTPUT_BIT_STREAM if (pBsInfo->eFrameType != videoFrameTypeInvalid && pBsInfo->eFrameType != videoFrameTypeSkip) { SLayerBSInfo* pLayer = NULL; int32_t i = 0, j = 0, iCurLayerBits = 0, total_bits = 0; if (m_bSwitch) { if (m_pFileBs) { WelsFclose (m_pFileBs); m_pFileBs = NULL; } if (m_pFileBsSize) { WelsFclose (m_pFileBsSize); m_pFileBsSize = NULL; } char strStreamFileName[128] = {0}; WelsSnprintf (strStreamFileName, 128, "adj%d_w%d.264", m_iSwitchTimes, m_pEncContext->pSvcParam->iPicWidth); m_pFileBs = WelsFopen (strStreamFileName, "wb"); WelsSnprintf (strStreamFileName, 128, "adj%d_w%d_size.iLen", m_iSwitchTimes, m_pEncContext->pSvcParam->iPicWidth); m_pFileBsSize = WelsFopen (strStreamFileName, "wb"); m_bSwitch = false; } for (i = 0; i < pBsInfo->iLayerNum; i++) { pLayer = &pBsInfo->sLayerInfo[i]; iCurLayerBits = 0; for (j = 0; j < pLayer->iNalCount; j++) { iCurLayerBits += pLayer->pNalLengthInByte[j]; } total_bits += iCurLayerBits; if (m_pFileBs != NULL) WelsFwrite (pLayer->pBsBuf, 1, iCurLayerBits, m_pFileBs); } if (m_pFileBsSize != NULL) WelsFwrite (&total_bits, sizeof (int32_t), 1, m_pFileBsSize); } #endif //OUTPUT_BIT_STREAM #ifdef DUMP_SRC_PICTURE DumpSrcPicture (pSrcPicList[0]->pData[0]); #endif // DUMP_SRC_PICTURE return cmResultSuccess; } int CWelsH264SVCEncoder::EncodeParameterSets (SFrameBSInfo* pBsInfo) { return WelsEncoderEncodeParameterSets (m_pEncContext, pBsInfo); } /* * Force key frame */ int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR) { if (! (m_pEncContext && m_bInitialFlag)) { return 1; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::ForceIntraFrame(), bIDR= %d", bIDR); ForceCodingIDR (m_pEncContext); m_pEncContext->sEncoderStatistics.uiIDRReqNum++; return 0; } void CWelsH264SVCEncoder::TraceParamInfo (SEncParamExt* pParam) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "iUsageType = %d,iPicWidth= %d;iPicHeight= %d;iTargetBitrate= %d;iMaxBitrate= %d;iRCMode= %d;iPaddingFlag= %d;iTemporalLayerNum= %d;iSpatialLayerNum= %d;fFrameRate= %.6ff;uiIntraPeriod= %d;" "eSpsPpsIdStrategy = %d;bPrefixNalAddingCtrl = %d;bEnableDenoise= %d;bEnableBackgroundDetection= %d;bEnableAdaptiveQuant= %d;bEnableFrameSkip= %d;bEnableLongTermReference= %d;iLtrMarkPeriod= %d;" "iComplexityMode = %d;iNumRefFrame = %d;iEntropyCodingModeFlag = %d;uiMaxNalSize = %d;iLTRRefNum = %d;iMultipleThreadIdc = %d;iLoopFilterDisableIdc = %d (offset(alpha/beta): %d,%d)", pParam->iUsageType, pParam->iPicWidth, pParam->iPicHeight, pParam->iTargetBitrate, pParam->iMaxBitrate, pParam->iRCMode, pParam->iPaddingFlag, pParam->iTemporalLayerNum, pParam->iSpatialLayerNum,