openh264/codec/encoder/core/src/wels_preprocess.cpp

1056 lines
39 KiB
C++
Raw Normal View History

/*!
* \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 (void* pEncCtx) {
m_pInterface[0] = m_pInterface[1] = NULL;
#ifndef NO_DYNAMIC_VP
#if defined(_WIN32)
2014-02-08 23:28:42 +02:00
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)
2014-02-08 23:28:42 +02:00
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__)
2014-02-08 23:28:42 +02:00
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
}
2014-02-08 23:28:42 +02:00
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 (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 bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE));
bool 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 bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq);
bool 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->bEncCurFrmAsIdrFlag
&& ! (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
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];
}
-- iDependencyId;
}
}
return iSpatialNum;
}
int32_t CWelsPreProcess::MultiLayerPreprocess (void* pCtx, const SSourcePicture** kppSrcPicList,
const int32_t kiSpatialNum) {
sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcCodingParam* pSvcParam = pEncCtx->pSvcParam;
const SSourcePicture* pSrc = NULL;
SPicture* pDstPic = NULL;
const int32_t iSpatialLayersCfgCount =
pSvcParam->iNumDependencyLayer; // 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 = pEncCtx->pSpatialPic[j][pEncCtx->uiSpatialLayersInTemporal[j] - 1];
WelsUpdateSpatialIdxMap (pEncCtx, 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);
if (pSvcParam->bEnableSceneChangeDetect && (kiSpatialNum == pSvcParam->iNumDependencyLayer)
&& !pEncCtx->pVaa->bIdrPeriodFlag && !pEncCtx->bEncCurFrmAsIdrFlag) {
SPicture* pRef = pEncCtx->pLtr[0].bReceivedT0LostFlag ?
pEncCtx->pSpatialPic[0][pEncCtx->uiSpatialLayersInTemporal[0] + pEncCtx->pVaa->uiValidLongTermPicIdx] :
m_pLastSpatialPicture[0][0];
pEncCtx->pVaa->bSceneChangeFlag = DetectSceneChange (pDstPic, pRef);
}
return 0;
}
/*!
* \brief Whether input picture need be scaled?
*/
bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture) {
const int32_t kiInputPicWidth = pParam->SUsedPicRect.iWidth;
const int32_t kiInputPicHeight = pParam->SUsedPicRect.iHeight;
const int32_t kiDstPicWidth = pParam->sDependencyLayers[pParam->iNumDependencyLayer - 1].iActualWidth;
const int32_t kiDstPicHeight = pParam->sDependencyLayers[pParam->iNumDependencyLayer - 1].iActualHeight;
bool bNeedDownsampling = true;
int32_t iSpatialIdx = pParam->iNumDependencyLayer - 1;
if (kiDstPicWidth >= kiInputPicWidth && kiDstPicHeight >= kiInputPicHeight) {
iSpatialIdx --; // highest D layer do not need downsampling
bNeedDownsampling = false;
}
for (; iSpatialIdx >= 0; iSpatialIdx --) {
SDLayerParam* pCurLayer = &pParam->sDependencyLayers[iSpatialIdx];
int32_t iCurDstWidth = pCurLayer->iActualWidth;
int32_t iCurDstHeight = pCurLayer->iActualHeight;
int32_t iInputWidthXDstHeight = kiInputPicWidth * iCurDstHeight;
int32_t iInputHeightXDstWidth = kiInputPicHeight * iCurDstWidth;
if (iInputWidthXDstHeight > iInputHeightXDstWidth) {
pScaledPicture->iScaledWidth[iSpatialIdx] = iCurDstWidth;
pScaledPicture->iScaledHeight[iSpatialIdx] = iInputHeightXDstWidth / kiInputPicWidth;
} else {
pScaledPicture->iScaledWidth[iSpatialIdx] = iInputWidthXDstHeight / kiInputPicHeight;
pScaledPicture->iScaledHeight[iSpatialIdx] = iCurDstHeight;
}
}
return bNeedDownsampling;
}
int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) {
bool bInputPicNeedScaling = JudgeNeedOfScaling (pParam, pScaledPicture);
if (bInputPicNeedScaling) {
pScaledPicture->pScaledInputPicture = AllocPicture (pMemoryAlign, pParam->SUsedPicRect.iWidth,
pParam->SUsedPicRect.iHeight, false);
if (pScaledPicture->pScaledInputPicture == NULL)
return -1;
}
return 0;
}
void FreeScaledPic (Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) {
if (pScaledPicture->pScaledInputPicture) {
FreePicture (pMemoryAlign, &pScaledPicture->pScaledInputPicture);
pScaledPicture->pScaledInputPicture = NULL;
}
}
int32_t CWelsPreProcess::InitLastSpatialPictures (void* pCtx) {
sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcCodingParam* pParam = pEncCtx->pSvcParam;
const int32_t kiDlayerCount = pParam->iNumDependencyLayer;
int32_t iDlayerIndex = 0;
for (; iDlayerIndex < kiDlayerCount; iDlayerIndex++) {
const int32_t kiLayerInTemporal = pEncCtx->uiSpatialLayersInTemporal[iDlayerIndex];
m_pLastSpatialPicture[iDlayerIndex][0] = pEncCtx->pSpatialPic[iDlayerIndex][kiLayerInTemporal - 2];
m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
}
for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) {
m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
}
return 0;
}
//*********************************************************************************************************/
int32_t CWelsPreProcess::ColorspaceConvert (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
const SSourcePicture* kpSrc, const int32_t kiWidth, const int32_t kiHeight) {
return 1;
//not support yet
}
void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, const int32_t kiHeight) {
int32_t iMethodIdx = METHOD_DENOISE;
SPixMap sSrcPixMap = {0};
sSrcPixMap.pPixel[0] = pSrc->pData[0];
sSrcPixMap.pPixel[1] = pSrc->pData[1];
sSrcPixMap.pPixel[2] = pSrc->pData[2];
sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sSrcPixMap.sRect.iRectWidth = kiWidth;
sSrcPixMap.sRect.iRectHeight = kiHeight;
sSrcPixMap.iStride[0] = pSrc->iLineSize[0];
sSrcPixMap.iStride[1] = pSrc->iLineSize[1];
sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, NULL);
}
bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
bool bSceneChangeFlag = false;
int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION;
SSceneChangeResult sSceneChangeDetectResult = {0};
SPixMap sSrcPixMap = {0};
SPixMap sRefPixMap = {0};
sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
sRefPixMap.pPixel[0] = pRefPicture->pData[0];
sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
sRefPixMap.eFormat = VIDEO_FORMAT_I420;
int32_t iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
if (iRet == 0) {
m_pInterfaceVp->Get (iMethodIdx, (void*)&sSceneChangeDetectResult);
bSceneChangeFlag = sSceneChangeDetectResult.bSceneChangeFlag ? true : false;
}
return bSceneChangeFlag;
}
int32_t CWelsPreProcess::DownsamplePadding (SPicture* pSrc, SPicture* pDstPic, int32_t iSrcWidth, int32_t iSrcHeight,
int32_t iShrinkWidth, int32_t iShrinkHeight, int32_t iTargetWidth, int32_t iTargetHeight) {
int32_t iRet = 0;
SPixMap sSrcPixMap = {0};
SPixMap sDstPicMap = {0};
sSrcPixMap.pPixel[0] = pSrc->pData[0];
sSrcPixMap.pPixel[1] = pSrc->pData[1];
sSrcPixMap.pPixel[2] = pSrc->pData[2];
sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sSrcPixMap.sRect.iRectWidth = iSrcWidth;
sSrcPixMap.sRect.iRectHeight = iSrcHeight;
sSrcPixMap.iStride[0] = pSrc->iLineSize[0];
sSrcPixMap.iStride[1] = pSrc->iLineSize[1];
sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight) {
int32_t iMethodIdx = METHOD_DOWNSAMPLE;
sDstPicMap.pPixel[0] = pDstPic->pData[0];
sDstPicMap.pPixel[1] = pDstPic->pData[1];
sDstPicMap.pPixel[2] = pDstPic->pData[2];
sDstPicMap.iSizeInBits = g_kiPixMapSizeInBits;
sDstPicMap.sRect.iRectWidth = iShrinkWidth;
sDstPicMap.sRect.iRectHeight = iShrinkHeight;
sDstPicMap.iStride[0] = pDstPic->iLineSize[0];
sDstPicMap.iStride[1] = pDstPic->iLineSize[1];
sDstPicMap.iStride[2] = pDstPic->iLineSize[2];
sDstPicMap.eFormat = VIDEO_FORMAT_I420;
iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sDstPicMap);
} else {
memcpy (&sDstPicMap, &sSrcPixMap, sizeof (sDstPicMap)); // confirmed_safe_unsafe_usage
}
// get rid of odd line
iShrinkWidth -= (iShrinkWidth & 1);
iShrinkHeight -= (iShrinkHeight & 1);
Padding ((uint8_t*)sDstPicMap.pPixel[0], (uint8_t*)sDstPicMap.pPixel[1], (uint8_t*)sDstPicMap.pPixel[2],
sDstPicMap.iStride[0], sDstPicMap.iStride[1], iShrinkWidth, iTargetWidth, iShrinkHeight, iTargetHeight);
return iRet;
}
//*********************************************************************************************************/
void CWelsPreProcess::VaaCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
bool bCalculateSQDiff, bool bCalculateVar, bool bCalculateBGD) {
pVaaInfo->sVaaCalcInfo.pCurY = pCurPicture->pData[0];
pVaaInfo->sVaaCalcInfo.pRefY = pRefPicture->pData[0];
{
int32_t iMethodIdx = METHOD_VAA_STATISTICS;
SPixMap sCurPixMap = {0};
SPixMap sRefPixMap = {0};
SVAACalcParam calc_param = {0};
sCurPixMap.pPixel[0] = pCurPicture->pData[0];
sCurPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sCurPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
sCurPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
sCurPixMap.iStride[0] = pCurPicture->iLineSize[0];
sCurPixMap.eFormat = VIDEO_FORMAT_I420;
sRefPixMap.pPixel[0] = pRefPicture->pData[0];
sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
sRefPixMap.eFormat = VIDEO_FORMAT_I420;
calc_param.iCalcVar = bCalculateVar;
calc_param.iCalcBgd = bCalculateBGD;
calc_param.iCalcSsd = bCalculateSQDiff;
calc_param.pCalcResult = &pVaaInfo->sVaaCalcInfo;
m_pInterfaceVp->Set (iMethodIdx, &calc_param);
m_pInterfaceVp->Process (iMethodIdx, &sCurPixMap, &sRefPixMap);
}
}
void CWelsPreProcess::BackgroundDetection (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
bool bDetectFlag) {
if (bDetectFlag) {
pVaaInfo->iPicWidth = pCurPicture->iWidthInPixel;
pVaaInfo->iPicHeight = pCurPicture->iHeightInPixel;
pVaaInfo->iPicStride = pCurPicture->iLineSize[0];
pVaaInfo->iPicStrideUV = pCurPicture->iLineSize[1];
pVaaInfo->pCurY = pCurPicture->pData[0];
pVaaInfo->pRefY = pRefPicture->pData[0];
pVaaInfo->pCurU = pCurPicture->pData[1];
pVaaInfo->pRefU = pRefPicture->pData[1];
pVaaInfo->pCurV = pCurPicture->pData[2];
pVaaInfo->pRefV = pRefPicture->pData[2];
int32_t iMethodIdx = METHOD_BACKGROUND_DETECTION;
SPixMap sSrcPixMap = {0};
SPixMap sRefPixMap = {0};
SBGDInterface BGDParam = {0};
sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
sSrcPixMap.pPixel[1] = pCurPicture->pData[1];
sSrcPixMap.pPixel[2] = pCurPicture->pData[2];
sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
sSrcPixMap.iStride[1] = pCurPicture->iLineSize[1];
sSrcPixMap.iStride[2] = pCurPicture->iLineSize[2];
sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
sRefPixMap.pPixel[0] = pRefPicture->pData[0];
sRefPixMap.pPixel[1] = pRefPicture->pData[1];
sRefPixMap.pPixel[2] = pRefPicture->pData[2];
sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
sRefPixMap.iStride[1] = pRefPicture->iLineSize[1];
sRefPixMap.iStride[2] = pRefPicture->iLineSize[2];
sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
sRefPixMap.eFormat = VIDEO_FORMAT_I420;
BGDParam.pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
BGDParam.pCalcRes = & (pVaaInfo->sVaaCalcInfo);
m_pInterfaceVp->Set (iMethodIdx, (void*)&BGDParam);
m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
} else {
int32_t iPicWidthInMb = (pCurPicture->iWidthInPixel + 15) >> 4;
int32_t iPicHeightInMb = (pCurPicture->iHeightInPixel + 15) >> 4;
memset (pVaaInfo->pVaaBackgroundMbFlag, 0, iPicWidthInMb * iPicHeightInMb);
}
}
void CWelsPreProcess::AdaptiveQuantCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture) {
pVaaInfo->sAdaptiveQuantParam.pCalcResult = & (pVaaInfo->sVaaCalcInfo);
pVaaInfo->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp = 0;
{
int32_t iMethodIdx = METHOD_ADAPTIVE_QUANT;
SPixMap pSrc = {0};
SPixMap pRef = {0};
int32_t iRet = 0;
pSrc.pPixel[0] = pCurPicture->pData[0];
pSrc.iSizeInBits = g_kiPixMapSizeInBits;
pSrc.iStride[0] = pCurPicture->iLineSize[0];
pSrc.sRect.iRectWidth = pCurPicture->iWidthInPixel;
pSrc.sRect.iRectHeight = pCurPicture->iHeightInPixel;
pSrc.eFormat = VIDEO_FORMAT_I420;
pRef.pPixel[0] = pRefPicture->pData[0];
pRef.iSizeInBits = g_kiPixMapSizeInBits;
pRef.iStride[0] = pRefPicture->iLineSize[0];
pRef.sRect.iRectWidth = pRefPicture->iWidthInPixel;
pRef.sRect.iRectHeight = pRefPicture->iHeightInPixel;
pRef.eFormat = VIDEO_FORMAT_I420;
iRet = m_pInterfaceVp->Set (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
iRet = m_pInterfaceVp->Process (iMethodIdx, &pSrc, &pRef);
if (iRet == 0)
m_pInterfaceVp->Get (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
}
}
void CWelsPreProcess::SetRefMbType (void* pCtx, uint32_t** pRefMbTypeArray, int32_t iRefPicType) {
sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
const uint8_t uiTid = pEncCtx->uiTemporalId;
const uint8_t uiDid = pEncCtx->uiDependencyId;
SRefList* pRefPicLlist = pEncCtx->ppRefPicListExt[uiDid];
SLTRState* pLtr = &pEncCtx->pLtr[uiDid];
uint8_t i = 0;
if (pEncCtx->pSvcParam->bEnableLongTermReference && pLtr->bReceivedT0LostFlag && uiTid == 0) {
for (i = 0; i < pRefPicLlist->uiLongRefCount; i++) {
SPicture* pRef = pRefPicLlist->pLongRefList[i];
if (pRef != NULL && pRef->uiRecieveConfirmed == 1/*RECIEVE_SUCCESS*/) {
*pRefMbTypeArray = pRef->uiRefMbType;
break;
}
}
} else {
for (i = 0; i < pRefPicLlist->uiShortRefCount; i++) {
SPicture* pRef = pRefPicLlist->pShortRefList[i];
if (pRef != NULL && pRef->bUsedAsRef && pRef->iFramePoc >= 0 && pRef->uiTemporalId <= uiTid) {
*pRefMbTypeArray = pRef->uiRefMbType;
break;
}
}
}
}
void CWelsPreProcess::AnalyzePictureComplexity (void* pCtx, SPicture* pCurPicture, SPicture* pRefPicture,
const int32_t kiDependencyId, const bool bCalculateBGD) {
sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcCodingParam* pSvcParam = pEncCtx->pSvcParam;
SVAAFrameInfo* pVaaInfo = pEncCtx->pVaa;
SComplexityAnalysisParam* sComplexityAnalysisParam = & (pVaaInfo->sComplexityAnalysisParam);
SWelsSvcRc* SWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDependencyId];
int32_t iComplexityAnalysisMode = 0;
if (pSvcParam->iRCMode == RC_MODE0 && pEncCtx->eSliceType == P_SLICE) {
iComplexityAnalysisMode = FRAME_SAD;
} else if (pSvcParam->iRCMode == RC_MODE1 && pEncCtx->eSliceType == P_SLICE) {
iComplexityAnalysisMode = GOM_SAD;
} else if (pSvcParam->iRCMode == RC_MODE1 && pEncCtx->eSliceType == I_SLICE) {
iComplexityAnalysisMode = GOM_VAR;
} else {
return;
}
sComplexityAnalysisParam->iComplexityAnalysisMode = iComplexityAnalysisMode;
sComplexityAnalysisParam->pCalcResult = & (pVaaInfo->sVaaCalcInfo);
sComplexityAnalysisParam->pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
SetRefMbType (pEncCtx, & (sComplexityAnalysisParam->uiRefMbType), pRefPicture->iPictureType);
sComplexityAnalysisParam->iCalcBgd = bCalculateBGD;
sComplexityAnalysisParam->iFrameComplexity = 0;
memset (SWelsSvcRc->pGomForegroundBlockNum, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
if (iComplexityAnalysisMode != FRAME_SAD)
memset (SWelsSvcRc->pCurrentFrameGomSad, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
sComplexityAnalysisParam->pGomComplexity = SWelsSvcRc->pCurrentFrameGomSad;
sComplexityAnalysisParam->pGomForegroundBlockNum = SWelsSvcRc->pGomForegroundBlockNum;
sComplexityAnalysisParam->iMbNumInGom = SWelsSvcRc->iNumberMbGom;
{
int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS;
SPixMap sSrcPixMap = {0};
SPixMap sRefPixMap = {0};
int32_t iRet = 0;
sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
sRefPixMap.pPixel[0] = pRefPicture->pData[0];
sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
sRefPixMap.eFormat = VIDEO_FORMAT_I420;
iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
if (iRet == 0)
m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
}
}
void CWelsPreProcess::Padding (uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iStrideY, int32_t iStrideUV,
int32_t iActualWidth, int32_t iPaddingWidth, int32_t iActualHeight, int32_t iPaddingHeight) {
int32_t i;
if (iPaddingHeight > iActualHeight) {
for (i = iActualHeight; i < iPaddingHeight; i++) {
memset (pSrcY + i * iStrideY, 0, iActualWidth);
if (! (i & 1)) {
memset (pSrcU + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
memset (pSrcV + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
}
}
}
if (iPaddingWidth > iActualWidth) {
for (i = 0; i < iPaddingHeight; i++) {
memset (pSrcY + i * iStrideY + iActualWidth, 0, iPaddingWidth - iActualWidth);
if (! (i & 1)) {
memset (pSrcU + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
memset (pSrcV + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
}
}
}
}
//TODO: may opti later
//TODO: not use this func?
void* WelsMemcpy (void* dst, const void* kpSrc, uint32_t uiSize) {
return ::memcpy (dst, kpSrc, uiSize);
}
void* WelsMemset (void* p, int32_t val, uint32_t uiSize) {
return ::memset (p, val, uiSize);
}
//i420_to_i420_c
void WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV, int32_t iDstStrideY, int32_t iDstStrideUV,
uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth,
int32_t iHeight) {
int32_t iWidth2 = iWidth >> 1;
int32_t iHeight2 = iHeight >> 1;
int32_t j;
for (j = iHeight; j; j--) {
WelsMemcpy (pDstY, pSrcY, iWidth);
pDstY += iDstStrideY;
pSrcY += iSrcStrideY;
}
for (j = iHeight2; j; j--) {
WelsMemcpy (pDstU, pSrcU, iWidth2);
WelsMemcpy (pDstV, pSrcV, iWidth2);
pDstU += iDstStrideUV;
pDstV += iDstStrideUV;
pSrcU += iSrcStrideUV;
pSrcV += iSrcStrideUV;
}
}
//vp's padding
void VPpadding (uint8_t* pSrcPtr, int32_t iCurWidth, int32_t iTargetWidth, int32_t iCurHeight, int32_t iTargetHeight,
int32_t iStride, uint8_t uiStuffValue) {
uint8_t* pTmp;
if (iTargetWidth > iCurWidth) {
pTmp = pSrcPtr + iCurWidth;
for (int32_t i = 0; i < iCurHeight; i++) {
WelsMemset (pTmp, uiStuffValue, iTargetWidth - iCurWidth);
pTmp += iStride;
}
}
if (iTargetHeight > iCurHeight) {
pTmp = pSrcPtr + iCurHeight * iStride;
for (int32_t i = iCurHeight; i < iTargetHeight; i++) {
WelsMemset (pTmp, uiStuffValue, iTargetWidth);
pTmp += iStride;
}
}
}
void CWelsPreProcess::WelsMoveMemoryWrapper (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
const SSourcePicture* kpSrc,
const int32_t kiTargetWidth, const int32_t kiTargetHeight) {
if (VIDEO_FORMAT_I420 != (kpSrc->iColorFormat & (~VIDEO_FORMAT_VFlip)))
return;
int32_t iSrcWidth = kpSrc->iPicWidth;
int32_t iSrcHeight = kpSrc->iPicHeight;
if (iSrcHeight > kiTargetHeight) iSrcHeight = kiTargetHeight;
if (iSrcWidth > kiTargetWidth) iSrcWidth = kiTargetWidth;
// copy from fr26 to fix the odd uiSize failed issue
if (iSrcWidth & 0x1) -- iSrcWidth;
if (iSrcHeight & 0x1) -- iSrcHeight;
const int32_t kiSrcTopOffsetY = pSvcParam->SUsedPicRect.iTop;
const int32_t kiSrcTopOffsetUV = (kiSrcTopOffsetY >> 1);
const int32_t kiSrcLeftOffsetY = pSvcParam->SUsedPicRect.iLeft;
const int32_t kiSrcLeftOffsetUV = (kiSrcLeftOffsetY >> 1);
int32_t iSrcOffset[3] = {0, 0, 0};
iSrcOffset[0] = kpSrc->iStride[0] * kiSrcTopOffsetY + kiSrcLeftOffsetY;
iSrcOffset[1] = kpSrc->iStride[1] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV ;
iSrcOffset[2] = kpSrc->iStride[2] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV;
uint8_t* pSrcY = kpSrc->pData[0] + iSrcOffset[0];
uint8_t* pSrcU = kpSrc->pData[1] + iSrcOffset[1];
uint8_t* pSrcV = kpSrc->pData[2] + iSrcOffset[2];
const int32_t kiSrcStrideY = kpSrc->iStride[0];
const int32_t kiSrcStrideUV = kpSrc->iStride[1];
uint8_t* pDstY = pDstPic->pData[0];
uint8_t* pDstU = pDstPic->pData[1];
uint8_t* pDstV = pDstPic->pData[2];
const int32_t kiDstStrideY = pDstPic->iLineSize[0];
const int32_t kiDstStrideUV = pDstPic->iLineSize[1];
#define MAX_WIDTH (4096)
#define MAX_HEIGHT (2304)//MAX_FS_LEVEL51 (36864); MAX_FS_LEVEL51*256/4096 = 2304
if (pSrcY) {
if (iSrcWidth <= 0 || iSrcWidth > MAX_WIDTH || iSrcHeight <= 0 || iSrcHeight > MAX_HEIGHT)
return;
if (kiSrcTopOffsetY >= iSrcHeight || kiSrcLeftOffsetY >= iSrcWidth || iSrcWidth > kiSrcStrideY)
return;
}
if (pDstY) {
if (kiTargetWidth <= 0 || kiTargetWidth > MAX_WIDTH || kiTargetHeight <= 0 || kiTargetHeight > MAX_HEIGHT)
return;
if (kiTargetWidth > kiDstStrideY)
return;
}
if (pSrcY == NULL || pSrcU == NULL || pSrcV == NULL || pDstY == NULL || pDstU == NULL || pDstV == NULL
|| (iSrcWidth & 1) || (iSrcHeight & 1)) {
} else {
//i420_to_i420_c
WelsMoveMemory_c (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV,
pSrcY, pSrcU, pSrcV, kiSrcStrideY, kiSrcStrideUV, iSrcWidth, iSrcHeight);
//in VP Process
if (kiTargetWidth > iSrcWidth || kiTargetHeight > iSrcHeight) {
const int32_t kiTargetWidthC = (kiTargetWidth >> 1);
const int32_t kiTargetHeightC = (kiTargetHeight >> 1);
const int32_t kiSrcWidthC = (iSrcWidth >> 1);
const int32_t kiSrcHeightC = (iSrcHeight >> 1);
// padding pDstPic I420
VPpadding ((uint8_t*)pDstY, iSrcWidth, kiTargetWidth, iSrcHeight, kiTargetHeight, kiDstStrideY, 0);
VPpadding ((uint8_t*)pDstU, kiSrcWidthC, kiTargetWidthC, kiSrcHeightC, kiTargetHeightC, kiDstStrideUV, 0x80);
VPpadding ((uint8_t*)pDstV, kiSrcWidthC, kiTargetWidthC, kiSrcHeightC, kiTargetHeightC, kiDstStrideUV, 0x80);
}
}
}
//*********************************************************************************************************/
} // namespace WelsSVCEnc