1068 lines · 39.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. * */ #ifndef NO_DYNAMIC_VP#if defined(_WIN32)#include <windows.h>#elif defined(MACOS)#include "bundleloader.h"#elif defined(__GNUC__)#include <dlfcn.h>#endif#endif #include "wels_preprocess.h"#include "picture_handle.h"#include "encoder_context.h"#include "utils.h" namespace WelsSVCEnc { #define WelsSafeDelete(p) if(p){ delete (p); (p) = NULL; }  //***** entry API declaration ************************************************************************//typedef EResult (* pfnCreateVpInterface) (void**, int);typedef EResult (* pfnDestroyVpInterface) (void*, int); int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam,  Scaled_Picture*  pScaledPic, CMemoryAlign* pMemoryAlign);bool  JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic);void    FreeScaledPic (Scaled_Picture*  pScaledPic, CMemoryAlign* pMemoryAlign); //******* table definition ***********************************************************************//const uint8_t g_kuiRefTemporalIdx[MAX_TEMPORAL_LEVEL][MAX_GOP_SIZE] = {  {  0, }, // 0  {  0,  0, }, // 1  {  0,  0,  0,  1, }, // 2  {  0,  0,  0,  2,  0,  1,  1,  2, }, // 3}; const int32_t g_kiPixMapSizeInBits = sizeof (uint8_t) * 8;  inline  void   WelsUpdateSpatialIdxMap (sWelsEncCtx* pEncCtx, int32_t iPos, SPicture* pPic, int32_t iDidx) {  pEncCtx->sSpatialIndexMap[iPos].pSrc = pPic;  pEncCtx->sSpatialIndexMap[iPos].iDid = iDidx;}  //***************************************************************************************************//CWelsLib::CWelsLib (sWelsEncCtx* pEncCtx) {  m_pInterface[0] = m_pInterface[1] = NULL; #ifndef NO_DYNAMIC_VP#if defined(_WIN32)  const char WelsVPLib[] = "welsvp.dll";  HMODULE shModule = LoadLibrary (WelsVPLib);  if (!shModule)    WelsLog (pEncCtx, WELS_LOG_ERROR, "welsvp load lib dynamic failed module=%x\n", shModule); #elif defined(MACOS)  const char WelsVPLib[] = "welsvp.bundle";  char pCurPath[256];  GetCurrentModulePath (pCurPath, 256);  strlcat (pCurPath, WelsVPLib, 256);  CFBundleRef shModule = LoadBundle (pCurPath);  if (!shModule)    WelsLog (pEncCtx, WELS_LOG_ERROR, "welsvp load lib dynamic failed module=%x\n", shModule); #elif defined(__GNUC__)  const char WelsVPLib[] = "./libwelsvp.so";  void* shModule = NULL;  shModule = dlopen (WelsVPLib, RTLD_LAZY);  if (shModule == NULL)    printf ("dlopen %s iRet=%p, err=%s\n", WelsVPLib, shModule, dlerror());#endif   m_pVpLib = (void*)shModule;#endif} CWelsLib::~CWelsLib() {#ifndef NO_DYNAMIC_VP  if (m_pVpLib) {#if defined(_WIN32)    HMODULE shModule = (HMODULE)m_pVpLib;    FreeLibrary (shModule); #elif defined(MACOS)    CFBundleRef shModule = (CFBundleRef)m_pVpLib;    FreeBundle (shModule); #elif defined(__GNUC__)    void* shModule = m_pVpLib;    dlclose (shModule);#endif    m_pVpLib = NULL;  }#endif} void* CWelsLib::QueryFunction (const char* pName) {  void* pFunc = NULL; #ifndef NO_DYNAMIC_VP  if (m_pVpLib) {#if defined(_WIN32)    HMODULE shModule = (HMODULE)m_pVpLib;    pFunc = (void*)GetProcAddress (shModule, pName); #elif defined(MACOS)    CFBundleRef shModule = (CFBundleRef)m_pVpLib;    pFunc = (void*)GetProcessAddress (shModule, pName); #elif defined(__GNUC__)    void* shModule = m_pVpLib;    pFunc = (void*)dlsym (shModule, pName);    if (pFunc == NULL)      printf ("dlsym %p iRet=%p, err=%s\n", shModule, pFunc, dlerror());#endif  }#endif  return pFunc;} int32_t CWelsLib::CreateIface (IWelsVP** ppInterfaceVp) {  *ppInterfaceVp = NULL;#ifndef NO_DYNAMIC_VP  if (m_pVpLib) { #endif    pfnCreateVpInterface  pCreateVpInterface  = NULL;    pfnDestroyVpInterface pDestroyVpInterface = NULL; #ifndef NO_DYNAMIC_VP    pCreateVpInterface  = (pfnCreateVpInterface)  QueryFunction ("CreateVpInterface");    pDestroyVpInterface = (pfnDestroyVpInterface) QueryFunction ("DestroyVpInterface");#else    pCreateVpInterface  = CreateVpInterface;    // TODO(ekr@rtfm.com): This cast corrects a signature difference... This is a potential real problem    pDestroyVpInterface = (pfnDestroyVpInterface)DestroyVpInterface;#endif     m_pInterface[0] = (void*)pCreateVpInterface;    m_pInterface[1] = (void*)pDestroyVpInterface;     if (m_pInterface[0] && m_pInterface[1])      pCreateVpInterface ((void**)ppInterfaceVp, WELSVP_INTERFACE_VERION);#ifndef NO_DYNAMIC_VP  } else {  }#endif   return (*ppInterfaceVp) ? 0 : 1;} int32_t CWelsLib::DestroyIface (IWelsVP* pInterfaceVp) {  if (pInterfaceVp) {    pfnDestroyVpInterface pDestroyVpInterface = (pfnDestroyVpInterface) m_pInterface[1];    if (pDestroyVpInterface) {      pDestroyVpInterface (pInterfaceVp, WELSVP_INTERFACE_VERION);    } else {    }  }   return 0;} /*****************************************************************************	implement of the interface****************************************************************************/ CWelsPreProcess::CWelsPreProcess (sWelsEncCtx* pEncCtx) {  m_pInterfaceVp = NULL;  m_pEncLib = NULL;  m_bInitDone = false;  m_bOfficialBranch  = false;  m_pEncCtx = pEncCtx;  memset (&m_sScaledPicture, 0, sizeof (m_sScaledPicture));  memset (m_pSpatialPic, 0, sizeof(m_pSpatialPic));  memset (m_uiSpatialLayersInTemporal, 0, sizeof(m_uiSpatialLayersInTemporal));  memset (m_uiSpatialPicNum, 0, sizeof(m_uiSpatialPicNum));} CWelsPreProcess::~CWelsPreProcess() {  FreeScaledPic (&m_sScaledPicture,  m_pEncCtx->pMemAlign);  WelsPreprocessDestroy();} int32_t CWelsPreProcess::WelsPreprocessCreate() {  if (m_pEncLib == NULL && m_pInterfaceVp == NULL) {    m_pEncLib  = new CWelsLib (m_pEncCtx);    if (!m_pEncLib)      goto exit;     m_pEncLib->CreateIface (&m_pInterfaceVp);    if (!m_pInterfaceVp)      goto exit;  } else    goto exit;   return 0; exit:  WelsPreprocessDestroy();  return 1;} int32_t CWelsPreProcess::WelsPreprocessDestroy() {  if (m_pEncLib) {    m_pEncLib->DestroyIface (m_pInterfaceVp);    m_pInterfaceVp = NULL;    WelsSafeDelete (m_pEncLib);  }   return 0;} int32_t CWelsPreProcess::WelsPreprocessReset (sWelsEncCtx* pCtx) {  int32_t iRet = -1;   if (pCtx) {    FreeScaledPic (&m_sScaledPicture, pCtx->pMemAlign);    iRet = InitLastSpatialPictures (pCtx);    iRet = WelsInitScaledPic (pCtx->pSvcParam, &m_sScaledPicture, pCtx->pMemAlign);  }   return iRet;} int32_t CWelsPreProcess::AllocSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam) {  CMemoryAlign* pMa						= pCtx->pMemAlign;  const int32_t kiDlayerCount					= pParam->iSpatialLayerNum;  int32_t iDlayerIndex							= 0;   // spatial pictures  iDlayerIndex = 0;  do {    const int32_t kiPicWidth = pParam->sDependencyLayers[iDlayerIndex].iFrameWidth;    const int32_t kiPicHeight   = pParam->sDependencyLayers[iDlayerIndex].iFrameHeight;    const uint8_t kuiLayerInTemporal = 2 + WELS_MAX (pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1);    const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum;    uint8_t i = 0;     do {      SPicture* pPic = AllocPicture (pMa, kiPicWidth, kiPicHeight, false);      WELS_VERIFY_RETURN_IF(1, (NULL == pPic))      m_pSpatialPic[iDlayerIndex][i] = pPic;      ++ i;    } while (i < kuiRefNumInTemporal);     m_uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal;    m_uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal;    ++ iDlayerIndex;  } while (iDlayerIndex < kiDlayerCount);   return 0;} void CWelsPreProcess::FreeSpatialPictures (sWelsEncCtx* pCtx) {  CMemoryAlign* pMa	= pCtx->pMemAlign;  int32_t j = 0;  while (j < pCtx->pSvcParam->iSpatialLayerNum) {    uint8_t i = 0;    uint8_t uiRefNumInTemporal = m_uiSpatialPicNum[j];     while (i < uiRefNumInTemporal) {      if (NULL != m_pSpatialPic[j][i]) {        FreePicture (pMa, &m_pSpatialPic[j][i]);      }      ++ i;    }    m_uiSpatialLayersInTemporal[j] = 0;    ++ j;  }} int32_t CWelsPreProcess::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture* kpSrcPic) {  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;  int32_t	iNumDependencyLayer = (int32_t)pSvcParam->iSpatialLayerNum;  int32_t iSpatialNum = 0;   if (!m_bInitDone) {    if (WelsPreprocessCreate() != 0)      return -1;    if (WelsPreprocessReset (pCtx) != 0)      return -1;     m_bOfficialBranch  = (iNumDependencyLayer != 1);    if ( iNumDependencyLayer == 1 ) {      if (pSvcParam->sDependencyLayers[0].iFrameWidth != kpSrcPic->iPicWidth ||          pSvcParam->sDependencyLayers[0].iFrameHeight != kpSrcPic->iPicHeight) {        m_bOfficialBranch = true;      }    }    m_bInitDone = true;  }   if (m_pInterfaceVp == NULL)    return -1;   pCtx->pVaa->bSceneChangeFlag = pCtx->pVaa->bIdrPeriodFlag = false;  if (pSvcParam->uiIntraPeriod)    pCtx->pVaa->bIdrPeriodFlag = (1 + pCtx->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod) ? true : false;   if (m_bOfficialBranch) {	// Perform Down Sampling potentially due to application    iSpatialNum	= SingleLayerPreprocess (pCtx, kpSrcPic, &m_sScaledPicture);  } else { // for console each spatial pictures are available there    iSpatialNum = 1;    MultiLayerPreprocess (pCtx, kpSrcPic);  }   return iSpatialNum;} int32_t CWelsPreProcess::AnalyzeSpatialPic (sWelsEncCtx* pCtx, const int32_t kiDidx) {  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;  bool bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pCtx->eSliceType == P_SLICE));  bool bCalculateBGD = (pCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection);   int32_t iCurTemporalIdx  = m_uiSpatialLayersInTemporal[kiDidx] - 1;   int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pCtx->iCodingIndex &                            (pSvcParam->uiGopSize - 1)];  if (pCtx->uiTemporalId == 0 && pCtx->pLtr[pCtx->uiDependencyId].bReceivedT0LostFlag)    iRefTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx;   SPicture* pCurPic = m_pSpatialPic[kiDidx][iCurTemporalIdx];  SPicture* pRefPic = m_pSpatialPic[kiDidx][iRefTemporalIdx];  {    SPicture* pLastPic = m_pLastSpatialPicture[kiDidx][0];    bool bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq);    bool bCalculateVar = (pSvcParam->iRCMode == RC_MODE1 && pCtx->eSliceType == I_SLICE);     VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD);  }   if (pSvcParam->bEnableBackgroundDetection) {    BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);  }   if (bNeededMbAq) {    SPicture* pCurPic = m_pLastSpatialPicture[kiDidx][1];    SPicture* pRefPic = m_pLastSpatialPicture[kiDidx][0];     AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic);  }   if (pSvcParam->bEnableRc) {    AnalyzePictureComplexity (pCtx, pCurPic, pRefPic, kiDidx, bCalculateBGD);  }   WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]);   return 0;} int32_t CWelsPreProcess::UpdateSpatialPictures(sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam,    const int8_t iCurTid, const int32_t d_idx) {  if (iCurTid < m_uiSpatialLayersInTemporal[d_idx] - 1 || pParam->iDecompStages == 0){    if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (m_uiSpatialLayersInTemporal[d_idx] - 1 > MAX_TEMPORAL_LEVEL)) {      InitLastSpatialPictures(pCtx);      return 1;    }    if (pParam->bEnableLongTermReference && pCtx->bLongTermRefFlag[d_idx][iCurTid]) {      SPicture* tmp	= m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx];      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx] =      m_pSpatialPic[d_idx][iCurTid];      m_pSpatialPic[d_idx][iCurTid] = m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1];      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1] = tmp;      pCtx->bLongTermRefFlag[d_idx][iCurTid] = false;    } else {      WelsExchangeSpatialPictures (&m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1],                                   &m_pSpatialPic[d_idx][iCurTid]);    }  }  return 0;}  /**	SingleLayerPreprocess: down sampling if applicable*  @return:	exact number of spatial layers need to encoder indeed*/int32_t CWelsPreProcess::SingleLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture* kpSrc,    Scaled_Picture* pScaledPicture) {  SWelsSvcCodingParam* pSvcParam    = pCtx->pSvcParam;  int8_t  iDependencyId             = pSvcParam->iSpatialLayerNum - 1;  int32_t iPicturePos               = m_uiSpatialLayersInTemporal[iDependencyId] - 1;   SPicture* pSrcPic					= NULL;	// large  SPicture* pDstPic					= NULL;	// small  SDLayerParam* pDlayerParam					= NULL;  int32_t iSpatialNum					= 0;  int32_t iSrcWidth					= 0;  int32_t iSrcHeight					= 0;  int32_t iTargetWidth					= 0;  int32_t iTargetHeight					= 0;  int32_t iTemporalId = 0;  int32_t iActualSpatialLayerNum      = 0;   pDlayerParam = &pSvcParam->sDependencyLayers[iDependencyId];  iTargetWidth	  = pDlayerParam->iFrameWidth;  iTargetHeight  = pDlayerParam->iFrameHeight;  iTemporalId    = pDlayerParam->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)];  iSrcWidth   = pSvcParam->SUsedPicRect.iWidth;  iSrcHeight  = pSvcParam->SUsedPicRect.iHeight;   pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture :            m_pSpatialPic[iDependencyId][iPicturePos];   WelsMoveMemoryWrapper (pSvcParam, pSrcPic, kpSrc, iSrcWidth, iSrcHeight);   if (pSvcParam->bEnableDenoise)    BilateralDenoising (pSrcPic, iSrcWidth, iSrcHeight);   // different scaling in between input picture and dst highest spatial picture.  int32_t iShrinkWidth  = iSrcWidth;  int32_t iShrinkHeight = iSrcHeight;  pDstPic = pSrcPic;  if (pScaledPicture->pScaledInputPicture) {    // for highest downsampling    pDstPic		= m_pSpatialPic[iDependencyId][iPicturePos];    iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];    iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];  }  DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight);   if (pSvcParam->bEnableSceneChangeDetect && !pCtx->pVaa->bIdrPeriodFlag      && !pCtx->bEncCurFrmAsIdrFlag      && ! (pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1))) {    SPicture* pRefPic = pCtx->pLtr[iDependencyId].bReceivedT0LostFlag ?                        m_pSpatialPic[iDependencyId][m_uiSpatialLayersInTemporal[iDependencyId] +                            pCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0];     pCtx->pVaa->bSceneChangeFlag = DetectSceneChange (pDstPic, pRefPic);  }   for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) {    if (pSvcParam->sDependencyLayers[i].uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]        != INVALID_TEMPORAL_ID) {      ++ iActualSpatialLayerNum;    }  }   if (iTemporalId != INVALID_TEMPORAL_ID) {    WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId);    ++ iSpatialNum;    -- iActualSpatialLayerNum;  }   m_pLastSpatialPicture[iDependencyId][1]	= m_pSpatialPic[iDependencyId][iPicturePos];  -- iDependencyId;   // generate other spacial layer  // pSrc is  //	-- padded input pic, if downsample should be applied to generate highest layer, [if] block above  //	-- highest layer, if no downsampling, [else] block above  if (pSvcParam->iSpatialLayerNum > 1) {    while (iDependencyId >= 0) {      pDlayerParam			= &pSvcParam->sDependencyLayers[iDependencyId];      iTargetWidth	= pDlayerParam->iFrameWidth;      iTargetHeight	= pDlayerParam->iFrameHeight;      iTemporalId = pDlayerParam->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)];      iPicturePos		= m_uiSpatialLayersInTemporal[iDependencyId] - 1;       // NOT work for CGS, FIXME      // spatial layer is able to encode indeed      if ((iTemporalId != INVALID_TEMPORAL_ID)) {        // down sampling performed

Lines 1–500 of 1068.

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