/*! * \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" #ifdef NO_DYNAMIC_VPEResult WELSAPI CreateVpInterface (void** ppCtx, int iVersion);EResult WELSAPI DestroyVpInterface (void** ppCtx, int iVersion);#endif namespace WelsSVCEnc { #define WelsSafeDelete(p) if(p){ delete (p); (p) = NULL; } //***** entry API declaration ************************************************************************//typedef EResult (WELSAPI* pfnCreateVpInterface) (void**, int);typedef EResult (WELSAPI* 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));} 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::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture** kppSrcPicList, const int32_t kiConfiguredLayerNum) { 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 != kiConfiguredLayerNum); if (!m_bOfficialBranch && (iNumDependencyLayer == 1)) { // check the input source uiSize to decide if need switch to official branch // NOTICE: the layernum=1 case is confused in official/non-official cases! SSourcePicture** pic_queue = (SSourcePicture**)kppSrcPicList; for (int32_t i = 0; i < iNumDependencyLayer; i++) { if (pSvcParam->sDependencyLayers[i].iFrameWidth != pic_queue[i]->iPicWidth || pSvcParam->sDependencyLayers[i].iFrameHeight != pic_queue[i]->iPicHeight) { m_bOfficialBranch = true; break; } } } m_bInitDone = true; } if (m_pInterfaceVp == NULL) return -1; if (kiConfiguredLayerNum <= 0) 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 assert (kiConfiguredLayerNum == 1); iSpatialNum = SingleLayerPreprocess (pCtx, kppSrcPicList[0], &m_sScaledPicture); } else { // for console each spatial pictures are available there iSpatialNum = kiConfiguredLayerNum; MultiLayerPreprocess (pCtx, kppSrcPicList, iSpatialNum); } 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 = pCtx->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 = pCtx->uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx; SPicture* pCurPic = pCtx->pSpatialPic[kiDidx][iCurTemporalIdx]; SPicture* pRefPic = pCtx->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;} /** 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 = pCtx->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 : pCtx->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 = pCtx->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 ? pCtx->pSpatialPic[iDependencyId][pCtx->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] = pCtx->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 = pCtx->uiSpatialLayersInTemporal[iDependencyId] - 1; // NOT work for CGS, FIXME // spatial layer is able to encode indeed if ((iTemporalId != INVALID_TEMPORAL_ID)) { // down sampling performed pDstPic = pCtx->pSpatialPic[iDependencyId][iPicturePos]; // small iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight); WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); -- iActualSpatialLayerNum; ++ iSpatialNum; m_pLastSpatialPicture[iDependencyId][1] = pCtx->pSpatialPic[iDependencyId][iPicturePos]; } -- iDependencyId; } } return iSpatialNum;} int32_t CWelsPreProcess::MultiLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture** kppSrcPicList, const int32_t kiSpatialNum) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; const SSourcePicture* pSrc = NULL; SPicture* pDstPic = NULL; const int32_t iSpatialLayersCfgCount = pSvcParam->iSpatialLayerNum; // count number of spatial layers to be encoded in cfg int32_t i = 0; int32_t j = -1; do { pSrc = kppSrcPicList[i]; // do not clear j, just let it continue to save complexity do { ++ j; if (pSvcParam->sDependencyLayers[j].iFrameWidth == pSrc->iPicWidth && pSvcParam->sDependencyLayers[j].iFrameHeight == pSrc->iPicHeight) { break; } } while (j < iSpatialLayersCfgCount); assert (j < iSpatialLayersCfgCount); pDstPic = pCtx->pSpatialPic[j][pCtx->uiSpatialLayersInTemporal[j] - 1]; WelsUpdateSpatialIdxMap (pCtx, i, pDstPic, j); WelsMoveMemoryWrapper (pSvcParam, pDstPic, pSrc, pSrc->iPicWidth, pSrc->iPicHeight); if (pSvcParam->bEnableDenoise) BilateralDenoising (pDstPic, pSrc->iPicWidth, pSrc->iPicHeight); m_pLastSpatialPicture[j][1] = pDstPic; ++ i; } while (i < kiSpatialNum); Lines 1–500 of 1019. 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. * */ #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" #ifdef NO_DYNAMIC_VP EResult WELSAPI CreateVpInterface (void** ppCtx, int iVersion); EResult WELSAPI DestroyVpInterface (void** ppCtx, int iVersion); #endif namespace WelsSVCEnc { #define WelsSafeDelete(p) if(p){ delete (p); (p) = NULL; } //***** entry API declaration ************************************************************************// typedef EResult (WELSAPI* pfnCreateVpInterface) (void**, int); typedef EResult (WELSAPI* 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)); } 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::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture** kppSrcPicList, const int32_t kiConfiguredLayerNum) { 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 != kiConfiguredLayerNum); if (!m_bOfficialBranch && (iNumDependencyLayer == 1)) { // check the input source uiSize to decide if need switch to official branch // NOTICE: the layernum=1 case is confused in official/non-official cases! SSourcePicture** pic_queue = (SSourcePicture**)kppSrcPicList; for (int32_t i = 0; i < iNumDependencyLayer; i++) { if (pSvcParam->sDependencyLayers[i].iFrameWidth != pic_queue[i]->iPicWidth || pSvcParam->sDependencyLayers[i].iFrameHeight != pic_queue[i]->iPicHeight) { m_bOfficialBranch = true; break; } } } m_bInitDone = true; } if (m_pInterfaceVp == NULL) return -1; if (kiConfiguredLayerNum <= 0) 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 assert (kiConfiguredLayerNum == 1); iSpatialNum = SingleLayerPreprocess (pCtx, kppSrcPicList[0], &m_sScaledPicture); } else { // for console each spatial pictures are available there iSpatialNum = kiConfiguredLayerNum; MultiLayerPreprocess (pCtx, kppSrcPicList, iSpatialNum); } 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 = pCtx->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 = pCtx->uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx; SPicture* pCurPic = pCtx->pSpatialPic[kiDidx][iCurTemporalIdx]; SPicture* pRefPic = pCtx->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; } /* * 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 = pCtx->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 : pCtx->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 = pCtx->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 ? pCtx->pSpatialPic[iDependencyId][pCtx->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] = pCtx->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 = pCtx->uiSpatialLayersInTemporal[iDependencyId] - 1; // NOT work for CGS, FIXME // spatial layer is able to encode indeed if ((iTemporalId != INVALID_TEMPORAL_ID)) { // down sampling performed pDstPic = pCtx->pSpatialPic[iDependencyId][iPicturePos]; // small iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight); WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); -- iActualSpatialLayerNum; ++ iSpatialNum; m_pLastSpatialPicture[iDependencyId][1] = pCtx->pSpatialPic[iDependencyId][iPicturePos]; } -- iDependencyId; } } return iSpatialNum; } int32_t CWelsPreProcess::MultiLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture** kppSrcPicList, const int32_t kiSpatialNum) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; const SSourcePicture* pSrc = NULL; SPicture* pDstPic = NULL; const int32_t iSpatialLayersCfgCount = pSvcParam->iSpatialLayerNum; // count number of spatial layers to be encoded in cfg int32_t i = 0; int32_t j = -1; do { pSrc = kppSrcPicList[i]; // do not clear j, just let it continue to save complexity do { ++ j; if (pSvcParam->sDependencyLayers[j].iFrameWidth == pSrc->iPicWidth && pSvcParam->sDependencyLayers[j].iFrameHeight == pSrc->iPicHeight) { break; } } while (j < iSpatialLayersCfgCount); assert (j < iSpatialLayersCfgCount); pDstPic = pCtx->pSpatialPic[j][pCtx->uiSpatialLayersInTemporal[j] - 1]; WelsUpdateSpatialIdxMap (pCtx, i, pDstPic, j); WelsMoveMemoryWrapper (pSvcParam, pDstPic, pSrc, pSrc->iPicWidth, pSrc->iPicHeight); if (pSvcParam->bEnableDenoise) BilateralDenoising (pDstPic, pSrc->iPicWidth, pSrc->iPicHeight); m_pLastSpatialPicture[j][1] = pDstPic; ++ i; } while (i < kiSpatialNum);