1389 lines · 55.7 KB · C++
RawDownload
/*! * \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) {    WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_DEBUG,             "CWelsH264SVCEncoder::EncodeFrame() not succeed, err=%d", kiEncoderReturn);    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   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) || (kiEncoderReturn == ENC_RETURN_MEMOVERFLOWFOUND)      || (kiEncoderReturn == ENC_RETURN_VLCOVERFLOWFOUND)) {    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 cmUnknownReason;  }   UpdateStatistics (pBsInfo, 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 (pSrcPic, m_pEncContext->pSvcParam->iUsageType);#endif // DUMP_SRC_PICTURE   return cmResultSuccess; } int CWelsH264SVCEncoder::EncodeParameterSets (SFrameBSInfo* pBsInfo) {  return WelsEncoderEncodeParameterSets (m_pEncContext, pBsInfo);} /* *  Force key frame */int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR, int iLayerId) {  if (bIDR) {    if (! (m_pEncContext && m_bInitialFlag)) {      return 1;    }     ForceCodingIDR (m_pEncContext, iLayerId);  } else {    WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,             "CWelsH264SVCEncoder::ForceIntraFrame(),nothing to do as bIDR set to false");  }   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;bSimulcastAVC=%d;bEnableDenoise= %d;bEnableBackgroundDetection= %d;bEnableSceneChangeDetect = %d;bEnableAdaptiveQuant= %d;bEnableFrameSkip= %d;bEnableLongTermReference= %d;iLtrMarkPeriod= %d, bIsLosslessLink=%d;"           "iComplexityMode = %d;iNumRefFrame = %d;iEntropyCodingModeFlag = %d;uiMaxNalSize = %d;iLTRRefNum = %d;iMultipleThreadIdc = %d;iLoopFilterDisableIdc = %d (offset(alpha/beta): %d,%d;iMaxQp = %d;iMinQp = %d)",           pParam->iUsageType,           pParam->iPicWidth,           pParam->iPicHeight,           pParam->iTargetBitrate,           pParam->iMaxBitrate,           pParam->iRCMode,           pParam->iPaddingFlag,

Lines 1–500 of 1389.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t