ref: d1e25d748fd5f7d9c2c5dba93c0ba3d7d1cb73ad
dir: /test/encoder/EncUT_MotionEstimate.cpp/
#include <stdlib.h> #include "gtest/gtest.h" #include "utils/DataGenerator.h" #include "md.h" #include "sample.h" #include "svc_motion_estimate.h" #include "wels_func_ptr_def.h" #include "cpu.h" using namespace WelsEnc; void CopyTargetBlock (uint8_t* pSrcBlock, const int32_t kiBlockSize, SMVUnitXY sTargetMv, const int32_t kiRefPicStride, uint8_t* pRefPic) { uint8_t* pTargetPos = pRefPic + sTargetMv.iMvY * kiRefPicStride + sTargetMv.iMvX; uint8_t* pSourcePos = pSrcBlock; for (int i = 0; i < kiBlockSize; i++) { memcpy (pSourcePos, pTargetPos, kiBlockSize * sizeof (uint8_t)); pTargetPos += kiRefPicStride; pSourcePos += kiBlockSize; } } void InitMe (const uint8_t kuiQp, const uint32_t kuiMvdTableMiddle, const uint32_t kuiMvdTableStride, uint16_t* pMvdCostTable, SWelsME* pMe) { MvdCostInit (pMvdCostTable, kuiMvdTableStride); pMe->pMvdCost = &pMvdCostTable[kuiQp * kuiMvdTableStride + kuiMvdTableMiddle]; pMe->sMvp.iMvX = pMe->sMvp.iMvY = 0; pMe->sMvBase.iMvX = pMe->sMvBase.iMvY = 0; pMe->sMv.iMvX = pMe->sMv.iMvY = 0; } class MotionEstimateTest : 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 = 16; m_uiMvdTableSize = (1 + (648 << 1)); pMa = new CMemoryAlign (0); m_pRefData = static_cast<uint8_t*> (pMa->WelsMalloc (m_iWidth * m_iHeight, "RefPic")); ASSERT_TRUE (NULL != m_pRefData); m_pSrcBlock = static_cast<uint8_t*> (pMa->WelsMalloc (m_iMaxSearchBlock * m_iMaxSearchBlock, "SrcBlock")); ASSERT_TRUE (NULL != m_pSrcBlock); m_pMvdCostTable = new uint16_t[52 * m_uiMvdTableSize]; ASSERT_TRUE (NULL != m_pMvdCostTable); } void DoLineTest (PLineFullSearchFunc func, bool horizontal); virtual void TearDown() { delete [] m_pMvdCostTable; pMa->WelsFree (m_pRefData, "RefPic"); pMa->WelsFree (m_pSrcBlock, "SrcBlock"); delete pMa; } public: uint8_t* m_pRefData; uint8_t* m_pSrcBlock; uint32_t m_uiMvdTableSize; uint16_t* m_pMvdCostTable; int32_t m_iWidth; int32_t m_iHeight; int32_t m_iMaxSearchBlock; CMemoryAlign* pMa; }; TEST_F (MotionEstimateTest, TestDiamondSearch) { #define TEST_POS (5) const int32_t kiPositionToCheck[TEST_POS][2] = {{0, 0}, {0, 1}, {1, 0}, {0, -1}, { -1, 0}}; const int32_t kiMaxBlock16Sad = 72000;//a rough number SWelsFuncPtrList sFuncList; SWelsME sMe; SSlice sSlice; memset (&sSlice, 0, sizeof (sSlice)); const uint8_t kuiQp = rand() % 52; InitMe (kuiQp, 648, m_uiMvdTableSize, m_pMvdCostTable, &sMe); SMVUnitXY sTargetMv; WelsInitSampleSadFunc (&sFuncList, 0); //test c functions uint8_t* pRefPicCenter = m_pRefData + (m_iHeight / 2) * m_iWidth + (m_iWidth / 2); bool bDataGeneratorSucceed = false; bool bFoundMatch = false; int32_t i, iTryTimes; for (i = 0; i < TEST_POS; i++) { sTargetMv.iMvX = kiPositionToCheck[i][0]; sTargetMv.iMvY = kiPositionToCheck[i][1]; iTryTimes = 100; bDataGeneratorSucceed = false; bFoundMatch = false; while (!bFoundMatch && (iTryTimes--) > 0) { if (!YUVPixelDataGenerator (m_pRefData, m_iWidth, m_iHeight, m_iWidth)) continue; bDataGeneratorSucceed = true; CopyTargetBlock (m_pSrcBlock, 16, sTargetMv, m_iWidth, pRefPicCenter); //clean the sMe status sMe.uiBlockSize = rand() % 5; sMe.pEncMb = m_pSrcBlock; sMe.pRefMb = pRefPicCenter; sMe.sMv.iMvX = sMe.sMv.iMvY = 0; sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad; WelsDiamondSearch (&sFuncList, &sMe, &sSlice, m_iMaxSearchBlock, m_iWidth); //the last selection may be affected by MVDcost, that is when (0,0) will be better //when comparing (1,1) and (1,0), due to the difference between MVD cost, it is possible that (1,0) is selected while the best match is (1,1) bFoundMatch = ((sMe.sMv.iMvX == (sTargetMv.iMvX)) || (sMe.sMv.iMvX == 0)) && ((sMe.sMv.iMvY == (sTargetMv.iMvY)) || (sMe.sMv.iMvY == 0)); } if (bDataGeneratorSucceed) { //if DataGenerator never succeed, there is no meaning to check iTryTimes ASSERT_TRUE (iTryTimes > 0); //it is possible that ref at differnt position is identical, but that should be under a low probability } } } class MotionEstimateRangeTest : public ::testing::Test { public: virtual void SetUp() { m_iWidth = 320; m_iHeight = 240; m_iWidthExt = m_iWidth + 2 * PADDING_LENGTH; m_iHeightExt = m_iHeight + 2 * PADDING_LENGTH; m_iMbWidth = m_iWidth >> 4; m_iMbHeight = m_iHeight >> 4; m_iUsageType = 0; m_iNumDependencyLayers = 1; m_iMvRange = m_iUsageType ? EXPANDED_MV_RANGE : CAMERA_STARTMV_RANGE; m_iMvdRange = (m_iUsageType ? EXPANDED_MVD_RANGE : ((m_iNumDependencyLayers == 1) ? CAMERA_MVD_RANGE : CAMERA_HIGHLAYER_MVD_RANGE)); m_uiMvdInterTableSize = (m_iMvdRange << 2); //intepel*4=qpel m_uiMvdInterTableStride = 1 + (m_uiMvdInterTableSize << 1);//qpel_mv_range*2=(+/-); m_uiMvdCacheAlignedSize = m_uiMvdInterTableStride * sizeof (uint16_t); m_pMa = new CMemoryAlign (16); ASSERT_TRUE (NULL != m_pMa); m_pMvdCostTable = (uint16_t*)m_pMa->WelsMallocz (52 * m_uiMvdCacheAlignedSize, "pMvdCostTable"); ASSERT_TRUE (NULL != m_pMvdCostTable); m_pRefStart = (uint8_t*)m_pMa->WelsMallocz (m_iWidthExt * m_iHeightExt, "reference frame "); ASSERT_TRUE (NULL != m_pRefStart); m_pSrc = (uint8_t*)m_pMa->WelsMallocz (m_iWidth * m_iHeight, "source frame"); ASSERT_TRUE (NULL != m_pSrc); } virtual void TearDown() { if (!m_pMa) return; if (m_pRefStart) { m_pMa->WelsFree (m_pRefStart, "reference frame "); m_pRefStart = NULL; } if (m_pSrc) { m_pMa->WelsFree (m_pSrc, "source frame "); m_pSrc = NULL; } if (m_pMvdCostTable) { m_pMa->WelsFree (m_pMvdCostTable, "pMvdCostTable"); m_pMvdCostTable = NULL; } if (m_pMa) { delete m_pMa; m_pMa = NULL; } } public: uint8_t* m_pRefStart; uint8_t* m_pSrc; uint16_t* m_pMvdCostTable; int32_t m_iWidth; int32_t m_iHeight; int32_t m_iWidthExt; int32_t m_iHeightExt; int32_t m_iMbWidth; int32_t m_iMbHeight; CMemoryAlign* m_pMa; int32_t m_iMvRange; int32_t m_iMvdRange; uint32_t m_uiMvdInterTableSize; uint32_t m_uiMvdInterTableStride; uint32_t m_uiMvdCacheAlignedSize; int32_t m_iUsageType; int32_t m_iNumDependencyLayers; }; TEST_F (MotionEstimateRangeTest, TestDiamondSearch) { const int32_t kiMaxBlock16Sad = 72000;//a rough number uint8_t* pRef = m_pRefStart + PADDING_LENGTH * m_iWidthExt + PADDING_LENGTH; SWelsFuncPtrList sFuncList; SWelsME sMe; SSlice sSlice; const uint8_t kuiQp = rand() % 52; InitMe (kuiQp, m_uiMvdInterTableSize, m_uiMvdInterTableStride, m_pMvdCostTable, &sMe); WelsInitSampleSadFunc (&sFuncList, 0); //test c functions memset (&sSlice, 0, sizeof (sSlice)); memset (m_pSrc, 128, m_iWidth * m_iHeight); memset (m_pRefStart, 0, m_iWidthExt * m_iHeightExt); sMe.uiBlockSize = BLOCK_16x16; // sMe.sMvp.iMvX = rand() % m_iMvRange; sMe.sMvp.iMvY = rand() % m_iMvRange; for (int h = 0; h < m_iHeight; h++) memset (pRef + h * m_iWidthExt, h, m_iWidthExt); sMe.pEncMb = m_pSrc; sMe.sMv.iMvX = sMe.sMvp.iMvX; sMe.sMv.iMvY = sMe.sMvp.iMvY; sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad; SetMvWithinIntegerMvRange (m_iMbWidth, m_iMbHeight, 0, 0, m_iMvRange, & (sSlice.sMvStartMin), & (sSlice.sMvStartMax)); sMe.pRefMb = pRef + sMe.sMvp.iMvY * m_iWidthExt; WelsDiamondSearch (&sFuncList, &sMe, &sSlice, m_iWidth, m_iWidthExt); if ((WELS_ABS (sMe.sMv.iMvX) > m_iMvRange)) printf ("mvx = %d\n", sMe.sMv.iMvX); ASSERT_TRUE (! (WELS_ABS (sMe.sMv.iMvX) > m_iMvRange)); if ((WELS_ABS (sMe.sMv.iMvY) > m_iMvRange)) printf ("mvy = %d\n", sMe.sMv.iMvY); ASSERT_TRUE (! (WELS_ABS (sMe.sMv.iMvY) > m_iMvRange)); } TEST_F (MotionEstimateRangeTest, TestWelsMotionCrossSearch) { SWelsFuncPtrList sFuncList; SWelsME sMe; SSlice sSlice; bool bUsageType = true; uint8_t* pRef = m_pRefStart + PADDING_LENGTH * m_iWidthExt + PADDING_LENGTH; const int32_t kiMaxBlock16Sad = 72000;//a rough number memset (&sSlice, 0, sizeof (sSlice)); memset (&sMe, 0, sizeof (sMe)); WelsInitSampleSadFunc (&sFuncList, 0); //test c functions WelsInitMeFunc (&sFuncList, 0, bUsageType); RandomPixelDataGenerator (m_pSrc, m_iWidth, m_iHeight, m_iWidth); RandomPixelDataGenerator (m_pRefStart, m_iWidthExt, m_iHeightExt, m_iWidthExt); sMe.uiBlockSize = BLOCK_16x16; // for (int32_t iMby = 0; iMby < m_iMbHeight; iMby++) { for (int32_t iMbx = 0; iMbx < m_iMbWidth; iMbx++) { const uint8_t kuiQp = rand() % 52; InitMe (kuiQp, m_uiMvdInterTableSize, m_uiMvdInterTableStride, m_pMvdCostTable, &sMe); SetMvWithinIntegerMvRange (m_iMbWidth, m_iMbHeight, iMbx , iMby, m_iMvRange, & (sSlice.sMvStartMin), & (sSlice.sMvStartMax)); sMe.sMvp.iMvX = rand() % m_iMvRange; sMe.sMvp.iMvY = rand() % m_iMvRange; sMe.iCurMeBlockPixX = (iMbx << 4); sMe.iCurMeBlockPixY = (iMby << 4); sMe.pRefMb = pRef + sMe.iCurMeBlockPixX + sMe.iCurMeBlockPixY * m_iWidthExt; sMe.pEncMb = m_pSrc + sMe.iCurMeBlockPixX + sMe.iCurMeBlockPixY * m_iWidth; sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad; sMe.pColoRefMb = sMe.pRefMb; WelsMotionCrossSearch (&sFuncList, &sMe, &sSlice, m_iWidth, m_iWidthExt); if ((WELS_ABS (sMe.sMv.iMvX) > m_iMvRange)) printf ("mvx = %d\n", sMe.sMv.iMvX); ASSERT_TRUE (! (WELS_ABS (sMe.sMv.iMvX) > m_iMvRange)); if ((WELS_ABS (sMe.sMv.iMvY) > m_iMvRange)) printf ("mvy = %d\n", sMe.sMv.iMvY); ASSERT_TRUE (! (WELS_ABS (sMe.sMv.iMvY) > m_iMvRange)); } } } void MotionEstimateTest::DoLineTest (PLineFullSearchFunc func, bool vertical) { const int32_t kiMaxBlock16Sad = 72000;//a rough number SWelsFuncPtrList sFuncList; SWelsME sMe; const uint8_t kuiQp = rand() % 52; InitMe (kuiQp, 648, m_uiMvdTableSize, m_pMvdCostTable, &sMe); SMVUnitXY sTargetMv; WelsInitSampleSadFunc (&sFuncList, 0); //test c functions WelsInitMeFunc (&sFuncList, WelsCPUFeatureDetect (NULL), 1); uint8_t* pRefPicCenter = m_pRefData + (m_iHeight / 2) * m_iWidth + (m_iWidth / 2); sMe.iCurMeBlockPixX = (m_iWidth / 2); sMe.iCurMeBlockPixY = (m_iHeight / 2); bool bDataGeneratorSucceed = false; bool bFoundMatch = false; int32_t iTryTimes = 100; if (vertical) { sTargetMv.iMvX = 0; sTargetMv.iMvY = -sMe.iCurMeBlockPixY + INTPEL_NEEDED_MARGIN + rand() % (m_iHeight - 16 - 2 * INTPEL_NEEDED_MARGIN); } else { sTargetMv.iMvX = -sMe.iCurMeBlockPixX + INTPEL_NEEDED_MARGIN + rand() % (m_iWidth - 16 - 2 * INTPEL_NEEDED_MARGIN); sTargetMv.iMvY = 0; } bDataGeneratorSucceed = false; bFoundMatch = false; while (!bFoundMatch && (iTryTimes--) > 0) { if (!YUVPixelDataGenerator (m_pRefData, m_iWidth, m_iHeight, m_iWidth)) continue; bDataGeneratorSucceed = true; CopyTargetBlock (m_pSrcBlock, 16, sTargetMv, m_iWidth, pRefPicCenter); //clean the sMe status sMe.uiBlockSize = rand() % 5; sMe.pEncMb = m_pSrcBlock; sMe.pRefMb = pRefPicCenter; sMe.pColoRefMb = pRefPicCenter; sMe.sMv.iMvX = sMe.sMv.iMvY = 0; sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad; const int32_t iCurMeBlockPixX = sMe.iCurMeBlockPixX; const int32_t iCurMeBlockQpelPixX = ((iCurMeBlockPixX) << 2); const int32_t iCurMeBlockPixY = sMe.iCurMeBlockPixY; const int32_t iCurMeBlockQpelPixY = ((iCurMeBlockPixY) << 2); uint16_t* pMvdCostX = sMe.pMvdCost - iCurMeBlockQpelPixX - sMe.sMvp.iMvX; //do the offset here uint16_t* pMvdCostY = sMe.pMvdCost - iCurMeBlockQpelPixY - sMe.sMvp.iMvY; uint16_t* pMvdCost = vertical ? pMvdCostY : pMvdCostX; int iSize = vertical ? m_iHeight : m_iWidth; //the last selection may be affected by MVDcost, that is when smaller MvY will be better if (vertical) { func (&sFuncList, &sMe, pMvdCost, m_iMaxSearchBlock, m_iWidth, INTPEL_NEEDED_MARGIN - sMe.iCurMeBlockPixY, iSize - INTPEL_NEEDED_MARGIN - 16 - sMe.iCurMeBlockPixY, vertical); bFoundMatch = (sMe.sMv.iMvX == 0 && (sMe.sMv.iMvY == sTargetMv.iMvY || abs (sMe.sMv.iMvY) < abs (sTargetMv.iMvY))); } else { func (&sFuncList, &sMe, pMvdCost, m_iMaxSearchBlock, m_iWidth, INTPEL_NEEDED_MARGIN - sMe.iCurMeBlockPixX, iSize - INTPEL_NEEDED_MARGIN - 16 - sMe.iCurMeBlockPixX, vertical); bFoundMatch = (sMe.sMv.iMvY == 0 && (sMe.sMv.iMvX == sTargetMv.iMvX || abs (sMe.sMv.iMvX) < abs (sTargetMv.iMvX))); } //printf("DoLineTest Target: %d,%d\n", sTargetMv.iMvX, sTargetMv.iMvY); } if (bDataGeneratorSucceed) { //if DataGenerator never succeed, there is no meaning to check iTryTimes ASSERT_TRUE (iTryTimes > 0); //it is possible that ref at differnt position is identical, but that should be under a low probability } } TEST_F (MotionEstimateTest, TestVerticalSearch) { DoLineTest (LineFullSearch_c, true); } TEST_F (MotionEstimateTest, TestHorizontalSearch) { DoLineTest (LineFullSearch_c, false); } #ifdef X86_ASM TEST_F (MotionEstimateTest, TestVerticalSearch_SSE41) { int32_t iTmp = 1; uint32_t uiCPUFlags = WelsCPUFeatureDetect (&iTmp); if ((uiCPUFlags & WELS_CPU_SSE41) == 0) return ; DoLineTest (VerticalFullSearchUsingSSE41, true); } TEST_F (MotionEstimateTest, TestHorizontalSearch_SSE41) { int32_t iTmp = 1; uint32_t uiCPUFlags = WelsCPUFeatureDetect (&iTmp); if ((uiCPUFlags & WELS_CPU_SSE41) == 0) return ; DoLineTest (HorizontalFullSearchUsingSSE41, false); } #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; 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}; if (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); } } } }