shithub: openh264

Download patch

ref: c8f2f084035905bddd60291a42fc8d45389c9ad8
parent: e536be8dfa15da9eabbe1ff22a044d469cfadedb
parent: 2fe99d688bea0d38d2a69fd775a6f9b09e1066d4
author: volvet <qizh@cisco.com>
date: Fri Mar 14 13:12:46 EDT 2014

Merge pull request #495 from sijchen/add_me_test11

[Encoder UnitTest] add basic me test

--- a/Makefile
+++ b/Makefile
@@ -78,7 +78,10 @@
     -Igtest/include
 
 CODEC_UNITTEST_INCLUDES += \
-    -Igtest/include
+    -Igtest/include \
+    -Icodec/processing/interface \
+    -Icodec/common \
+    -Icodec/encoder/core/inc
 
 H264DEC_INCLUDES = $(DECODER_INCLUDES) -Icodec/console/dec/inc
 H264DEC_LDFLAGS = -L. $(call LINK_LIB,decoder) $(call LINK_LIB,common)
--- /dev/null
+++ b/test/DataGenerator.cpp
@@ -1,0 +1,65 @@
+#include <string.h>//memset/memcpy
+#include "utils/DataGenerator.h"
+#include "utils/BufferedData.h"
+#include "utils/FileInputStream.h"
+
+using namespace std;
+
+
+bool YUVPixelDataGenerator( uint8_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride )
+{
+#define SRC_FRAME_WIDTH (160)
+#define SRC_FRAME_HEIGHT (96)
+
+  if ( SRC_FRAME_WIDTH-iWidth <= 0 || SRC_FRAME_HEIGHT-iHeight <= 0 ) {
+    return false;
+  }
+
+  const int32_t kiFrameSize = SRC_FRAME_WIDTH*SRC_FRAME_HEIGHT;
+  BufferedData sBuf;
+  sBuf.SetLength(kiFrameSize);
+  if (sBuf.Length() != kiFrameSize) {
+    return false;
+  }
+
+  FileInputStream fileStream;
+  if (!fileStream.Open("res/CiscoVT2people_160x96_6fps.yuv")) {
+    return false;
+  }
+  if (fileStream.read(sBuf.data(), kiFrameSize) == kiFrameSize) {
+    srand((uint32_t)time(NULL));
+    int32_t iStartPosX = rand()%(SRC_FRAME_WIDTH-iWidth);
+    int32_t iStartPosY = rand()%(SRC_FRAME_HEIGHT-iHeight);
+    uint8_t* pSrcPointer = sBuf.data() + iStartPosX + iStartPosY*SRC_FRAME_WIDTH;
+    uint8_t* pLocalPointer = pPointer;
+
+    for (int j=0;j<iHeight;j++) {
+      memcpy(pLocalPointer, pSrcPointer, iWidth*sizeof(uint8_t));
+      pLocalPointer += iStride;
+      pSrcPointer += SRC_FRAME_WIDTH;
+    }
+    return true;
+  }
+  return false;
+}
+
+void RandomPixelDataGenerator( uint8_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride )
+{
+  uint8_t* pLocalPointer = pPointer;
+  for (int32_t j=0;j<iHeight;j++) {
+    for (int32_t i=0;i<iWidth;i++) {
+      pLocalPointer[i] = rand()%256;
+    }
+    pLocalPointer += iStride;
+  }
+}
+
+
+void RandomResidueDataGenerator( uint16_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride )
+{
+}
+
+void RandomCoeffDataGenerator( uint16_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride )
+{
+}
+
--- a/test/EncUT_MemoryAlloc.cpp
+++ b/test/EncUT_MemoryAlloc.cpp
@@ -1,7 +1,5 @@
-#include "../gtest/include/gtest/gtest.h"
-#include <string.h>		// use memset/memcmp
-#include <time.h>
-#include "../codec/encoder/core/inc/memory_align.h"
+#include "gtest/gtest.h"
+#include "memory_align.h"
 
 using namespace WelsSVCEnc;
 
