Add FME unit test

This commit is contained in:
sijchen 2014-05-05 15:41:15 +08:00
parent cf5edec5ae
commit 44640712f6
5 changed files with 1418 additions and 1240 deletions

View File

@ -127,6 +127,7 @@ typedef struct TagFeatureSearchOut{
}SFeatureSearchOut; }SFeatureSearchOut;
#define COST_MVD(table, mx, my) (table[mx] + table[my]) #define COST_MVD(table, mx, my) (table[mx] + table[my])
extern const int32_t QStepx16ByQp[52];
// Function definitions below // Function definitions below
@ -242,36 +243,32 @@ int32_t ReleaseFeatureSearchPreparation( CMemoryAlign *pMa, uint16_t*& pFeatureO
#define FMESWITCH_DEFAULT_GOODFRAME_NUM (2) #define FMESWITCH_DEFAULT_GOODFRAME_NUM (2)
#define FME_DEFAULT_FEATURE_INDEX (0) #define FME_DEFAULT_FEATURE_INDEX (0)
void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef,
SScreenBlockFeatureStorage* pScreenBlockFeatureStorage);
void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef, uint16_t* pFeatureOfBlock,
SScreenBlockFeatureStorage* pScreenBlockFeatureStorage);
void UpdateFMESwitch(SDqLayer* pCurLayer); void UpdateFMESwitch(SDqLayer* pCurLayer);
void UpdateFMESwitchNull(SDqLayer* pCurLayer); void UpdateFMESwitchNull(SDqLayer* pCurLayer);
//inline functions //inline functions
inline void SetMvWithinIntegerMvRange( const int32_t kiMbWidth, const int32_t kiMbHeight, const int32_t kiMbX, const int32_t kiMbY, inline void SetMvWithinIntegerMvRange( const int32_t kiMbWidth, const int32_t kiMbHeight, const int32_t kiMbX, const int32_t kiMbY,
const int32_t kiMaxMvRange, const int32_t kiMaxMvRange,
SMVUnitXY* pMvMin, SMVUnitXY* pMvMax) SMVUnitXY* pMvMin, SMVUnitXY* pMvMax) {
{
pMvMin->iMvX = WELS_MAX(-1*((kiMbX + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange); pMvMin->iMvX = WELS_MAX(-1*((kiMbX + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange);
pMvMin->iMvY = WELS_MAX(-1*((kiMbY + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange); pMvMin->iMvY = WELS_MAX(-1*((kiMbY + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange);
pMvMax->iMvX = WELS_MIN( ((kiMbWidth - kiMbX)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange); pMvMax->iMvX = WELS_MIN( ((kiMbWidth - kiMbX)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange);
pMvMax->iMvY = WELS_MIN( ((kiMbHeight - kiMbY)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange); pMvMax->iMvY = WELS_MIN( ((kiMbHeight - kiMbY)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange);
} }
inline bool CheckMvInRange( const int16_t kiCurrentMv, const int16_t kiMinMv, const int16_t kiMaxMv ) inline bool CheckMvInRange( const int16_t kiCurrentMv, const int16_t kiMinMv, const int16_t kiMaxMv ) {
{
return ((kiCurrentMv >= kiMinMv) && (kiCurrentMv < kiMaxMv)); return ((kiCurrentMv >= kiMinMv) && (kiCurrentMv < kiMaxMv));
} }
inline bool CheckMvInRange( const SMVUnitXY ksCurrentMv, const SMVUnitXY ksMinMv, const SMVUnitXY ksMaxMv ) inline bool CheckMvInRange( const SMVUnitXY ksCurrentMv, const SMVUnitXY ksMinMv, const SMVUnitXY ksMaxMv ) {
{
return (CheckMvInRange(ksCurrentMv.iMvX, ksMinMv.iMvX, ksMaxMv.iMvX) return (CheckMvInRange(ksCurrentMv.iMvX, ksMinMv.iMvX, ksMaxMv.iMvX)
&& CheckMvInRange(ksCurrentMv.iMvY, ksMinMv.iMvY, ksMaxMv.iMvY)); && CheckMvInRange(ksCurrentMv.iMvY, ksMinMv.iMvY, ksMaxMv.iMvY));
} }
//FME switch related //FME switch related
inline bool CalcFMESwitchFlag(const uint8_t uiFMEGoodFrameCount, const int32_t iHighFreMbPrecentage, inline bool CalcFMESwitchFlag(const uint8_t uiFMEGoodFrameCount, const int32_t iHighFreMbPrecentage,
const int32_t iAvgMbSAD, const bool bScrollingDetected ) const int32_t iAvgMbSAD, const bool bScrollingDetected ) {
{
return ( bScrollingDetected ||( uiFMEGoodFrameCount>0 && iAvgMbSAD > FMESWITCH_MBSAD_THRESHOLD ) ); return ( bScrollingDetected ||( uiFMEGoodFrameCount>0 && iAvgMbSAD > FMESWITCH_MBSAD_THRESHOLD ) );
//TODO: add the logic of iHighFreMbPrecentage //TODO: add the logic of iHighFreMbPrecentage
//return ( iHighFreMbPrecentage > 2 //return ( iHighFreMbPrecentage > 2

View File

@ -2467,9 +2467,8 @@ void PreprocessSliceCoding (sWelsEncCtx* pCtx) {
pFeatureSearchPreparation->pRefBlockFeature = pScreenBlockFeatureStorage; pFeatureSearchPreparation->pRefBlockFeature = pScreenBlockFeatureStorage;
if (pFeatureSearchPreparation->bFMESwitchFlag if (pFeatureSearchPreparation->bFMESwitchFlag
&& !pScreenBlockFeatureStorage->bRefBlockFeatureCalculated) { && !pScreenBlockFeatureStorage->bRefBlockFeatureCalculated) {
pScreenBlockFeatureStorage->pFeatureOfBlockPointer = pFeatureSearchPreparation->pFeatureOfBlock;
//TODO: use ORIGIN of reference when preprocessing is ready //TODO: use ORIGIN of reference when preprocessing is ready
PerformFMEPreprocess( pFuncList, pCurLayer->pRefPic, pScreenBlockFeatureStorage ); PerformFMEPreprocess( pFuncList, pCurLayer->pRefPic,pFeatureSearchPreparation->pFeatureOfBlock,pScreenBlockFeatureStorage);
} }
//assign ME pointer //assign ME pointer

View File

@ -57,14 +57,12 @@ const int32_t QStepx16ByQp[52] = { /* save QStep<<4 for int32_t */
2560, 2816, 3328, 3584 /* 48~51 */ 2560, 2816, 3328, 3584 /* 48~51 */
}; };
static inline void UpdateMeResults( const SMVUnitXY ksBestMv, const uint32_t kiBestSadCost, uint8_t* pRef, SWelsME * pMe ) static inline void UpdateMeResults( const SMVUnitXY ksBestMv, const uint32_t kiBestSadCost, uint8_t* pRef, SWelsME * pMe ) {
{
pMe->sMv = ksBestMv; pMe->sMv = ksBestMv;
pMe->pRefMb = pRef; pMe->pRefMb = pRef;
pMe->uiSadCost = kiBestSadCost; pMe->uiSadCost = kiBestSadCost;
} }
static inline void MeEndIntepelSearch( SWelsME * pMe ) static inline void MeEndIntepelSearch( SWelsME * pMe ) {
{
/* -> qpel mv */ /* -> qpel mv */
pMe->sMv.iMvX <<= 2; pMe->sMv.iMvX <<= 2;
pMe->sMv.iMvY <<= 2; pMe->sMv.iMvY <<= 2;
@ -597,14 +595,20 @@ int32_t RequestScreenBlockFeatureStorage( CMemoryAlign *pMa, const int32_t kiFra
} }
int32_t ReleaseScreenBlockFeatureStorage( CMemoryAlign *pMa, SScreenBlockFeatureStorage* pScreenBlockFeatureStorage ) { int32_t ReleaseScreenBlockFeatureStorage( CMemoryAlign *pMa, SScreenBlockFeatureStorage* pScreenBlockFeatureStorage ) {
if ( pMa && pScreenBlockFeatureStorage ) { if ( pMa && pScreenBlockFeatureStorage ) {
if (pScreenBlockFeatureStorage->pTimesOfFeatureValue) {
pMa->WelsFree( pScreenBlockFeatureStorage->pTimesOfFeatureValue, "pScreenBlockFeatureStorage->pTimesOfFeatureValue"); pMa->WelsFree( pScreenBlockFeatureStorage->pTimesOfFeatureValue, "pScreenBlockFeatureStorage->pTimesOfFeatureValue");
pScreenBlockFeatureStorage->pTimesOfFeatureValue=NULL; pScreenBlockFeatureStorage->pTimesOfFeatureValue=NULL;
}
if (pScreenBlockFeatureStorage->pLocationOfFeature) {
pMa->WelsFree( pScreenBlockFeatureStorage->pLocationOfFeature, "pScreenBlockFeatureStorage->pLocationOfFeature"); pMa->WelsFree( pScreenBlockFeatureStorage->pLocationOfFeature, "pScreenBlockFeatureStorage->pLocationOfFeature");
pScreenBlockFeatureStorage->pLocationOfFeature=NULL; pScreenBlockFeatureStorage->pLocationOfFeature=NULL;
}
if (pScreenBlockFeatureStorage->pLocationPointer) {
pMa->WelsFree( pScreenBlockFeatureStorage->pLocationPointer, "pScreenBlockFeatureStorage->pLocationPointer"); pMa->WelsFree( pScreenBlockFeatureStorage->pLocationPointer, "pScreenBlockFeatureStorage->pLocationPointer");
pScreenBlockFeatureStorage->pLocationPointer=NULL; pScreenBlockFeatureStorage->pLocationPointer=NULL;
}
return ENC_RETURN_SUCCESS; return ENC_RETURN_SUCCESS;
} }
@ -724,8 +728,10 @@ void CalculateFeatureOfBlock( SWelsFuncPtrList *pFunc, SPicture* pRef,
FillQpelLocationByFeatureValue_c(pFeatureOfBlock, iWidth, kiHeight, pFeatureValuePointerList); FillQpelLocationByFeatureValue_c(pFeatureOfBlock, iWidth, kiHeight, pFeatureValuePointerList);
} }
void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef, void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef, uint16_t* pFeatureOfBlock,
SScreenBlockFeatureStorage* pScreenBlockFeatureStorage) { SScreenBlockFeatureStorage* pScreenBlockFeatureStorage)
{
pScreenBlockFeatureStorage->pFeatureOfBlockPointer = pFeatureOfBlock;
CalculateFeatureOfBlock(pFunc, pRef, pScreenBlockFeatureStorage ); CalculateFeatureOfBlock(pFunc, pRef, pScreenBlockFeatureStorage );
pScreenBlockFeatureStorage->bRefBlockFeatureCalculated = true; pScreenBlockFeatureStorage->bRefBlockFeatureCalculated = true;

View File

@ -7,6 +7,15 @@
#include "wels_func_ptr_def.h" #include "wels_func_ptr_def.h"
#include "cpu.h" #include "cpu.h"
namespace WelsSVCEnc {
extern void SetFeatureSearchIn( SWelsFuncPtrList *pFunc, const SWelsME& sMe,
const SSlice *pSlice, SScreenBlockFeatureStorage* pRefFeatureStorage,
const int32_t kiEncStride, const int32_t kiRefStride,
SFeatureSearchIn* pFeatureSearchIn );
extern void MotionEstimateFeatureFullSearch( SFeatureSearchIn &sFeatureSearchIn,
const uint32_t kuiMaxSearchPoint,
SWelsME* pMe);
}
using namespace WelsSVCEnc; using namespace WelsSVCEnc;
@ -32,10 +41,14 @@ void InitMe( const uint8_t kuiQp, const uint32_t kuiMvdTableMiddle, const uint32
pMe->sMv.iMvX = pMe->sMv.iMvY = 0; pMe->sMv.iMvX = pMe->sMv.iMvY = 0;
} }
static inline int GetRandomMv(int32_t iMin, int32_t iMax) {
return (rand()%(iMax-iMin)-(iMax-iMin)/2);
}
class MotionEstimateTest : public ::testing::Test { class MotionEstimateTest : public ::testing::Test {
public: public:
virtual void SetUp() { virtual void SetUp() {
m_pRefPic = NULL; m_pRefData = NULL;
m_pSrcBlock = NULL; m_pSrcBlock = NULL;
m_pMvdCostTable = NULL; m_pMvdCostTable = NULL;
@ -45,9 +58,9 @@ public:
m_uiMvdTableSize = (1 + (648 << 1)); m_uiMvdTableSize = (1 + (648 << 1));
pMa = new CMemoryAlign(0); pMa = new CMemoryAlign(0);
m_pRefPic = static_cast<uint8_t *> m_pRefData = static_cast<uint8_t *>
(pMa->WelsMalloc(m_iWidth*m_iHeight, "RefPic")); (pMa->WelsMalloc(m_iWidth*m_iHeight, "RefPic"));
ASSERT_TRUE( NULL != m_pRefPic ); ASSERT_TRUE( NULL != m_pRefData );
m_pSrcBlock = static_cast<uint8_t *> m_pSrcBlock = static_cast<uint8_t *>
(pMa->WelsMalloc(m_iMaxSearchBlock*m_iMaxSearchBlock, "SrcBlock")); (pMa->WelsMalloc(m_iMaxSearchBlock*m_iMaxSearchBlock, "SrcBlock"));
ASSERT_TRUE( NULL != m_pSrcBlock ); ASSERT_TRUE( NULL != m_pSrcBlock );
@ -56,12 +69,12 @@ public:
} }
virtual void TearDown() { virtual void TearDown() {
delete [] m_pMvdCostTable; delete [] m_pMvdCostTable;
pMa->WelsFree( m_pRefPic, "RefPic"); pMa->WelsFree( m_pRefData, "RefPic");
pMa->WelsFree( m_pSrcBlock, "SrcBlock"); pMa->WelsFree( m_pSrcBlock, "SrcBlock");
delete pMa; delete pMa;
} }
public: public:
uint8_t *m_pRefPic; uint8_t *m_pRefData;
uint8_t *m_pSrcBlock; uint8_t *m_pSrcBlock;
uint32_t m_uiMvdTableSize; uint32_t m_uiMvdTableSize;
uint16_t *m_pMvdCostTable; uint16_t *m_pMvdCostTable;
@ -88,7 +101,7 @@ TEST_F(MotionEstimateTest, TestDiamondSearch) {
SMVUnitXY sTargetMv; SMVUnitXY sTargetMv;
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2); uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
bool bDataGeneratorSucceed = false; bool bDataGeneratorSucceed = false;
bool bFoundMatch = false; bool bFoundMatch = false;
int32_t i, iTryTimes; int32_t i, iTryTimes;
@ -99,7 +112,7 @@ TEST_F(MotionEstimateTest, TestDiamondSearch) {
bDataGeneratorSucceed = false; bDataGeneratorSucceed = false;
bFoundMatch = false; bFoundMatch = false;
while (!bFoundMatch && (iTryTimes--)>0) { while (!bFoundMatch && (iTryTimes--)>0) {
if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth )) if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue; continue;
bDataGeneratorSucceed = true; bDataGeneratorSucceed = true;
@ -138,7 +151,7 @@ TEST_F(MotionEstimateTest, TestVerticalSearch) {
SMVUnitXY sTargetMv; SMVUnitXY sTargetMv;
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2); uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
sMe.iCurMeBlockPixX = (m_iWidth/2); sMe.iCurMeBlockPixX = (m_iWidth/2);
sMe.iCurMeBlockPixY = (m_iHeight/2); sMe.iCurMeBlockPixY = (m_iHeight/2);
@ -151,7 +164,7 @@ TEST_F(MotionEstimateTest, TestVerticalSearch) {
bDataGeneratorSucceed = false; bDataGeneratorSucceed = false;
bFoundMatch = false; bFoundMatch = false;
while (!bFoundMatch && (iTryTimes--)>0) { while (!bFoundMatch && (iTryTimes--)>0) {
if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth )) if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue; continue;
bDataGeneratorSucceed = true; bDataGeneratorSucceed = true;
@ -199,7 +212,7 @@ TEST_F(MotionEstimateTest, TestHorizontalSearch) {
SMVUnitXY sTargetMv; SMVUnitXY sTargetMv;
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2); uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
sMe.iCurMeBlockPixX = (m_iWidth/2); sMe.iCurMeBlockPixX = (m_iWidth/2);
sMe.iCurMeBlockPixY = (m_iHeight/2); sMe.iCurMeBlockPixY = (m_iHeight/2);
@ -212,7 +225,7 @@ TEST_F(MotionEstimateTest, TestHorizontalSearch) {
bDataGeneratorSucceed = false; bDataGeneratorSucceed = false;
bFoundMatch = false; bFoundMatch = false;
while (!bFoundMatch && (iTryTimes--)>0) { while (!bFoundMatch && (iTryTimes--)>0) {
if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth )) if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue; continue;
bDataGeneratorSucceed = true; bDataGeneratorSucceed = true;
@ -267,7 +280,7 @@ TEST_F(MotionEstimateTest, TestVerticalSearch_SSE41)
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1); WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2); uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
sMe.iCurMeBlockPixX = (m_iWidth/2); sMe.iCurMeBlockPixX = (m_iWidth/2);
sMe.iCurMeBlockPixY = (m_iHeight/2); sMe.iCurMeBlockPixY = (m_iHeight/2);
@ -280,7 +293,7 @@ TEST_F(MotionEstimateTest, TestVerticalSearch_SSE41)
bDataGeneratorSucceed = false; bDataGeneratorSucceed = false;
bFoundMatch = false; bFoundMatch = false;
while (!bFoundMatch && (iTryTimes--)>0) { while (!bFoundMatch && (iTryTimes--)>0) {
if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth )) if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue; continue;
bDataGeneratorSucceed = true; bDataGeneratorSucceed = true;
@ -333,7 +346,7 @@ TEST_F(MotionEstimateTest, TestHorizontalSearch_SSE41)
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1); WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2); uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
sMe.iCurMeBlockPixX = (m_iWidth/2); sMe.iCurMeBlockPixX = (m_iWidth/2);
sMe.iCurMeBlockPixY = (m_iHeight/2); sMe.iCurMeBlockPixY = (m_iHeight/2);
@ -346,13 +359,12 @@ TEST_F(MotionEstimateTest, TestHorizontalSearch_SSE41)
bDataGeneratorSucceed = false; bDataGeneratorSucceed = false;
bFoundMatch = false; bFoundMatch = false;
while (!bFoundMatch && (iTryTimes--)>0) { while (!bFoundMatch && (iTryTimes--)>0) {
if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth )) if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue; continue;
bDataGeneratorSucceed = true; bDataGeneratorSucceed = true;
CopyTargetBlock( m_pSrcBlock, 16, sTargetMv, m_iWidth, pRefPicCenter); CopyTargetBlock( m_pSrcBlock, m_iMaxSearchBlock, sTargetMv, m_iWidth, pRefPicCenter );
//clean the sMe status //clean sMe status
sMe.uiBlockSize = rand()%5; sMe.uiBlockSize = rand()%5;
sMe.pEncMb = m_pSrcBlock; sMe.pEncMb = m_pSrcBlock;
sMe.pRefMb = pRefPicCenter; sMe.pRefMb = pRefPicCenter;
@ -383,3 +395,167 @@ TEST_F(MotionEstimateTest, TestHorizontalSearch_SSE41)
} }
} }
#endif #endif
class FeatureMotionEstimateTest : public ::testing::Test {
public:
virtual void SetUp() {
m_pRefData = NULL;
m_pSrcBlock = NULL;
m_pMvdCostTable = NULL;
m_iWidth = 64;//size of search window
m_iHeight = 64;//size of search window
m_iMaxSearchBlock = 8;
m_uiMvdTableSize = (1 + (648 << 1));
m_pMa = new CMemoryAlign(16);
ASSERT_TRUE( NULL != m_pMa );
m_pRefData = (uint8_t*)m_pMa->WelsMalloc (m_iWidth*m_iHeight*sizeof (uint8_t), "m_pRefData");
ASSERT_TRUE( NULL != m_pRefData );
m_pSrcBlock = (uint8_t*)m_pMa->WelsMalloc (m_iMaxSearchBlock*m_iMaxSearchBlock*sizeof (uint8_t), "m_pSrcBlock");
ASSERT_TRUE( NULL != m_pSrcBlock );
m_pMvdCostTable = (uint16_t*)m_pMa->WelsMalloc (52*m_uiMvdTableSize*sizeof (uint16_t), "m_pMvdCostTable");
ASSERT_TRUE( NULL != m_pMvdCostTable );
m_pFeatureSearchPreparation = (SFeatureSearchPreparation*)m_pMa->WelsMalloc (sizeof (SFeatureSearchPreparation), "m_pFeatureSearchPreparation");
ASSERT_TRUE( NULL != m_pFeatureSearchPreparation );
m_pScreenBlockFeatureStorage = (SScreenBlockFeatureStorage*)m_pMa->WelsMalloc (sizeof (SScreenBlockFeatureStorage), "m_pScreenBlockFeatureStorage");
ASSERT_TRUE( NULL != m_pScreenBlockFeatureStorage );
}
virtual void TearDown() {
if (m_pMa) {
if (m_pRefData) {
m_pMa->WelsFree(m_pRefData, "m_pRefData");
m_pRefData = NULL;
}
if (m_pSrcBlock) {
m_pMa->WelsFree(m_pSrcBlock, "m_pSrcBlock");
m_pSrcBlock = NULL;
}
if (m_pMvdCostTable) {
m_pMa->WelsFree(m_pMvdCostTable, "m_pMvdCostTable");
m_pMvdCostTable = NULL;
}
if (m_pFeatureSearchPreparation) {
ReleaseFeatureSearchPreparation( m_pMa, m_pFeatureSearchPreparation->pFeatureOfBlock);
m_pMa->WelsFree(m_pFeatureSearchPreparation, "m_pFeatureSearchPreparation");
m_pFeatureSearchPreparation = NULL;
}
if (m_pScreenBlockFeatureStorage) {
ReleaseScreenBlockFeatureStorage( m_pMa, m_pScreenBlockFeatureStorage );
m_pMa->WelsFree(m_pScreenBlockFeatureStorage, "m_pScreenBlockFeatureStorage");
m_pScreenBlockFeatureStorage = NULL;
}
delete m_pMa;
m_pMa = NULL;
}
}
void InitRefPicForMeTest(SPicture* pRefPic) {
pRefPic->pData[0] = m_pRefData;
pRefPic->iLineSize[0] = m_iWidth;
pRefPic->iFrameAverageQp = rand()%52;
pRefPic->iWidthInPixel = m_iWidth;
pRefPic->iHeightInPixel = m_iHeight;
}
public:
CMemoryAlign* m_pMa;
SFeatureSearchPreparation* m_pFeatureSearchPreparation;
SScreenBlockFeatureStorage* m_pScreenBlockFeatureStorage;
uint8_t *m_pRefData;
uint8_t *m_pSrcBlock;
uint16_t *m_pMvdCostTable;
uint32_t m_uiMvdTableSize;
int32_t m_iWidth;
int32_t m_iHeight;
int32_t m_iMaxSearchBlock;
};
TEST_F(FeatureMotionEstimateTest, TestFeatureSearch) {
const int32_t kiMaxBlock16Sad = 72000;//a rough number
SWelsFuncPtrList sFuncList;
WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
WelsInitMeFunc( &sFuncList, 0, true );
SWelsME sMe;
srand((uint32_t)time(NULL));
const uint8_t kuiQp = rand()%52;
InitMe(kuiQp, 648, m_uiMvdTableSize, m_pMvdCostTable, &sMe);
sMe.iCurMeBlockPixX = (m_iWidth/2);
sMe.iCurMeBlockPixY = (m_iHeight/2);
uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
SPicture sRef;
InitRefPicForMeTest(&sRef);
SSlice sSlice;
const int32_t kiSupposedPaddingLength=16;
SetMvWithinIntegerMvRange( m_iWidth/16-kiSupposedPaddingLength, m_iHeight/16-kiSupposedPaddingLength,
m_iWidth/2/16, m_iHeight/2/16, 508,
&(sSlice.sMvStartMin), &(sSlice.sMvStartMax));
int32_t iReturn;
const int32_t kiNeedFeatureStorage = ME_DIA_CROSS_FME;
iReturn = RequestFeatureSearchPreparation( m_pMa, m_iWidth, m_iHeight, kiNeedFeatureStorage,
m_pFeatureSearchPreparation);
ASSERT_TRUE( ENC_RETURN_SUCCESS==iReturn );
iReturn = RequestScreenBlockFeatureStorage( m_pMa, m_iWidth, m_iHeight, kiNeedFeatureStorage,
m_pScreenBlockFeatureStorage);
ASSERT_TRUE( ENC_RETURN_SUCCESS==iReturn );
SMVUnitXY sTargetMv;
for (int i=sSlice.sMvStartMin.iMvX; i<=sSlice.sMvStartMax.iMvX;i++) {
for (int j=sSlice.sMvStartMin.iMvY; j<=sSlice.sMvStartMax.iMvY;j++) {
if ( i==0 || j==0) continue;//exclude x=0 or y=0 since that will be skipped by FME
bool bDataGeneratorSucceed = false;
bool bFoundMatch = false;
if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
continue;
bDataGeneratorSucceed = true;
sTargetMv.iMvX = i;
sTargetMv.iMvY = j;
CopyTargetBlock( m_pSrcBlock, m_iMaxSearchBlock, sTargetMv, m_iWidth, pRefPicCenter );
//clean sMe status
sMe.uiBlockSize = BLOCK_8x8;
sMe.pEncMb = m_pSrcBlock;
sMe.pRefMb = pRefPicCenter;
sMe.pColoRefMb = pRefPicCenter;
sMe.sMv.iMvX = sMe.sMv.iMvY = 0;
sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad;
//begin FME process
PerformFMEPreprocess(&sFuncList, &sRef, m_pFeatureSearchPreparation->pFeatureOfBlock,
m_pScreenBlockFeatureStorage);
m_pScreenBlockFeatureStorage->uiSadCostThreshold[BLOCK_8x8] = UINT_MAX;//to avoid early skip
uint32_t uiMaxSearchPoint = INT_MAX;
SFeatureSearchIn sFeatureSearchIn = {0};
SetFeatureSearchIn(&sFuncList, sMe, &sSlice, m_pScreenBlockFeatureStorage,
m_iMaxSearchBlock, m_iWidth,
&sFeatureSearchIn);
MotionEstimateFeatureFullSearch( sFeatureSearchIn, uiMaxSearchPoint, &sMe);
bool bMvMatch = sMe.sMv.iMvX==sTargetMv.iMvX && sMe.sMv.iMvY==sTargetMv.iMvY;
bool bFeatureMatch =
( *(m_pScreenBlockFeatureStorage->pFeatureOfBlockPointer +(m_iHeight/2+sTargetMv.iMvY)*(m_iWidth-8)+(m_iWidth/2+sTargetMv.iMvX))
== *(m_pScreenBlockFeatureStorage->pFeatureOfBlockPointer +(m_iHeight/2+sMe.sMv.iMvY)*(m_iWidth-8)+(m_iWidth/2+sMe.sMv.iMvX)) )
&& ((sMe.pMvdCost[sMe.sMv.iMvY<<2]+sMe.pMvdCost[sMe.sMv.iMvX<<2]) <= (sMe.pMvdCost[sTargetMv.iMvY<<2]+sMe.pMvdCost[sTargetMv.iMvX<<2]));
//the last selection may be affected by MVDcost, that is when smaller Mv will be better
bFoundMatch = bMvMatch || bFeatureMatch;
if (bDataGeneratorSucceed) {
//if DataGenerator never succeed, there is no meaning to check iTryTimes
if (!bFoundMatch) {
printf("TestFeatureSearch Target: %d,%d, Result: %d,%d\n", sTargetMv.iMvX, sTargetMv.iMvY, sMe.sMv.iMvX, sMe.sMv.iMvY);
}
EXPECT_TRUE(bFoundMatch);
}
}
}
}