/*!
* \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.
*
*/
#if defined(WIN32)
#include <windows.h>
#elif defined(MACOS)
#include "bundleloader.h"
#elif defined(__GNUC__)
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "wels_preprocess.h"
#include "memory_align.h"
#include "encoder.h"
#include "extern.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_t 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
{ 0, 0, 0, 3, 0, 2, 2, 3, 0, 1, 1, 3, 1, 2, 2, 3 } // 4
};
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(void *pEncCtx)
{
m_pInterface[0] = m_pInterface[1] = NULL;
#ifndef NO_DYNAMIC_VP
#if defined(WIN32)
const str_t 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 str_t WelsVPLib[] = "welsvp.bundle";
str_t 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 str_t WelsVPLib[] = "./libwelsvp.so";
void* shModule = NULL;
shModule = dlopen(WelsVPLib, RTLD_LAZY);
if (shModule == NULL)
printf("dlopen %s iRet=%x, err=%s\n", WelsVPLib, shModule, dlerror());
#endif
m_pVpLib = (void *)shModule;
#endif
}
CWelsLib::~CWelsLib()
{
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;
}
}
void* CWelsLib::QueryFunction(const str_t *pName)
{
void *pFunc = NULL;
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 %s iRet=%p, err=%s\n", shModule, pFunc, dlerror());
#endif
}
return pFunc;
}
int32_t CWelsLib::CreateIface(void **ppEncCtx)
{
#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(ppEncCtx, WELSVP_INTERFACE_VERION);
#ifndef NO_DYNAMIC_VP
}
else
{
}
#endif
return ppEncCtx ? 0 : 1;
}
int32_t CWelsLib::DestroyIface(void *pEncCtx)
{
if (pEncCtx)
{
pfnDestroyVpInterface pDestroyVpInterface = (pfnDestroyVpInterface) m_pInterface[1];
if (pDestroyVpInterface)
{
pDestroyVpInterface(pEncCtx, WELSVP_INTERFACE_VERION);
}
else
{
}
}
return 0;
}
/***************************************************************************
*
* implement of the interface
*
***************************************************************************/
CWelsPreProcess::CWelsPreProcess(void *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, static_cast<sWelsEncCtx *>(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((void **)&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((void *)m_pInterfaceVp);
m_pInterfaceVp = NULL;
WelsSafeDelete(m_pEncLib);
}
return 0;
}
int32_t CWelsPreProcess::WelsPreprocessReset ( void *pCtx )
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx;
int32_t iRet = -1;
if (pEncCtx)
{
FreeScaledPic(&m_sScaledPicture, pEncCtx->pMemAlign);
iRet = InitLastSpatialPictures(pEncCtx);
iRet = WelsInitScaledPic(pEncCtx->pSvcParam, &m_sScaledPicture, pEncCtx->pMemAlign);
}
return iRet;
}
int32_t CWelsPreProcess::WelsPreprocessStep1( void *pCtx, const SSourcePicture **kppSrcPicList, const int32_t kiConfiguredLayerNum )
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx;
SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam;
int32_t iNumDependencyLayer = (int32_t)pSvcParam->iNumDependencyLayer;
int32_t iSpatialNum = 0;
if (!m_bInitDone)
{
if (WelsPreprocessCreate() != 0)
return -1;
if (WelsPreprocessReset(pEncCtx) != 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;
pEncCtx->pVaa->bSceneChangeFlag = pEncCtx->pVaa->bIdrPeriodFlag = false;
if( pSvcParam->uiIntraPeriod )
pEncCtx->pVaa->bIdrPeriodFlag = ( 1 + pEncCtx->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod ) ? true : false;
if ( m_bOfficialBranch ) // Perform Down Sampling potentially due to application
{
assert( kiConfiguredLayerNum == 1 );
iSpatialNum = SingleLayerPreprocess( pEncCtx, kppSrcPicList[0], &m_sScaledPicture );
}
else // for console each spatial pictures are available there
{
iSpatialNum = kiConfiguredLayerNum;
MultiLayerPreprocess( pEncCtx, kppSrcPicList, iSpatialNum );
}
return iSpatialNum;
}
int32_t CWelsPreProcess::WelsPreprocessStep3( void *pCtx, const int32_t kiDidx )
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx;
SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam;
bool_t bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE));
bool_t bCalculateBGD = (pEncCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection);
int32_t iCurTemporalIdx = pEncCtx->uiSpatialLayersInTemporal[kiDidx] - 1;
int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)];
if ( pEncCtx->uiTemporalId == 0 && pEncCtx->pLtr[pEncCtx->uiDependencyId].bReceivedT0LostFlag )
iRefTemporalIdx = pEncCtx->uiSpatialLayersInTemporal[kiDidx] + pEncCtx->pVaa->uiValidLongTermPicIdx;
SPicture *pCurPic = pEncCtx->pSpatialPic[kiDidx][iCurTemporalIdx];
SPicture *pRefPic = pEncCtx->pSpatialPic[kiDidx][iRefTemporalIdx];
{
SPicture *pLastPic= m_pLastSpatialPicture[kiDidx][0];
bool_t bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq);
bool_t bCalculateVar = (pSvcParam->iRCMode == RC_MODE1 && pEncCtx->eSliceType == I_SLICE);
VaaCalculation( pEncCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD);
}
if (pSvcParam->bEnableBackgroundDetection)
{
BackgroundDetection(pEncCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);
}
if ( bNeededMbAq )
{
SPicture *pCurPic = m_pLastSpatialPicture[kiDidx][1];
SPicture *pRefPic = m_pLastSpatialPicture[kiDidx][0];
AdaptiveQuantCalculation( pEncCtx->pVaa, pCurPic, pRefPic );
}
if ( pSvcParam->bEnableRc )
{
AnalyzePictureComplexity( pEncCtx, 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( void *pCtx, const SSourcePicture *kpSrc, Scaled_Picture * pScaledPicture )
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx;
SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam;
int8_t iDependencyId = pSvcParam->iNumDependencyLayer - 1;
int32_t iPicturePos = pEncCtx->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[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)];
iSrcWidth = pSvcParam->SUsedPicRect.iWidth;
iSrcHeight = pSvcParam->SUsedPicRect.iHeight;
pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : pEncCtx->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 = pEncCtx->pSpatialPic[iDependencyId][iPicturePos];
iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
}
DownsamplePadding(pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight);
if(pSvcParam->bEnableSceneChangeDetect && !pEncCtx->pVaa->bIdrPeriodFlag && !(pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1))){
SPicture *pRefPic = pEncCtx->pLtr[iDependencyId].bReceivedT0LostFlag ?
pEncCtx->pSpatialPic[iDependencyId][pEncCtx->uiSpatialLayersInTemporal[iDependencyId] + pEncCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0];
pEncCtx->pVaa->bSceneChangeFlag = DetectSceneChange(pDstPic, pRefPic);
}
for( int32_t i=0;i<pSvcParam->iNumDependencyLayer;i++ ){
if( pSvcParam->sDependencyLayers[i].uiCodingIdx2TemporalId[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)]
!= INVALID_TEMPORAL_ID ){
++ iActualSpatialLayerNum;
}
}
if ( iTemporalId != INVALID_TEMPORAL_ID )
{
WelsUpdateSpatialIdxMap(pEncCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId);
++ iSpatialNum;
-- iActualSpatialLayerNum;
}
m_pLastSpatialPicture[iDependencyId][1] = pEncCtx->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->iNumDependencyLayer > 1 )
{
while (iDependencyId >= 0)
{
pDlayerParam = &pSvcParam->sDependencyLayers[iDependencyId];
iTargetWidth = pDlayerParam->iFrameWidth;
iTargetHeight = pDlayerParam->iFrameHeight;
iTemporalId = pDlayerParam->uiCodingIdx2TemporalId[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)];
iPicturePos = pEncCtx->uiSpatialLayersInTemporal[iDependencyId] - 1;
// NOT work for CGS, FIXME
// spatial layer is able to encode indeed
if ( (iTemporalId != INVALID_TEMPORAL_ID) )
{
// down sampling performed
if( NULL == pSrcPic )
return -1;
pDstPic = pEncCtx->pSpatialPic[iDependencyId][iPicturePos]; // small
iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
DownsamplePadding(pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight);
WelsUpdateSpatialIdxMap(pEncCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId);
-- iActualSpatialLayerNum;
++ iSpatialNum;
m_pLastSpatialPicture[iDependencyId][1] = pEncCtx->pSpatialPic[iDependencyId][iPicturePos];
}
Lines 1–500 of 1146. 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. * */ #if defined(WIN32) #include <windows.h> #elif defined(MACOS) #include "bundleloader.h" #elif defined(__GNUC__) #include <dlfcn.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "wels_preprocess.h" #include "memory_align.h" #include "encoder.h" #include "extern.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_t 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 { 0, 0, 0, 3, 0, 2, 2, 3, 0, 1, 1, 3, 1, 2, 2, 3 } // 4 }; 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(void *pEncCtx) { m_pInterface[0] = m_pInterface[1] = NULL; #ifndef NO_DYNAMIC_VP #if defined(WIN32) const str_t 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 str_t WelsVPLib[] = "welsvp.bundle"; str_t 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 str_t WelsVPLib[] = "./libwelsvp.so"; void* shModule = NULL; shModule = dlopen(WelsVPLib, RTLD_LAZY); if (shModule == NULL) printf("dlopen %s iRet=%x, err=%s\n", WelsVPLib, shModule, dlerror()); #endif m_pVpLib = (void *)shModule; #endif } CWelsLib::~CWelsLib() { 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; } } void* CWelsLib::QueryFunction(const str_t *pName) { void *pFunc = NULL; 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 %s iRet=%p, err=%s\n", shModule, pFunc, dlerror()); #endif } return pFunc; } int32_t CWelsLib::CreateIface(void **ppEncCtx) { #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(ppEncCtx, WELSVP_INTERFACE_VERION); #ifndef NO_DYNAMIC_VP } else { } #endif return ppEncCtx ? 0 : 1; } int32_t CWelsLib::DestroyIface(void *pEncCtx) { if (pEncCtx) { pfnDestroyVpInterface pDestroyVpInterface = (pfnDestroyVpInterface) m_pInterface[1]; if (pDestroyVpInterface) { pDestroyVpInterface(pEncCtx, WELSVP_INTERFACE_VERION); } else { } } return 0; } /*************************************************************************** * * implement of the interface * ***************************************************************************/ CWelsPreProcess::CWelsPreProcess(void *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, static_cast<sWelsEncCtx *>(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((void **)&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((void *)m_pInterfaceVp); m_pInterfaceVp = NULL; WelsSafeDelete(m_pEncLib); } return 0; } int32_t CWelsPreProcess::WelsPreprocessReset ( void *pCtx ) { sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx; int32_t iRet = -1; if (pEncCtx) { FreeScaledPic(&m_sScaledPicture, pEncCtx->pMemAlign); iRet = InitLastSpatialPictures(pEncCtx); iRet = WelsInitScaledPic(pEncCtx->pSvcParam, &m_sScaledPicture, pEncCtx->pMemAlign); } return iRet; } int32_t CWelsPreProcess::WelsPreprocessStep1( void *pCtx, const SSourcePicture **kppSrcPicList, const int32_t kiConfiguredLayerNum ) { sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx; SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam; int32_t iNumDependencyLayer = (int32_t)pSvcParam->iNumDependencyLayer; int32_t iSpatialNum = 0; if (!m_bInitDone) { if (WelsPreprocessCreate() != 0) return -1; if (WelsPreprocessReset(pEncCtx) != 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; pEncCtx->pVaa->bSceneChangeFlag = pEncCtx->pVaa->bIdrPeriodFlag = false; if( pSvcParam->uiIntraPeriod ) pEncCtx->pVaa->bIdrPeriodFlag = ( 1 + pEncCtx->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod ) ? true : false; if ( m_bOfficialBranch ) // Perform Down Sampling potentially due to application { assert( kiConfiguredLayerNum == 1 ); iSpatialNum = SingleLayerPreprocess( pEncCtx, kppSrcPicList[0], &m_sScaledPicture ); } else // for console each spatial pictures are available there { iSpatialNum = kiConfiguredLayerNum; MultiLayerPreprocess( pEncCtx, kppSrcPicList, iSpatialNum ); } return iSpatialNum; } int32_t CWelsPreProcess::WelsPreprocessStep3( void *pCtx, const int32_t kiDidx ) { sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx; SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam; bool_t bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE)); bool_t bCalculateBGD = (pEncCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection); int32_t iCurTemporalIdx = pEncCtx->uiSpatialLayersInTemporal[kiDidx] - 1; int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)]; if ( pEncCtx->uiTemporalId == 0 && pEncCtx->pLtr[pEncCtx->uiDependencyId].bReceivedT0LostFlag ) iRefTemporalIdx = pEncCtx->uiSpatialLayersInTemporal[kiDidx] + pEncCtx->pVaa->uiValidLongTermPicIdx; SPicture *pCurPic = pEncCtx->pSpatialPic[kiDidx][iCurTemporalIdx]; SPicture *pRefPic = pEncCtx->pSpatialPic[kiDidx][iRefTemporalIdx]; { SPicture *pLastPic= m_pLastSpatialPicture[kiDidx][0]; bool_t bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq); bool_t bCalculateVar = (pSvcParam->iRCMode == RC_MODE1 && pEncCtx->eSliceType == I_SLICE); VaaCalculation( pEncCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD); } if (pSvcParam->bEnableBackgroundDetection) { BackgroundDetection(pEncCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE); } if ( bNeededMbAq ) { SPicture *pCurPic = m_pLastSpatialPicture[kiDidx][1]; SPicture *pRefPic = m_pLastSpatialPicture[kiDidx][0]; AdaptiveQuantCalculation( pEncCtx->pVaa, pCurPic, pRefPic ); } if ( pSvcParam->bEnableRc ) { AnalyzePictureComplexity( pEncCtx, 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( void *pCtx, const SSourcePicture *kpSrc, Scaled_Picture * pScaledPicture ) { sWelsEncCtx *pEncCtx = (sWelsEncCtx *)pCtx; SWelsSvcCodingParam *pSvcParam = pEncCtx->pSvcParam; int8_t iDependencyId = pSvcParam->iNumDependencyLayer - 1; int32_t iPicturePos = pEncCtx->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[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)]; iSrcWidth = pSvcParam->SUsedPicRect.iWidth; iSrcHeight = pSvcParam->SUsedPicRect.iHeight; pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : pEncCtx->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 = pEncCtx->pSpatialPic[iDependencyId][iPicturePos]; iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; } DownsamplePadding(pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight); if(pSvcParam->bEnableSceneChangeDetect && !pEncCtx->pVaa->bIdrPeriodFlag && !(pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1))){ SPicture *pRefPic = pEncCtx->pLtr[iDependencyId].bReceivedT0LostFlag ? pEncCtx->pSpatialPic[iDependencyId][pEncCtx->uiSpatialLayersInTemporal[iDependencyId] + pEncCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0]; pEncCtx->pVaa->bSceneChangeFlag = DetectSceneChange(pDstPic, pRefPic); } for( int32_t i=0;i<pSvcParam->iNumDependencyLayer;i++ ){ if( pSvcParam->sDependencyLayers[i].uiCodingIdx2TemporalId[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)] != INVALID_TEMPORAL_ID ){ ++ iActualSpatialLayerNum; } } if ( iTemporalId != INVALID_TEMPORAL_ID ) { WelsUpdateSpatialIdxMap(pEncCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); ++ iSpatialNum; -- iActualSpatialLayerNum; } m_pLastSpatialPicture[iDependencyId][1] = pEncCtx->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->iNumDependencyLayer > 1 ) { while (iDependencyId >= 0) { pDlayerParam = &pSvcParam->sDependencyLayers[iDependencyId]; iTargetWidth = pDlayerParam->iFrameWidth; iTargetHeight = pDlayerParam->iFrameHeight; iTemporalId = pDlayerParam->uiCodingIdx2TemporalId[pEncCtx->iCodingIndex & (pSvcParam->uiGopSize-1)]; iPicturePos = pEncCtx->uiSpatialLayersInTemporal[iDependencyId] - 1; // NOT work for CGS, FIXME // spatial layer is able to encode indeed if ( (iTemporalId != INVALID_TEMPORAL_ID) ) { // down sampling performed if( NULL == pSrcPic ) return -1; pDstPic = pEncCtx->pSpatialPic[iDependencyId][iPicturePos]; // small iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; DownsamplePadding(pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight); WelsUpdateSpatialIdxMap(pEncCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); -- iActualSpatialLayerNum; ++ iSpatialNum; m_pLastSpatialPicture[iDependencyId][1] = pEncCtx->pSpatialPic[iDependencyId][iPicturePos]; }