@@ -46,7 +44,7 @@
     const uint32_t kuiExpectedSize	= sizeof( void ** ) + sizeof( int32_t ) + kuiExtraAlignSize + uiSize;
     uint8_t *pUnitTestData = static_cast<uint8_t *>(cTestMa.WelsMalloc(uiSize, strUnitTestTag));
     if ( pUnitTestData != NULL ) {
-      ASSERT_TRUE( (((int64_t)(static_cast<void *>(pUnitTestData))) & kuiExtraAlignSize) == 0 );
+      ASSERT_TRUE( (((uintptr_t)(pUnitTestData)) & kuiExtraAlignSize) == 0 );
       EXPECT_EQ( kuiExpectedSize, cTestMa.WelsGetMemoryUsage() );
       cTestMa.WelsFree( pUnitTestData, strUnitTestTag );
       EXPECT_EQ( 0, cTestMa.WelsGetMemoryUsage() );
--- /dev/null
+++ b/test/EncUT_MotionEstimate.cpp
@@ -1,0 +1,125 @@
+#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"
+
+
+using namespace WelsSVCEnc;
+
+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_pRefPic = 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));
+
+    m_pRefPic = static_cast<uint8_t *>
+    (malloc(m_iWidth*m_iHeight));
+    ASSERT_TRUE( NULL != m_pRefPic );
+    m_pSrcBlock = static_cast<uint8_t *>
+    (malloc(m_iMaxSearchBlock*m_iMaxSearchBlock));
+    ASSERT_TRUE( NULL != m_pSrcBlock );
+    m_pMvdCostTable=new uint16_t[52*m_uiMvdTableSize];
+    ASSERT_TRUE( NULL != m_pMvdCostTable );
+  }
+  virtual void TearDown() {
+    delete [] m_pMvdCostTable;
+    free( m_pRefPic );
+    free( m_pSrcBlock );
+  }
+public:
+  uint8_t *m_pRefPic;
+  uint8_t *m_pSrcBlock;
+  uint32_t m_uiMvdTableSize;
+  uint16_t *m_pMvdCostTable;
+
+  int32_t m_iWidth;
+  int32_t m_iHeight;
+  int32_t m_iMaxSearchBlock;
+};
+
+
+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;
+
+  srand((uint32_t)time(NULL));
+  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_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  bool bDataGeneratorSucceed = false;
+  bool bFoundMatch = false;
+  int32_t i,j,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_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+        continue;
+
+      bDataGeneratorSucceed = true;
+      CopyTargetBlock( m_pSrcBlock, 16, sTargetMv, m_iWidth, pRefPicCenter);
+
+      //clean the sMe status
+      sMe.uiPixel = rand()%5;
+      sMe.pEncMb = m_pSrcBlock;
+      sMe.pRefMb = pRefPicCenter;
+      sMe.sMv.iMvX = sMe.sMv.iMvY = 0;
+      sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad;
+      WelsMotionEstimateIterativeSearch (&sFuncList, &sMe, m_iMaxSearchBlock,
+        m_iWidth, pRefPicCenter);
+
+      //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*4))||(sMe.sMv.iMvX==0)) && ((sMe.sMv.iMvY==(sTargetMv.iMvY*4))||(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
+    }
+  }
+}
--- a/test/targets.mk
+++ b/test/targets.mk
@@ -3,11 +3,13 @@
 	$(CODEC_UNITTEST_SRCDIR)/BaseDecoderTest.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/BaseEncoderTest.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/cpp_interface_test.cpp\
+	$(CODEC_UNITTEST_SRCDIR)/DataGenerator.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/decode_encode_test.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/decoder_test.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/encoder_test.cpp\
-	$(CODEC_UNITTEST_SRCDIR)/simple_test.cpp\
 	$(CODEC_UNITTEST_SRCDIR)/EncUT_MemoryAlloc.cpp\
+	$(CODEC_UNITTEST_SRCDIR)/EncUT_MotionEstimate.cpp\
+	$(CODEC_UNITTEST_SRCDIR)/simple_test.cpp\
 
 CODEC_UNITTEST_OBJS += $(CODEC_UNITTEST_CPP_SRCS:.cpp=.o)
 
--- /dev/null
+++ b/test/utils/DataGenerator.h
@@ -1,0 +1,15 @@
+#ifndef DATA_GENERATOR_H__
+#define DATA_GENERATOR_H__
+
+#include "typedefs.h"
+
+bool YUVPixelDataGenerator( uint8_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride );
+
+void RandomPixelDataGenerator( uint8_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride );
+
+void RandomResidueDataGenerator( uint16_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride );
+
+void RandomCoeffDataGenerator( uint16_t* pPointer, int32_t iWidth, int32_t iHeight, int32_t iStride );
+
+
+#endif//DATA_GENERATOR_H__