shithub: openh264

Download patch

ref: 5c60e8f868eacd4747239dca5518e7761f2e570f
parent: 94cabe10d54021c8269d51ba3fa5d88c4a0607fe
author: Licai Guo <guolicai@gmail.com>
date: Fri Mar 28 06:22:11 EDT 2014

Add ASM related functions for ME cross search

Add asm level functions

Add asm code for ME

Modify format

Add unit test for asm code.

Modify function name and format.

Remove unuse comment

Modify targets file

Add Macro protect for SSE41 funtion test

Modify according to review request.

--- a/codec/build/iOS/enc/welsenc/welsenc.xcodeproj/project.pbxproj
+++ b/codec/build/iOS/enc/welsenc/welsenc.xcodeproj/project.pbxproj
@@ -81,6 +81,7 @@
 		4C34066918C57D0400DFA14A /* memory_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = memory_neon.S; sourceTree = "<group>"; };
 		4C34066A18C57D0400DFA14A /* pixel_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pixel_neon.S; sourceTree = "<group>"; };
 		4C34066B18C57D0400DFA14A /* reconstruct_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = reconstruct_neon.S; sourceTree = "<group>"; };
+		4CDBFB9D18E5068D0025A767 /* wels_transpose_matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wels_transpose_matrix.h; sourceTree = "<group>"; };
 		4CE4431118B6FFA00017DF25 /* libwelsenc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libwelsenc.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4CE4431418B6FFA00017DF25 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
 		4CE4432118B6FFA00017DF25 /* welsencTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = welsencTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -281,6 +282,7 @@
 		4CE446A918BC605C0017DF25 /* inc */ = {
 			isa = PBXGroup;
 			children = (
+				4CDBFB9D18E5068D0025A767 /* wels_transpose_matrix.h */,
 				4CE446AA18BC605C0017DF25 /* as264_common.h */,
 				4CE446AB18BC605C0017DF25 /* au_set.h */,
 				4CE446AC18BC605C0017DF25 /* bit_stream.h */,
--- a/codec/encoder/core/inc/svc_motion_estimate.h
+++ b/codec/encoder/core/inc/svc_motion_estimate.h
@@ -199,11 +199,24 @@
                         const int32_t kiEncStride, const int32_t kiRefStride,
                         const int32_t kiMinPos, const int32_t kiMaxPos,
                         const bool bVerticalSearch );
+#ifdef X86_ASM
+extern "C"
+{
+uint32_t SampleSad8x8Hor8_sse41 (uint8_t*, int32_t, uint8_t*, int32_t, uint16_t*, int32_t*);
+uint32_t SampleSad16x16Hor8_sse41 (uint8_t*, int32_t, uint8_t*, int32_t, uint16_t*, int32_t*);
+}
+
 void VerticalFullSearchUsingSSE41( void *pFunc, void *vpMe,
                             uint16_t* pMvdTable, const int32_t kiFixedMvd,
                             const int32_t kiEncStride, const int32_t kiRefStride,
                           const int32_t kiMinPos, const int32_t kiMaxPos,
                           const bool bVerticalSearch );
+void HorizontalFullSearchUsingSSE41( void *pFunc, void *vpMe,
+                                      uint16_t* pMvdTable, const int32_t kiFixedMvd,
+                                      const int32_t kiEncStride, const int32_t kiRefStride,
+                                      const int32_t kiMinPos, const int32_t kiMaxPos,
+                                      const bool bVerticalSearch );
+#endif
 void WelsMotionCrossSearch(SWelsFuncPtrList *pFuncList,  SDqLayer* pCurLayer, SWelsME * pMe, const SSlice* pSlice);
 
 // Feature Search Basics
--- a/codec/encoder/core/inc/wels_const.h
+++ b/codec/encoder/core/inc/wels_const.h
@@ -87,6 +87,7 @@
 #define PARA_SET_TYPE_SUBSETSPS	1
 #define PARA_SET_TYPE_PPS		2
 
+#define MAX_VERTICAL_MV_RANGE   1024  //TODO, for allocate enough memory for transpose
 #define MAX_FRAME_RATE			30	// maximal frame rate to support
 #define MIN_FRAME_RATE			1	// minimal frame rate need support
 
--- a/codec/encoder/core/inc/wels_func_ptr_def.h
+++ b/codec/encoder/core/inc/wels_func_ptr_def.h
@@ -134,6 +134,7 @@
 typedef int32_t (*PIntraPred8x8Combined3Func) (uint8_t*, int32_t, uint8_t*, int32_t, int32_t*, int32_t, uint8_t*,
     uint8_t*, uint8_t*);
 
+typedef uint32_t (*PSampleSadHor8Func)( uint8_t*, int32_t, uint8_t*, int32_t, uint16_t*, int32_t* );
 typedef void (*PMotionSearchFunc) (SWelsFuncPtrList* pFuncList, void* pCurDqLayer, void* pMe,
                                    void* pSlice);
 typedef void (*PSearchMethodFunc) (SWelsFuncPtrList* pFuncList, void* pMe, void* pSlice, const int32_t kiEncStride, const int32_t kiRefStride);
@@ -202,14 +203,16 @@
   PGetIntraPredFunc     pfGetLumaI4x4Pred[I4_PRED_A];
   PGetIntraPredFunc     pfGetChromaPred[C_PRED_A];
 
+  PSampleSadHor8Func	pfSampleSadHor8[2];	// 0: for 16x16 square; 1: for 8x8 square
   PMotionSearchFunc
   pfMotionSearch[BLOCK_STATIC_IDC_ALL]; //svc_encode_slice.c svc_mode_decision.c svc_enhance_layer_md.c svc_base_layer_md.c
   PSearchMethodFunc pfSearchMethod[BLOCK_SIZE_ALL];
   PCalculateSatdFunc pfCalculateSatd;
   PCheckDirectionalMv pfCheckDirectionalMv;
-  PLineFullSearchFunc pfLineFullSearch;
   PCalculateBlockFeatureOfFrame pfCalculateBlockFeatureOfFrame[2];//0 - for 8x8, 1 for 16x16
   PCalculateSingleBlockFeature pfCalculateSingleBlockFeature[2];//0 - for 8x8, 1 for 16x16
+  PLineFullSearchFunc pfVerticalFullSearch;
+  PLineFullSearchFunc pfHorizontalFullSearch;
 
   PCopyFunc      pfCopy16x16Aligned;    //svc_encode_slice.c svc_mode_decision.c svc_base_layer_md.c
   PCopyFunc      pfCopy16x16NotAligned;  //md.c
--- /dev/null
+++ b/codec/encoder/core/inc/wels_transpose_matrix.h
@@ -1,0 +1,54 @@
+/*!
+ * \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 WELS_RUBY_ENCODER_TRANSPOSE_MATRIX_H__
+#define WELS_RUBY_ENCODER_TRANSPOSE_MATRIX_H__
+
+#include "typedefs.h"
+
+namespace WelsSVCEnc {
+
+#ifdef X86_ASM
+extern "C"
+{
+void TransposeMatrixBlocksx16_sse2( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride, const int32_t kiBlocksNum );
+void TransposeMatrixBlock16x16_sse2( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride );
+void TransposeMatrixBlocksx8_mmx( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride, const int32_t kiBlocksNum );
+void TransposeMatrixBlock8x8_mmx( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride );
+}
+#endif
+
+typedef void (*PTransposeMatrixBlockFunc)( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride );
+typedef void (*PTransposeMatrixBlocksFunc)( void *pDst, const int32_t kiDstStride, void *pSrc, const int32_t kiSrcStride, const int32_t kiBlocksNum );
+
+}// end of namespace declaration
+
+#endif//WELS_RUBY_ENCODER_TRANSPOSE_MATRIX_H__
--- a/codec/encoder/core/src/svc_motion_estimate.cpp
+++ b/codec/encoder/core/src/svc_motion_estimate.cpp
@@ -41,6 +41,7 @@
 #include "cpu_core.h"
 #include "ls_defines.h"
 #include "svc_motion_estimate.h"
+#include "wels_transpose_matrix.h"
 
 namespace WelsSVCEnc {
 
@@ -65,8 +66,14 @@
     pFuncList->pfCheckDirectionalMv = CheckDirectionalMv;
 
     //for cross serarch
-    pFuncList->pfLineFullSearch = LineFullSearch_c;
+    pFuncList->pfVerticalFullSearch = LineFullSearch_c;
+    pFuncList->pfHorizontalFullSearch = LineFullSearch_c;
+#if defined (X86_ASM)
     if ( uiCpuFlag & WELS_CPU_SSE41 ) {
+      pFuncList->pfSampleSadHor8[0] = SampleSad8x8Hor8_sse41;
+      pFuncList->pfSampleSadHor8[1] = SampleSad16x16Hor8_sse41;
+      pFuncList->pfVerticalFullSearch = VerticalFullSearchUsingSSE41;
+      pFuncList->pfHorizontalFullSearch = HorizontalFullSearchUsingSSE41;
     }
 
     //for feature search
@@ -75,6 +82,7 @@
     //TODO: it is possible to differentiate width that is times of 8, so as to accelerate the speed when width is times of 8?
     pFuncList->pfCalculateSingleBlockFeature[0] = SumOf8x8SingleBlock_c;
     pFuncList->pfCalculateSingleBlockFeature[1] = SumOf16x16SingleBlock_c;
+#endif
   }
 }
 
@@ -302,6 +310,17 @@
 /////////////////////////
 // Cross Search Basics
 /////////////////////////
+#if defined (X86_ASM)
+void CalcMvdCostx8_c( uint16_t *pMvdCost, const int32_t kiStartMv, uint16_t* pMvdTable, const uint16_t kiFixedCost )
+{
+  uint16_t *pBaseCost		= pMvdCost;
+  const int32_t kiOffset	= (kiStartMv<<2);
+  uint16_t *pMvd		= pMvdTable+kiOffset;
+  for (int32_t i = 0; i < 8; ++ i) {
+    pBaseCost[i] = ((*pMvd) + kiFixedCost);
+    pMvd += 4;
+  }
+}
 void VerticalFullSearchUsingSSE41( void *pFunc, void *vpMe,
                             uint16_t* pMvdTable, const int32_t kiFixedMvd,
                             const int32_t kiEncStride, const int32_t kiRefStride,
@@ -308,12 +327,130 @@
                           const int32_t kiMinPos, const int32_t kiMaxPos,
                           const bool bVerticalSearch ) {
   SWelsFuncPtrList *pFuncList      = static_cast<SWelsFuncPtrList *>(pFunc);
-  SWelsME *pMe                            = static_cast<SWelsME *>(vpMe);
+  SWelsME *pMe				                    = static_cast<SWelsME *>(vpMe);
+  uint8_t*  kpEncMb	= pMe->pEncMb;
+  const int32_t kiCurMeBlockPix	= pMe->iCurMeBlockPixY;
+  uint8_t* pRef			      = &pMe->pColoRefMb[(kiMinPos - kiCurMeBlockPix)*kiRefStride];
+  const int32_t kIsBlock16x16	= pMe->uiBlockSize == BLOCK_16x16;
+  const int32_t kiEdgeBlocks	= kIsBlock16x16 ? 16 : 8;
+  PSampleSadHor8Func pSampleSadHor8 = pFuncList->pfSampleSadHor8[kIsBlock16x16];
+  PSampleSadSatdCostFunc pSad = pFuncList->sSampleDealingFuncs.pfSampleSad[pMe->uiBlockSize];
+  PTransposeMatrixBlockFunc	TransposeMatrixBlock = kIsBlock16x16 ? TransposeMatrixBlock16x16_sse2 : TransposeMatrixBlock8x8_mmx;
+  PTransposeMatrixBlocksFunc	TransposeMatrixBlocks= kIsBlock16x16 ? TransposeMatrixBlocksx16_sse2 : TransposeMatrixBlocksx8_mmx;
+
+  const int32_t kiDiff			= kiMaxPos - kiMinPos;
+  const int32_t kiRowNum		= WELS_ALIGN((kiDiff - kiEdgeBlocks + 1), kiEdgeBlocks);
+  const int32_t kiBlocksNum		= kIsBlock16x16 ? (kiRowNum>>4) : (kiRowNum>>3);
+  int32_t iCountLoop8		= (kiRowNum-kiEdgeBlocks) >> 3;
+  const int32_t kiRemainingVectors		= kiDiff - (iCountLoop8<<3);
+  const int32_t kiMatrixStride		= MAX_VERTICAL_MV_RANGE;
+  ENFORCE_STACK_ALIGN_2D( uint8_t, uiMatrixRef, 16, kiMatrixStride, 16 );	// transpose matrix result for ref
+  ENFORCE_STACK_ALIGN_2D( uint8_t, uiMatrixEnc, 16, 16, 16 );				// transpose matrix result for enc
+  assert(kiRowNum <= kiMatrixStride);	// make sure effective memory
+
+  TransposeMatrixBlock( &uiMatrixEnc[0][0], 16, kpEncMb, kiEncStride );
+  TransposeMatrixBlocks( &uiMatrixRef[0][0], kiMatrixStride, pRef, kiRefStride, kiBlocksNum );
+  ENFORCE_STACK_ALIGN_1D( uint16_t, uiBaseCost, 8, 16 );
+  int32_t iTargetPos			= kiMinPos;
+  int16_t iBestPos				= pMe->sMv.iMvX;
+  uint32_t uiBestCost			= pMe->uiSadCost;
+  uint32_t uiCostMin;
+  int32_t iIndexMinPos;
+  kpEncMb	= &uiMatrixEnc[0][0];
+  pRef	= &uiMatrixRef[0][0];
+
+  while(iCountLoop8 > 0) {
+    CalcMvdCostx8_c(uiBaseCost, iTargetPos, pMvdTable, kiFixedMvd);
+    uiCostMin = pSampleSadHor8( kpEncMb, 16, pRef, kiMatrixStride, uiBaseCost, &iIndexMinPos );
+    if (uiCostMin < uiBestCost) {
+      uiBestCost	= uiCostMin;
+      iBestPos		= iTargetPos+iIndexMinPos;
+    }
+    iTargetPos	+= 8;
+    pRef += 8;
+    -- iCountLoop8;
+  }
+  if (kiRemainingVectors > 0) {
+    kpEncMb	= pMe->pEncMb;
+    pRef	= &pMe->pColoRefMb[(iTargetPos - kiCurMeBlockPix)*kiRefStride];
+    while (iTargetPos < kiMaxPos) {
+      const uint16_t pMvdCost	= pMvdTable[iTargetPos<<2];
+      uint32_t uiSadCost	= pSad( kpEncMb, kiEncStride, pRef, kiRefStride ) + (kiFixedMvd + pMvdCost);
+      if (uiSadCost < uiBestCost) {
+        uiBestCost	= uiSadCost;
+        iBestPos	= iTargetPos;
+      }
+      pRef += kiRefStride;
+      ++iTargetPos;
+    }
+  }
+  if (uiBestCost < pMe->uiSadCost) {
+    SMVUnitXY sBestMv;
+    sBestMv.iMvX = 0;
+    sBestMv.iMvY = iBestPos - kiCurMeBlockPix;
+    UpdateMeResults( sBestMv, uiBestCost, &pMe->pColoRefMb[sBestMv.iMvY*kiRefStride], pMe );
+  }
 }
-void LineFullSearch_c(  void *pFunc, void *vpMe,
-                          uint16_t* pMvdTable, const int32_t kiFixedMvd,
-                          const int32_t kiEncStride, const int32_t kiRefStride,
-                          const int32_t kiMinPos, const int32_t kiMaxPos,
+
+void HorizontalFullSearchUsingSSE41( void *pFunc, void *vpMe,
+                                      uint16_t* pMvdTable, const int32_t kiFixedMvd,
+                                      const int32_t kiEncStride, const int32_t kiRefStride,
+                                      const int32_t kiMinPos, const int32_t kiMaxPos,
+                                      const bool bVerticalSearch )
+{
+  SWelsFuncPtrList *pFuncList      = static_cast<SWelsFuncPtrList *>(pFunc);
+  SWelsME *pMe				                    = static_cast<SWelsME *>(vpMe);
+  uint8_t *kpEncMb	= pMe->pEncMb;
+  const int32_t kiCurMeBlockPix	= pMe->iCurMeBlockPixX;
+  uint8_t *pRef			      = &pMe->pColoRefMb[kiMinPos - kiCurMeBlockPix];
+  const int32_t kIsBlock16x16	= pMe->uiBlockSize == BLOCK_16x16;
+  PSampleSadHor8Func pSampleSadHor8 = pFuncList->pfSampleSadHor8[kIsBlock16x16];
+  PSampleSadSatdCostFunc pSad = pFuncList->sSampleDealingFuncs.pfSampleSad[pMe->uiBlockSize];
+  ENFORCE_STACK_ALIGN_1D( uint16_t, uiBaseCost, 8, 16 );
+  const int32_t kiNumVector	= kiMaxPos - kiMinPos;
+  int32_t iCountLoop8	= kiNumVector >> 3;
+  const int32_t kiRemainingLoop8	= kiNumVector & 7;
+  int32_t iTargetPos			= kiMinPos;
+  int16_t iBestPos				= pMe->sMv.iMvX;
+  uint32_t uiBestCost			= pMe->uiSadCost;
+  uint32_t uiCostMin;
+  int32_t iIndexMinPos;
+
+  while(iCountLoop8 > 0) {
+    CalcMvdCostx8_c(uiBaseCost, iTargetPos, pMvdTable, kiFixedMvd);
+    uiCostMin = pSampleSadHor8( kpEncMb, kiEncStride, pRef, kiRefStride, uiBaseCost, &iIndexMinPos );
+    if (uiCostMin < uiBestCost) {
+      uiBestCost	= uiCostMin;
+      iBestPos		= iTargetPos+iIndexMinPos;
+    }
+    iTargetPos	+= 8;
+    pRef += 8;
+    -- iCountLoop8;
+  }
+  if ( kiRemainingLoop8 > 0 ) {
+    while (iTargetPos < kiMaxPos) {
+      const uint16_t pMvdCost	= pMvdTable[iTargetPos<<2];
+      uint32_t uiSadCost	= pSad( kpEncMb, kiEncStride, pRef, kiRefStride ) + (kiFixedMvd + pMvdCost);
+      if (uiSadCost < uiBestCost) {
+        uiBestCost	= uiSadCost;
+        iBestPos	= iTargetPos;
+      }
+      ++pRef;
+      ++iTargetPos;
+    }
+  }
+  if (uiBestCost < pMe->uiSadCost) {
+    SMVUnitXY sBestMv;
+    sBestMv.iMvX = iBestPos - kiCurMeBlockPix;
+    sBestMv.iMvY = 0;
+    UpdateMeResults( sBestMv, uiBestCost, &pMe->pColoRefMb[sBestMv.iMvY], pMe );
+  }
+}
+#endif
+void LineFullSearch_c(	void *pFunc, void *vpMe,
+													uint16_t* pMvdTable, const int32_t kiFixedMvd,
+													const int32_t kiEncStride, const int32_t kiRefStride,
+													const int32_t kiMinPos, const int32_t kiMaxPos,
                           const bool bVerticalSearch ) {
   SWelsFuncPtrList *pFuncList      = static_cast<SWelsFuncPtrList *>(pFunc);
   SWelsME *pMe                            = static_cast<SWelsME *>(vpMe);
@@ -346,8 +483,8 @@
 
 void WelsMotionCrossSearch(SWelsFuncPtrList *pFuncList,  SWelsME * pMe,
 											const SSlice* pSlice, const int32_t kiEncStride,  const int32_t kiRefStride) {
-  PLineFullSearchFunc pfVerticalFullSearchFunc	= pFuncList->pfLineFullSearch;
-  PLineFullSearchFunc pfHorizontalFullSearchFunc	= pFuncList->pfLineFullSearch;
+  PLineFullSearchFunc pfVerticalFullSearchFunc	= pFuncList->pfVerticalFullSearch;
+  PLineFullSearchFunc pfHorizontalFullSearchFunc	= pFuncList->pfHorizontalFullSearch;
 
   const int32_t iCurMeBlockPixX = pMe->iCurMeBlockPixX;
   const int32_t iCurMeBlockQpelPixX = ((iCurMeBlockPixX)<<2);
--- /dev/null
+++ b/codec/encoder/core/x86/matrix_transpose.asm
@@ -1,0 +1,395 @@
+;*!
+;* \copy
+;*     Copyright (c)  2009-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.
+;*************************************************************************/
+
+%include "asm_inc.asm"
+
+;in:  m0, m1, m2, m3, m4, m5, m6, m7
+;out: m0, m3, m5, m2, m7, m1, m6, m4
+%macro TRANSPOSE_8x8B_MMX 10
+	MMX_XSwap bw,  %1, %2, %8
+	MMX_XSwap bw,  %3, %4, %2
+	MMX_XSwap bw,  %5, %6, %4
+	movq	%6, %9
+	movq	%10, %4
+	MMX_XSwap bw,  %7, %6, %4
+
+	MMX_XSwap wd,  %1, %3, %6
+	MMX_XSwap wd,  %8, %2, %3
+	MMX_XSwap wd,  %5, %7, %2
+	movq	%7, %10
+	movq	%10, %3
+	MMX_XSwap wd,  %7, %4, %3
+
+	MMX_XSwap dq,  %1, %5, %4
+	MMX_XSwap dq,  %6, %2, %5
+	MMX_XSwap dq,  %8, %7, %2
+	movq	%7, %10
+	movq	%10, %5
+	MMX_XSwap dq,  %7, %3, %5
+
+	movq	%3, %10
+%endmacro
+
+;in: m0, m3, m5, m2, m7, m1, m6, m4
+%macro TRANSPOSE8x8_WRITE_MMX 2	; dst, dst_stride
+	movq [%1], mm0			; result of line 1, x8 bytes
+	movq [%1+%2], mm3		; result of line 2
+	lea %1, [%1+2*%2]
+	movq [%1], mm5			; result of line 3
+	movq [%1+%2], mm2		; result of line 4
+	lea %1, [%1+2*%2]
+	movq [%1], mm7			; result of line 5
+	movq [%1+%2], mm1		; result of line 6
+	lea %1, [%1+2*%2]
+	movq [%1], mm6			; result of line 7
+	movq [%1+%2], mm4		; result of line 8
+%endmacro
+
+;in: m0, m3, m5, m2, m7, m1, m6, m4
+%macro TRANSPOSE8x8_WRITE_ALT_MMX 3	; dst, dst_stride, reg32
+	movq [%1], mm0			; result of line 1, x8 bytes
+	movq [%1+%2], mm3		; result of line 2
+	lea %3, [%1+2*%2]
+	movq [%3], mm5			; result of line 3
+	movq [%3+%2], mm2		; result of line 4
+	lea %3, [%3+2*%2]
+	movq [%3], mm7			; result of line 5
+	movq [%3+%2], mm1		; result of line 6
+	lea %3, [%3+2*%2]
+	movq [%3], mm6			; result of line 7
+	movq [%3+%2], mm4		; result of line 8
+%endmacro	; end of TRANSPOSE8x8_WRITE_ALT_MMX
+
+; for transpose 16x8
+
+;in:  m0, m1, m2, m3, m4, m5, m6, m7
+;out: m4, m2, m3, m7, m5, m1, m6, m0
+%macro TRANSPOSE_8x16B_SSE2		10
+	SSE2_XSawp bw,  %1, %2, %8
+	SSE2_XSawp bw,  %3, %4, %2
+	SSE2_XSawp bw,  %5, %6, %4
+	movdqa	%6, %9
+	movdqa	%10, %4
+	SSE2_XSawp bw,  %7, %6, %4
+
+	SSE2_XSawp wd,  %1, %3, %6
+	SSE2_XSawp wd,  %8, %2, %3
+	SSE2_XSawp wd,  %5, %7, %2
+	movdqa	%7, %10
+	movdqa	%10, %3
+	SSE2_XSawp wd,  %7, %4, %3
+
+	SSE2_XSawp dq,  %1, %5, %4
+	SSE2_XSawp dq,  %6, %2, %5
+	SSE2_XSawp dq,  %8, %7, %2
+	movdqa	%7, %10
+	movdqa	%10, %5
+	SSE2_XSawp dq,  %7, %3, %5
+
+	SSE2_XSawp qdq,  %1, %8, %3
+	SSE2_XSawp qdq,  %4, %2, %8
+	SSE2_XSawp qdq,  %6, %7, %2
+	movdqa	%7, %10
+	movdqa	%10, %1
+	SSE2_XSawp qdq,  %7, %5, %1
+	movdqa	%5, %10
+%endmacro	; end of TRANSPOSE_8x16B_SSE2
+
+
+%macro TRANSPOSE8x16_WRITE_SSE2	2	; dst, dst_stride
+	movq [%1], xmm4			; result of line 1, x8 bytes
+	movq [%1+%2], xmm2		; result of line 2
+	lea %1, [%1+2*%2]
+	movq [%1], xmm3			; result of line 3
+	movq [%1+%2], xmm7		; result of line 4
+
+	lea %1, [%1+2*%2]
+	movq [%1], xmm5			; result of line 5
+	movq [%1+%2], xmm1		; result of line 6
+	lea %1, [%1+2*%2]
+	movq [%1], xmm6			; result of line 7
+	movq [%1+%2], xmm0		; result of line 8
+
+	lea %1, [%1+2*%2]
+	movhpd [%1], xmm4		; result of line 9
+	movhpd [%1+%2], xmm2	; result of line 10
+	lea %1, [%1+2*%2]
+	movhpd [%1], xmm3		; result of line 11
+	movhpd [%1+%2], xmm7	; result of line 12
+
+	lea %1, [%1+2*%2]
+	movhpd [%1], xmm5		; result of line 13
+	movhpd [%1+%2], xmm1	; result of line 14
+	lea %1, [%1+2*%2]
+	movhpd [%1], xmm6		; result of line 15
+	movhpd [%1+%2], xmm0	; result of line 16
+%endmacro	; end of TRANSPOSE_WRITE_RESULT_SSE2
+
+%macro TRANSPOSE8x16_WRITE_ALT_SSE2	3	; dst, dst_stride, reg32
+	movq [%1], xmm4			; result of line 1, x8 bytes
+	movq [%1+%2], xmm2		; result of line 2
+	lea %3, [%1+2*%2]
+	movq [%3], xmm3			; result of line 3
+	movq [%3+%2], xmm7		; result of line 4
+
+	lea %3, [%3+2*%2]
+	movq [%3], xmm5			; result of line 5
+	movq [%3+%2], xmm1		; result of line 6
+	lea %3, [%3+2*%2]
+	movq [%3], xmm6			; result of line 7
+	movq [%3+%2], xmm0		; result of line 8
+
+	lea %3, [%3+2*%2]
+	movhpd [%3], xmm4		; result of line 9
+	movhpd [%3+%2], xmm2	; result of line 10
+	lea %3, [%3+2*%2]
+	movhpd [%3], xmm3		; result of line 11
+	movhpd [%3+%2], xmm7	; result of line 12
+
+	lea %3, [%3+2*%2]
+	movhpd [%3], xmm5		; result of line 13
+	movhpd [%3+%2], xmm1	; result of line 14
+	lea %3, [%3+2*%2]
+	movhpd [%3], xmm6		; result of line 15
+	movhpd [%3+%2], xmm0	; result of line 16
+%endmacro	; end of TRANSPOSE8x16_WRITE_ALT_SSE2
+
+
+SECTION .text
+
+WELS_EXTERN TransposeMatrixBlock16x16_sse2
+; void TransposeMatrixBlock16x16_sse2( void *dst/*16x16*/, const int32_t dst_stride, void *src/*16x16*/, const int32_t src_stride );
+	push r4
+	push r5
+	%assign push_num 2
+	LOAD_4_PARA
+	PUSH_XMM 8
+	SIGN_EXTENSION	r1, r1d
+	SIGN_EXTENSION	r3, r3d
+
+	mov r4, r7
+	and r4, 0Fh
+	sub r7, 10h
+	sub r7, r4
+	lea r5, [r3+r3*2]
+	; top 8x16 block
+	movdqa xmm0, [r2]
+	movdqa xmm1, [r2+r3]
+	movdqa xmm2, [r2+r3*2]
+	movdqa xmm3, [r2+r5]
+	lea r2, [r2+r3*4]
+	movdqa xmm4, [r2]
+	movdqa xmm5, [r2+r3]
+	movdqa xmm6, [r2+r3*2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m4, m2, m3, m7, m5, m1, m6, m0
+	TRANSPOSE_8x16B_SSE2	xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, [r2+r5], [r7]
+
+	TRANSPOSE8x16_WRITE_SSE2		r0, r1
+
+	; bottom 8x16 block
+	lea	r2, [r2+r3*4]
+	movdqa xmm0, [r2]
+	movdqa xmm1, [r2+r3]
+	movdqa xmm2, [r2+r3*2]
+	movdqa xmm3, [r2+r5]
+	lea r2, [r2+r3*4]
+	movdqa xmm4, [r2]
+	movdqa xmm5, [r2+r3]
+	movdqa xmm6, [r2+r3*2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m4, m2, m3, m7, m5, m1, m6, m0
+	TRANSPOSE_8x16B_SSE2	xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, [r2+r5], [r7]
+
+	mov r5, r1
+	sal r5, 4
+	sub r0, r5
+	lea r0, [r0+r1*2+8]
+	TRANSPOSE8x16_WRITE_SSE2		r0, r1
+
+	add r7, r4
+	add r7, 10h
+	POP_XMM
+	LOAD_4_PARA_POP
+	pop r5
+	pop r4
+	ret
+
+WELS_EXTERN TransposeMatrixBlocksx16_sse2
+; void TransposeMatrixBlocksx16_sse2( void *dst/*W16x16*/, const int32_t dst_stride, void *src/*16xW16*/, const int32_t src_stride, const int32_t num_blocks );
+	push r5
+	push r6
+	%assign push_num 2
+	LOAD_5_PARA
+	PUSH_XMM 8
+	SIGN_EXTENSION  r1, r1d
+	SIGN_EXTENSION  r3, r3d
+	SIGN_EXTENSION  r4, r4d
+	mov r5, r7
+	and r5, 0Fh
+	sub r7, 10h
+	sub r7, r5
+TRANSPOSE_LOOP_SSE2:
+	; explictly loading next loop data
+	lea	r6, [r2+r3*8]
+	push r4
+%rep 8
+	mov	r4, [r6]
+	mov	r4, [r6+r3]
+	lea	r6, [r6+r3*2]
+%endrep
+	pop r4
+	; top 8x16 block
+	movdqa xmm0, [r2]
+	movdqa xmm1, [r2+r3]
+	lea r2, [r2+r3*2]
+	movdqa xmm2, [r2]
+	movdqa xmm3, [r2+r3]
+	lea r2, [r2+r3*2]
+	movdqa xmm4, [r2]
+	movdqa xmm5, [r2+r3]
+	lea r2, [r2+r3*2]
+	movdqa xmm6, [r2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m4, m2, m3, m7, m5, m1, m6, m0
+	TRANSPOSE_8x16B_SSE2	xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, [r2+r3], [r7]
+	TRANSPOSE8x16_WRITE_ALT_SSE2		r0, r1, r6
+	lea	r2, [r2+r3*2]
+
+	; bottom 8x16 block
+	movdqa xmm0, [r2]
+	movdqa xmm1, [r2+r3]
+	lea	r2, [r2+r3*2]
+	movdqa xmm2, [r2]
+	movdqa xmm3, [r2+r3]
+	lea r2, [r2+r3*2]
+	movdqa xmm4, [r2]
+	movdqa xmm5, [r2+r3]
+	lea	r2, [r2+r3*2]
+	movdqa xmm6, [r2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m4, m2, m3, m7, m5, m1, m6, m0
+	TRANSPOSE_8x16B_SSE2	xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, [r2+r3], [r7]
+	TRANSPOSE8x16_WRITE_ALT_SSE2		r0+8, r1, r6
+	lea	r2, [r2+r3*2]
+	lea r0, [r0+16]
+	dec r4
+	jg near TRANSPOSE_LOOP_SSE2
+
+	add r7, r5
+	add r7, 10h
+	POP_XMM
+	LOAD_5_PARA_POP
+	pop r6
+	pop r5
+	ret
+
+WELS_EXTERN TransposeMatrixBlock8x8_mmx
+; void TransposeMatrixBlock8x8_mmx( void *dst/*8x8*/, const int32_t dst_stride, void *src/*8x8*/, const int32_t src_stride );
+	%assign push_num 0
+	LOAD_4_PARA
+	SIGN_EXTENSION  r1, r1d
+	SIGN_EXTENSION  r3, r3d
+	sub	r7, 8
+
+	movq mm0, [r2]
+	movq mm1, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm2, [r2]
+	movq mm3, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm4, [r2]
+	movq mm5, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm6, [r2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m0, m3, m5, m2, m7, m1, m6, m4
+	TRANSPOSE_8x8B_MMX mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, [r2+r3], [r7]
+
+	TRANSPOSE8x8_WRITE_MMX r0, r1
+
+	emms
+	add r7, 8
+	LOAD_4_PARA_POP
+	ret
+
+WELS_EXTERN TransposeMatrixBlocksx8_mmx
+; void TransposeMatrixBlocksx8_mmx( void *dst/*8xW8*/, const int32_t dst_stride, void *src/*W8x8*/, const int32_t src_stride, const int32_t num_blocks );
+	push r5
+	push r6
+	%assign push_num 2
+	LOAD_5_PARA
+	SIGN_EXTENSION  r1, r1d
+	SIGN_EXTENSION  r3, r3d
+	SIGN_EXTENSION  r4, r4d
+	sub	r7, 8
+
+	lea	r5, [r2+r3*8]
+
+TRANSPOSE_BLOCKS_X8_LOOP_MMX:
+	; explictly loading next loop data
+%rep 4
+	mov r6, [r5]
+	mov r6, [r5+r3]
+	lea	r5, [r5+r3*2]
+%endrep
+	movq mm0, [r2]
+	movq mm1, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm2, [r2]
+	movq mm3, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm4, [r2]
+	movq mm5, [r2+r3]
+	lea r2, [r2+2*r3]
+	movq mm6, [r2]
+
+	;in:  m0, m1, m2, m3, m4, m5, m6, m7
+	;out: m0, m3, m5, m2, m7, m1, m6, m4
+	TRANSPOSE_8x8B_MMX mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, [r2+r3], [r7]
+
+	TRANSPOSE8x8_WRITE_ALT_MMX r0, r1, r6
+	lea r0, [r0+8]
+	lea r2, [r2+2*r3]
+	dec r4
+	jg near TRANSPOSE_BLOCKS_X8_LOOP_MMX
+
+	emms
+	add r7, 8
+	LOAD_5_PARA_POP
+	pop r6
+	pop r5
+	ret
--- /dev/null
+++ b/codec/encoder/core/x86/sample_sc.asm
@@ -1,0 +1,225 @@
+;*!
+;* \copy
+;*     Copyright (c)  2009-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.
+;*
+;*************************************************************************/
+%include "asm_inc.asm"
+
+SECTION .text
+
+;**********************************************************************************************************************************
+;
+;	uint32_t SampleSad16x16Hor8_sse41( uint8_t *src, int32_t stride_src, uint8_t *ref, int32_t stride_ref, uint16 base_cost[8], int32_t *index_min_cost )
+;
+;	\note:
+;		src need align with 16 bytes, ref is optional
+;	\return value:
+;		return minimal SAD cost, according index carried by index_min_cost
+;**********************************************************************************************************************************
+; try 8 mv via offset
+; xmm7 store sad costs
+%macro   SAD_16x16_LINE_SSE41  4	; src, ref, stride_src, stride_ref
+    movdqa		xmm0, [%1]
+    movdqu		xmm1, [%2]
+    movdqu		xmm2, [%2+8h]
+    movdqa		xmm3, xmm1
+    movdqa		xmm4, xmm2
+
+    mpsadbw		xmm1, xmm0, 0	; 000 B
+    paddw		xmm7, xmm1		; accumulate cost
+
+    mpsadbw		xmm3, xmm0, 5	; 101 B
+    paddw		xmm7, xmm3		; accumulate cost
+
+    mpsadbw		xmm2, xmm0, 2	; 010 B
+    paddw		xmm7, xmm2		; accumulate cost
+
+    mpsadbw		xmm4, xmm0, 7	; 111 B
+    paddw		xmm7, xmm4		; accumulate cost
+
+    add			%1, %3
+    add			%2, %4
+%endmacro	; end of SAD_16x16_LINE_SSE41
+%macro   SAD_16x16_LINE_SSE41E  4	; src, ref, stride_src, stride_ref
+    movdqa		xmm0, [%1]
+    movdqu		xmm1, [%2]
+    movdqu		xmm2, [%2+8h]
+    movdqa		xmm3, xmm1
+    movdqa		xmm4, xmm2
+
+    mpsadbw		xmm1, xmm0, 0	; 000 B
+    paddw		xmm7, xmm1		; accumulate cost
+
+    mpsadbw		xmm3, xmm0, 5	; 101 B
+    paddw		xmm7, xmm3		; accumulate cost
+
+    mpsadbw		xmm2, xmm0, 2	; 010 B
+    paddw		xmm7, xmm2		; accumulate cost
+
+    mpsadbw		xmm4, xmm0, 7	; 111 B
+    paddw		xmm7, xmm4		; accumulate cost
+%endmacro	; end of SAD_16x16_LINE_SSE41E
+
+WELS_EXTERN SampleSad16x16Hor8_sse41
+    ;push ebx
+    ;push esi
+    ;mov eax, [esp+12]	;   src
+    ;mov ecx, [esp+16]	;   stride_src
+    ;mov ebx, [esp+20]	;   ref
+    ;mov edx, [esp+24]	;   stride_ref
+    ;mov esi, [esp+28]	;   base_cost
+    %assign  push_num 0
+    LOAD_6_PARA
+    PUSH_XMM 8
+    SIGN_EXTENSION	r1, r1d
+    SIGN_EXTENSION	r3, r3d
+    pxor	xmm7,	xmm7
+
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41	r0, r2, r1, r3
+    SAD_16x16_LINE_SSE41E	r0, r2, r1, r3
+
+    pxor	xmm0,	xmm0
+    movdqa	xmm6,	xmm7
+    punpcklwd	xmm6,	xmm0
+    punpckhwd	xmm7,	xmm0
+
+    movdqa	xmm5,	[r4]
+    movdqa	xmm4,	xmm5
+    punpcklwd	xmm4,	xmm0
+    punpckhwd	xmm5,	xmm0
+
+    paddd	xmm4,	xmm6
+    paddd	xmm5,	xmm7
+    movdqa	xmm3,	xmm4
+    pminud	xmm3,	xmm5
+    pshufd	xmm2,	xmm3,	01001110B
+    pminud	xmm2,	xmm3
+    pshufd	xmm3,	xmm2,	10110001B
+    pminud	xmm2,	xmm3
+    movd	retrd,	xmm2
+    pcmpeqd	xmm4,	xmm2
+    movmskps	r2d, xmm4
+    bsf		r1d,	r2d
+    jnz	near WRITE_INDEX
+
+    pcmpeqd	xmm5,	xmm2
+    movmskps	r2d, xmm5
+    bsf		r1d,	r2d
+    add		r1d,	4
+
+WRITE_INDEX:
+    mov		[r5],	r1d
+    POP_XMM
+    LOAD_6_PARA_POP
+    ret
+
+;**********************************************************************************************************************************
+;
+;	uint32_t SampleSad8x8Hor8_sse41( uint8_t *src, int32_t stride_src, uint8_t *ref, int32_t stride_ref, uint16_t base_cost[8], int32_t *index_min_cost )
+;
+;	\note:
+;		src and ref is optional to align with 16 due inter 8x8
+;	\return value:
+;		return minimal SAD cost, according index carried by index_min_cost
+;
+;**********************************************************************************************************************************
+; try 8 mv via offset
+; xmm7 store sad costs
+%macro   SAD_8x8_LINE_SSE41  4	; src, ref, stride_src, stride_ref
+    movdqu		xmm0, [%1]
+    movdqu		xmm1, [%2]
+    movdqa		xmm2, xmm1
+
+    mpsadbw		xmm1, xmm0, 0	; 000 B
+    paddw		xmm7, xmm1		; accumulate cost
+
+    mpsadbw		xmm2, xmm0, 5	; 101 B
+    paddw		xmm7, xmm2		; accumulate cost
+
+    add			%1, %3
+    add			%2, %4
+%endmacro	; end of SAD_8x8_LINE_SSE41
+%macro   SAD_8x8_LINE_SSE41E  4	; src, ref, stride_src, stride_ref
+    movdqu		xmm0, [%1]
+    movdqu		xmm1, [%2]
+    movdqa		xmm2, xmm1
+
+    mpsadbw		xmm1, xmm0, 0	; 000 B
+    paddw		xmm7, xmm1		; accumulate cost
+
+    mpsadbw		xmm2, xmm0, 5	; 101 B
+    paddw		xmm7, xmm2		; accumulate cost
+%endmacro	; end of SAD_8x8_LINE_SSE41E
+
+WELS_EXTERN SampleSad8x8Hor8_sse41
+    %assign  push_num 0
+    LOAD_6_PARA
+    PUSH_XMM 8
+    SIGN_EXTENSION	r1, r1d
+    SIGN_EXTENSION	r3, r3d
+    movdqa xmm7, [r4]	;	load base cost list
+
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41	r0, r2, r1, r3
+    SAD_8x8_LINE_SSE41E	r0, r2, r1, r3
+
+    phminposuw	xmm0, xmm7	; horizon search the minimal sad cost and its index
+    movd	retrd, xmm0	; for return: DEST[15:0] <- MIN, DEST[31:16] <- INDEX
+    mov		r1d, retrd
+    and		retrd, 0xFFFF
+    sar		r1d, 16
+    mov		[r5], r1d
+
+    POP_XMM
+    LOAD_6_PARA_POP
+    ret
+
--- a/codec/encoder/targets.mk
+++ b/codec/encoder/targets.mk
@@ -40,8 +40,10 @@
 	$(ENCODER_SRCDIR)/core/x86/coeff.asm\
 	$(ENCODER_SRCDIR)/core/x86/dct.asm\
 	$(ENCODER_SRCDIR)/core/x86/intra_pred.asm\
+	$(ENCODER_SRCDIR)/core/x86/matrix_transpose.asm\
 	$(ENCODER_SRCDIR)/core/x86/memzero.asm\
 	$(ENCODER_SRCDIR)/core/x86/quant.asm\
+	$(ENCODER_SRCDIR)/core/x86/sample_sc.asm\
 	$(ENCODER_SRCDIR)/core/x86/score.asm\
 
 ENCODER_OBJS += $(ENCODER_ASM_SRCS:.asm=.$(OBJ))
--- a/test/encoder/EncUT_MotionEstimate.cpp
+++ b/test/encoder/EncUT_MotionEstimate.cpp
@@ -5,6 +5,7 @@
 #include "sample.h"
 #include "svc_motion_estimate.h"
 #include "wels_func_ptr_def.h"
+#include "cpu.h"
 
 
 using namespace WelsSVCEnc;
@@ -43,11 +44,12 @@
     m_iMaxSearchBlock = 16;
     m_uiMvdTableSize	=  (1 + (648 << 1));
 
+    pMa = new CMemoryAlign(0);
     m_pRefPic = static_cast<uint8_t *>
-    (malloc(m_iWidth*m_iHeight));
+    (pMa->WelsMalloc(m_iWidth*m_iHeight, "RefPic"));
     ASSERT_TRUE( NULL != m_pRefPic );
     m_pSrcBlock = static_cast<uint8_t *>
-    (malloc(m_iMaxSearchBlock*m_iMaxSearchBlock));
+    (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 );
@@ -54,8 +56,9 @@
   }
   virtual void TearDown() {
     delete [] m_pMvdCostTable;
-    free( m_pRefPic );
-    free( m_pSrcBlock );
+    pMa->WelsFree( m_pRefPic, "RefPic");
+    pMa->WelsFree( m_pSrcBlock, "SrcBlock");
+    delete pMa;
   }
 public:
   uint8_t *m_pRefPic;
@@ -66,6 +69,7 @@
   int32_t m_iWidth;
   int32_t m_iHeight;
   int32_t m_iMaxSearchBlock;
+  CMemoryAlign *pMa;
 };
 
 
@@ -243,4 +247,134 @@
     ASSERT_TRUE(iTryTimes > 0);
     //it is possible that ref at differnt position is identical, but that should be under a low probability
   }
-}
\ No newline at end of file
+}
+
+#ifdef X86_ASM
+TEST_F(MotionEstimateTest, TestVerticalSearch_SSE41)
+{
+  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
+  WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
+
+  uint8_t *pRefPicCenter = m_pRefPic+(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;
+
+  sTargetMv.iMvX = 0;
+  sTargetMv.iMvY = WELS_MAX(INTPEL_NEEDED_MARGIN, rand()%m_iHeight-INTPEL_NEEDED_MARGIN);
+  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.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;
+    VerticalFullSearchUsingSSE41 ( &sFuncList, &sMe,
+                      pMvdCostY, pMvdCostX[ iCurMeBlockQpelPixX ],
+                      m_iMaxSearchBlock, m_iWidth,
+                      INTPEL_NEEDED_MARGIN,
+                      m_iHeight-INTPEL_NEEDED_MARGIN, true );
+
+    //the last selection may be affected by MVDcost, that is when smaller MvY will be better
+    bFoundMatch = (sMe.sMv.iMvX==0
+                   &&(sMe.sMv.iMvY==sTargetMv.iMvY||abs(sMe.sMv.iMvY)<abs(sTargetMv.iMvY)));
+    //printf("TestVerticalSearch 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, TestHorizontalSearch_SSE41)
+{
+  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
+  WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
+
+  uint8_t *pRefPicCenter = m_pRefPic+(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;
+
+  sTargetMv.iMvX = WELS_MAX(INTPEL_NEEDED_MARGIN, rand()%m_iWidth-INTPEL_NEEDED_MARGIN);
+  sTargetMv.iMvY = 0;
+  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.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;
+    HorizontalFullSearchUsingSSE41 ( &sFuncList, &sMe,
+                      pMvdCostX, pMvdCostY[ iCurMeBlockQpelPixY ],
+                      m_iMaxSearchBlock, m_iWidth,
+                      INTPEL_NEEDED_MARGIN,
+                      m_iWidth-INTPEL_NEEDED_MARGIN, false );
+
+    //the last selection may be affected by MVDcost, that is when smaller MvY will be better
+    bFoundMatch = (sMe.sMv.iMvY==0
+                   &&(sMe.sMv.iMvX==sTargetMv.iMvX||abs(sMe.sMv.iMvX)<abs(sTargetMv.iMvX)));
+    //printf("TestHorizontalSearch 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
+  }
+}
+#endif
\ No newline at end of file