1146 lines · 39.9 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.
 *
 */

#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.

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