1 /*!
2  * \copy
3  *     Copyright (c)  2013, Cisco Systems
4  *     All rights reserved.
5  *
6  *     Redistribution and use in source and binary forms, with or without
7  *     modification, are permitted provided that the following conditions
8  *     are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *
13  *        * Redistributions in binary form must reproduce the above copyright
14  *          notice, this list of conditions and the following disclaimer in
15  *          the documentation and/or other materials provided with the
16  *          distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *     POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include "ComplexityAnalysis.h"
34 #include "cpu.h"
35 #include "macros.h"
36 #include "intra_pred_common.h"
37 
38 WELSVP_NAMESPACE_BEGIN
39 
40 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
41 
CComplexityAnalysis(int32_t iCpuFlag)42 CComplexityAnalysis::CComplexityAnalysis (int32_t iCpuFlag) {
43   m_eMethod   = METHOD_COMPLEXITY_ANALYSIS;
44   m_pfGomSad   = NULL;
45   WelsMemset (&m_sComplexityAnalysisParam, 0, sizeof (m_sComplexityAnalysisParam));
46 }
47 
~CComplexityAnalysis()48 CComplexityAnalysis::~CComplexityAnalysis() {
49 }
50 
Process(int32_t iType,SPixMap * pSrcPixMap,SPixMap * pRefPixMap)51 EResult CComplexityAnalysis::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
52   EResult eReturn = RET_SUCCESS;
53 
54   switch (m_sComplexityAnalysisParam.iComplexityAnalysisMode) {
55   case FRAME_SAD:
56     AnalyzeFrameComplexityViaSad (pSrcPixMap, pRefPixMap);
57     break;
58   case GOM_SAD:
59     AnalyzeGomComplexityViaSad (pSrcPixMap, pRefPixMap);
60     break;
61   case GOM_VAR:
62     AnalyzeGomComplexityViaVar (pSrcPixMap, pRefPixMap);
63     break;
64   default:
65     eReturn = RET_INVALIDPARAM;
66     break;
67   }
68 
69   return eReturn;
70 }
71 
72 
Set(int32_t iType,void * pParam)73 EResult CComplexityAnalysis::Set (int32_t iType, void* pParam) {
74   if (pParam == NULL) {
75     return RET_INVALIDPARAM;
76   }
77 
78   m_sComplexityAnalysisParam = * (SComplexityAnalysisParam*)pParam;
79 
80   return RET_SUCCESS;
81 }
82 
Get(int32_t iType,void * pParam)83 EResult CComplexityAnalysis::Get (int32_t iType, void* pParam) {
84   if (pParam == NULL) {
85     return RET_INVALIDPARAM;
86   }
87 
88   SComplexityAnalysisParam* sComplexityAnalysisParam = (SComplexityAnalysisParam*)pParam;
89 
90   sComplexityAnalysisParam->iFrameComplexity = m_sComplexityAnalysisParam.iFrameComplexity;
91 
92   return RET_SUCCESS;
93 }
94 
95 
96 ///////////////////////////////////////////////////////////////////////////////////////////////
AnalyzeFrameComplexityViaSad(SPixMap * pSrcPixMap,SPixMap * pRefPixMap)97 void CComplexityAnalysis::AnalyzeFrameComplexityViaSad (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
98   SVAACalcResult*     pVaaCalcResults = NULL;
99   pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
100 
101   m_sComplexityAnalysisParam.iFrameComplexity = pVaaCalcResults->iFrameSad;
102 
103   if (m_sComplexityAnalysisParam.iCalcBgd) { //BGD control
104     m_sComplexityAnalysisParam.iFrameComplexity = GetFrameSadExcludeBackground (pSrcPixMap, pRefPixMap);
105   }
106 }
107 
GetFrameSadExcludeBackground(SPixMap * pSrcPixMap,SPixMap * pRefPixMap)108 int32_t CComplexityAnalysis::GetFrameSadExcludeBackground (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
109   int32_t iWidth     = pSrcPixMap->sRect.iRectWidth;
110   int32_t iHeight    = pSrcPixMap->sRect.iRectHeight;
111   int32_t iMbWidth  = iWidth  >> 4;
112   int32_t iMbHeight = iHeight >> 4;
113   int32_t iMbNum    = iMbWidth * iMbHeight;
114 
115   int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
116   int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
117   int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0;
118 
119   uint8_t* pBackgroundMbFlag = (uint8_t*)m_sComplexityAnalysisParam.pBackgroundMbFlag;
120   uint32_t* uiRefMbType = (uint32_t*)m_sComplexityAnalysisParam.uiRefMbType;
121   SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
122   int32_t*  pGomForegroundBlockNum = m_sComplexityAnalysisParam.pGomForegroundBlockNum;
123 
124   uint32_t uiFrameSad = 0;
125   for (int32_t j = 0; j < iGomMbNum; j ++) {
126     iGomMbStartIndex = j * iMbNumInGom;
127     iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
128 
129     for (int32_t i = iGomMbStartIndex; i < iGomMbEndIndex; i ++) {
130       if (pBackgroundMbFlag[i] == 0 || IS_INTRA (uiRefMbType[i])) {
131         pGomForegroundBlockNum[j]++;
132         uiFrameSad += pVaaCalcResults->pSad8x8[i][0];
133         uiFrameSad += pVaaCalcResults->pSad8x8[i][1];
134         uiFrameSad += pVaaCalcResults->pSad8x8[i][2];
135         uiFrameSad += pVaaCalcResults->pSad8x8[i][3];
136       }
137     }
138   }
139 
140   return (uiFrameSad);
141 }
142 
143 
InitGomSadFunc(PGOMSadFunc & pfGomSad,uint8_t iCalcBgd)144 void InitGomSadFunc (PGOMSadFunc& pfGomSad, uint8_t iCalcBgd) {
145   pfGomSad = GomSampleSad;
146 
147   if (iCalcBgd) {
148     pfGomSad = GomSampleSadExceptBackground;
149   }
150 }
151 
GomSampleSad(uint32_t * pGomSad,int32_t * pGomForegroundBlockNum,int32_t * pSad8x8,uint8_t pBackgroundMbFlag)152 void GomSampleSad (uint32_t* pGomSad, int32_t* pGomForegroundBlockNum, int32_t* pSad8x8, uint8_t pBackgroundMbFlag) {
153   (*pGomForegroundBlockNum) ++;
154   *pGomSad += pSad8x8[0];
155   *pGomSad += pSad8x8[1];
156   *pGomSad += pSad8x8[2];
157   *pGomSad += pSad8x8[3];
158 }
159 
GomSampleSadExceptBackground(uint32_t * pGomSad,int32_t * pGomForegroundBlockNum,int32_t * pSad8x8,uint8_t pBackgroundMbFlag)160 void GomSampleSadExceptBackground (uint32_t* pGomSad, int32_t* pGomForegroundBlockNum, int32_t* pSad8x8,
161                                    uint8_t pBackgroundMbFlag) {
162   if (pBackgroundMbFlag == 0) {
163     (*pGomForegroundBlockNum) ++;
164     *pGomSad += pSad8x8[0];
165     *pGomSad += pSad8x8[1];
166     *pGomSad += pSad8x8[2];
167     *pGomSad += pSad8x8[3];
168   }
169 }
170 
AnalyzeGomComplexityViaSad(SPixMap * pSrcPixMap,SPixMap * pRefPixMap)171 void CComplexityAnalysis::AnalyzeGomComplexityViaSad (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
172   int32_t iWidth     = pSrcPixMap->sRect.iRectWidth;
173   int32_t iHeight    = pSrcPixMap->sRect.iRectHeight;
174   int32_t iMbWidth  = iWidth  >> 4;
175   int32_t iMbHeight = iHeight >> 4;
176   int32_t iMbNum    = iMbWidth * iMbHeight;
177 
178   int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
179   int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
180 
181   int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0, iGomMbRowNum = 0;
182   int32_t iMbStartIndex = 0, iMbEndIndex = 0;
183 
184   uint8_t* pBackgroundMbFlag = (uint8_t*)m_sComplexityAnalysisParam.pBackgroundMbFlag;
185   uint32_t* uiRefMbType = (uint32_t*)m_sComplexityAnalysisParam.uiRefMbType;
186   SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
187   int32_t*  pGomForegroundBlockNum = (int32_t*)m_sComplexityAnalysisParam.pGomForegroundBlockNum;
188   int32_t*  pGomComplexity = (int32_t*)m_sComplexityAnalysisParam.pGomComplexity;
189 
190   uint32_t uiGomSad = 0, uiFrameSad = 0;
191   InitGomSadFunc (m_pfGomSad, m_sComplexityAnalysisParam.iCalcBgd);
192 
193   for (int32_t j = 0; j < iGomMbNum; j ++) {
194     uiGomSad = 0;
195 
196     iGomMbStartIndex = j * iMbNumInGom;
197     iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
198     iGomMbRowNum = (iGomMbEndIndex + iMbWidth - 1) / iMbWidth  - iGomMbStartIndex / iMbWidth;
199 
200     iMbStartIndex = iGomMbStartIndex;
201     iMbEndIndex = WELS_MIN ((iMbStartIndex / iMbWidth + 1) * iMbWidth, iGomMbEndIndex);
202 
203     do {
204       for (int32_t i = iMbStartIndex; i < iMbEndIndex; i ++) {
205         m_pfGomSad (&uiGomSad, pGomForegroundBlockNum + j, pVaaCalcResults->pSad8x8[i], pBackgroundMbFlag[i]
206                     && !IS_INTRA (uiRefMbType[i]));
207       }
208 
209       iMbStartIndex = iMbEndIndex;
210       iMbEndIndex = WELS_MIN (iMbEndIndex + iMbWidth , iGomMbEndIndex);
211 
212     } while (--iGomMbRowNum);
213     pGomComplexity[j] = uiGomSad;
214     uiFrameSad += pGomComplexity[j];
215   }
216   m_sComplexityAnalysisParam.iFrameComplexity = uiFrameSad;
217 }
218 
219 
AnalyzeGomComplexityViaVar(SPixMap * pSrcPixMap,SPixMap * pRefPixMap)220 void CComplexityAnalysis::AnalyzeGomComplexityViaVar (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
221   int32_t iWidth     = pSrcPixMap->sRect.iRectWidth;
222   int32_t iHeight    = pSrcPixMap->sRect.iRectHeight;
223   int32_t iMbWidth  = iWidth  >> 4;
224   int32_t iMbHeight = iHeight >> 4;
225   int32_t iMbNum    = iMbWidth * iMbHeight;
226 
227   int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
228   int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
229   int32_t iGomSampleNum = 0;
230 
231   int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0, iGomMbRowNum = 0;
232   int32_t iMbStartIndex = 0, iMbEndIndex = 0;
233 
234   SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
235   int32_t*  pGomComplexity = (int32_t*)m_sComplexityAnalysisParam.pGomComplexity;
236   uint32_t  uiFrameSad = 0;
237 
238   uint32_t uiSampleSum = 0, uiSquareSum = 0;
239 
240   for (int32_t j = 0; j < iGomMbNum; j ++) {
241     uiSampleSum = 0;
242     uiSquareSum = 0;
243 
244     iGomMbStartIndex = j * iMbNumInGom;
245     iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
246     iGomMbRowNum = (iGomMbEndIndex + iMbWidth - 1) / iMbWidth  - iGomMbStartIndex / iMbWidth;
247 
248     iMbStartIndex = iGomMbStartIndex;
249     iMbEndIndex = WELS_MIN ((iMbStartIndex / iMbWidth + 1) * iMbWidth, iGomMbEndIndex);
250 
251     iGomSampleNum = (iMbEndIndex - iMbStartIndex) * MB_WIDTH_LUMA * MB_WIDTH_LUMA;
252 
253     do {
254       for (int32_t i = iMbStartIndex; i < iMbEndIndex; i ++) {
255         uiSampleSum += pVaaCalcResults->pSum16x16[i];
256         uiSquareSum += pVaaCalcResults->pSumOfSquare16x16[i];
257       }
258 
259       iMbStartIndex = iMbEndIndex;
260       iMbEndIndex = WELS_MIN (iMbEndIndex + iMbWidth, iGomMbEndIndex);
261 
262     } while (--iGomMbRowNum);
263 
264     pGomComplexity[j] = uiSquareSum - (uiSampleSum * uiSampleSum / iGomSampleNum);
265     uiFrameSad += pGomComplexity[j];
266   }
267   m_sComplexityAnalysisParam.iFrameComplexity = uiFrameSad;
268 }
269 
270 
CComplexityAnalysisScreen(int32_t iCpuFlag)271 CComplexityAnalysisScreen::CComplexityAnalysisScreen (int32_t iCpuFlag) {
272   m_eMethod   = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
273   WelsMemset (&m_ComplexityAnalysisParam, 0, sizeof (m_ComplexityAnalysisParam));
274 
275   m_pSadFunc = WelsSampleSad16x16_c;
276   m_pIntraFunc[0] = WelsI16x16LumaPredV_c;
277   m_pIntraFunc[1] = WelsI16x16LumaPredH_c;
278 #ifdef X86_ASM
279   if (iCpuFlag & WELS_CPU_SSE2) {
280     m_pSadFunc = WelsSampleSad16x16_sse2;
281     m_pIntraFunc[0] = WelsI16x16LumaPredV_sse2;
282     m_pIntraFunc[1] = WelsI16x16LumaPredH_sse2;
283 
284   }
285 #endif
286 
287 #if defined (HAVE_NEON)
288   if (iCpuFlag & WELS_CPU_NEON) {
289     m_pSadFunc = WelsSampleSad16x16_neon;
290     m_pIntraFunc[0] = WelsI16x16LumaPredV_neon;
291     m_pIntraFunc[1] = WelsI16x16LumaPredH_neon;
292 
293   }
294 #endif
295 
296 #if defined (HAVE_NEON_AARCH64)
297   if (iCpuFlag & WELS_CPU_NEON) {
298     m_pSadFunc = WelsSampleSad16x16_AArch64_neon;
299     m_pIntraFunc[0] =  WelsI16x16LumaPredV_AArch64_neon;
300     m_pIntraFunc[1] = WelsI16x16LumaPredH_AArch64_neon;
301   }
302 #endif
303 
304 }
305 
~CComplexityAnalysisScreen()306 CComplexityAnalysisScreen::~CComplexityAnalysisScreen() {
307 }
308 
Process(int32_t nType,SPixMap * pSrc,SPixMap * pRef)309 EResult CComplexityAnalysisScreen::Process (int32_t nType, SPixMap* pSrc, SPixMap* pRef) {
310   bool bScrollFlag = m_ComplexityAnalysisParam.sScrollResult.bScrollDetectFlag;
311   int32_t iIdrFlag    = m_ComplexityAnalysisParam.iIdrFlag;
312   int32_t iScrollMvX = m_ComplexityAnalysisParam.sScrollResult.iScrollMvX;
313   int32_t iScrollMvY = m_ComplexityAnalysisParam.sScrollResult.iScrollMvY;
314 
315   if (m_ComplexityAnalysisParam.iMbRowInGom <= 0)
316     return RET_INVALIDPARAM;
317   if (!iIdrFlag && pRef == NULL)
318     return RET_INVALIDPARAM;
319 
320   if (iIdrFlag || pRef == NULL) {
321     GomComplexityAnalysisIntra (pSrc);
322   } else if (!bScrollFlag || ((iScrollMvX == 0) && (iScrollMvY == 0))) {
323     GomComplexityAnalysisInter (pSrc, pRef, 0);
324   } else {
325     GomComplexityAnalysisInter (pSrc, pRef, 1);
326   }
327 
328   return RET_SUCCESS;
329 }
330 
331 
Set(int32_t nType,void * pParam)332 EResult CComplexityAnalysisScreen::Set (int32_t nType, void* pParam) {
333   if (pParam == NULL)
334     return RET_INVALIDPARAM;
335 
336   m_ComplexityAnalysisParam = * (SComplexityAnalysisScreenParam*)pParam;
337 
338   return RET_SUCCESS;
339 }
340 
Get(int32_t nType,void * pParam)341 EResult CComplexityAnalysisScreen::Get (int32_t nType, void* pParam) {
342   if (pParam == NULL)
343     return RET_INVALIDPARAM;
344 
345   * (SComplexityAnalysisScreenParam*)pParam = m_ComplexityAnalysisParam;
346 
347   return RET_SUCCESS;
348 }
349 
GomComplexityAnalysisIntra(SPixMap * pSrc)350 void CComplexityAnalysisScreen::GomComplexityAnalysisIntra (SPixMap* pSrc) {
351   int32_t iWidth                  = pSrc->sRect.iRectWidth;
352   int32_t iHeight                 = pSrc->sRect.iRectHeight;
353   int32_t iBlockWidth             = iWidth  >> 4;
354   int32_t iBlockHeight            = iHeight >> 4;
355 
356   int32_t iBlockSadH, iBlockSadV, iGomSad = 0;
357   int32_t iIdx = 0;
358 
359   uint8_t* pPtrY = NULL;
360   int32_t iStrideY = 0;
361   int32_t iRowStrideY = 0;
362 
363   uint8_t* pTmpCur = NULL;
364 
365   ENFORCE_STACK_ALIGN_1D (uint8_t, iMemPredMb, 256, 16)
366 
367   pPtrY = (uint8_t*)pSrc->pPixel[0];
368 
369   iStrideY  = pSrc->iStride[0];
370   iRowStrideY = iStrideY << 4;
371 
372   m_ComplexityAnalysisParam.iFrameComplexity = 0;
373 
374   for (int32_t j = 0; j < iBlockHeight; j ++) {
375     pTmpCur = pPtrY;
376 
377     for (int32_t i = 0; i < iBlockWidth; i++) {
378       iBlockSadH = iBlockSadV = 0x7fffffff; // INT_MAX
379       if (j > 0) {
380         m_pIntraFunc[0] (iMemPredMb, pTmpCur, iStrideY);
381         iBlockSadH = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
382       }
383       if (i > 0) {
384         m_pIntraFunc[1] (iMemPredMb, pTmpCur, iStrideY);
385         iBlockSadV = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
386       }
387       if (i || j)
388         iGomSad += WELS_MIN (iBlockSadH, iBlockSadV);
389 
390       pTmpCur += 16;
391 
392       if (i == iBlockWidth - 1 && ((j + 1) % m_ComplexityAnalysisParam.iMbRowInGom == 0 || j == iBlockHeight - 1)) {
393         m_ComplexityAnalysisParam.pGomComplexity[iIdx] = iGomSad;
394         m_ComplexityAnalysisParam.iFrameComplexity += iGomSad;
395         iIdx++;
396         iGomSad = 0;
397       }
398     }
399 
400     pPtrY += iRowStrideY;
401   }
402   m_ComplexityAnalysisParam.iGomNumInFrame = iIdx;
403 }
404 
405 
GomComplexityAnalysisInter(SPixMap * pSrc,SPixMap * pRef,bool bScrollFlag)406 void CComplexityAnalysisScreen::GomComplexityAnalysisInter (SPixMap* pSrc, SPixMap* pRef, bool bScrollFlag) {
407   int32_t iWidth                  = pSrc->sRect.iRectWidth;
408   int32_t iHeight                 = pSrc->sRect.iRectHeight;
409   int32_t iBlockWidth             = iWidth  >> 4;
410   int32_t iBlockHeight            = iHeight >> 4;
411 
412   int32_t iInterSad, iScrollSad, iBlockSadH, iBlockSadV, iGomSad = 0;
413   int32_t iIdx = 0;
414 
415   int32_t iScrollMvX = m_ComplexityAnalysisParam.sScrollResult.iScrollMvX;
416   int32_t iScrollMvY = m_ComplexityAnalysisParam.sScrollResult.iScrollMvY;
417 
418   uint8_t* pPtrX = NULL, *pPtrY = NULL;
419   int32_t iStrideX = 0, iStrideY = 0;
420   int32_t iRowStrideX = 0, iRowStrideY = 0;
421 
422   uint8_t* pTmpRef = NULL, *pTmpCur = NULL, *pTmpRefScroll = NULL;
423 
424   ENFORCE_STACK_ALIGN_1D (uint8_t, iMemPredMb, 256, 16)
425 
426   pPtrX = (uint8_t*)pRef->pPixel[0];
427   pPtrY = (uint8_t*)pSrc->pPixel[0];
428 
429   iStrideX  = pRef->iStride[0];
430   iStrideY  = pSrc->iStride[0];
431 
432   iRowStrideX  = pRef->iStride[0] << 4;
433   iRowStrideY  = pSrc->iStride[0] << 4;
434 
435   m_ComplexityAnalysisParam.iFrameComplexity = 0;
436 
437   for (int32_t j = 0; j < iBlockHeight; j ++) {
438     pTmpRef  = pPtrX;
439     pTmpCur  = pPtrY;
440 
441     for (int32_t i = 0; i < iBlockWidth; i++) {
442       int32_t iBlockPointX = i << 4;
443       int32_t iBlockPointY = j << 4;
444 
445       iInterSad = m_pSadFunc (pTmpCur, iStrideY, pTmpRef, iStrideX);
446       if (bScrollFlag) {
447         if ((iInterSad != 0) &&
448             (iBlockPointX + iScrollMvX >= 0) && (iBlockPointX + iScrollMvX <= iWidth - 8) &&
449             (iBlockPointY + iScrollMvY >= 0) && (iBlockPointY + iScrollMvY <= iHeight - 8)) {
450           pTmpRefScroll = pTmpRef - iScrollMvY * iStrideX + iScrollMvX;
451           iScrollSad = m_pSadFunc (pTmpCur, iStrideY, pTmpRefScroll, iStrideX);
452 
453           if (iScrollSad < iInterSad) {
454             iInterSad = iScrollSad;
455           }
456         }
457 
458       }
459 
460       iBlockSadH = iBlockSadV = 0x7fffffff; // INT_MAX
461 
462       if (j > 0) {
463         m_pIntraFunc[0] (iMemPredMb, pTmpCur, iStrideY);
464         iBlockSadH = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
465       }
466       if (i > 0) {
467         m_pIntraFunc[1] (iMemPredMb, pTmpCur, iStrideY);
468         iBlockSadV = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
469       }
470 
471       iGomSad += WELS_MIN (WELS_MIN (iBlockSadH, iBlockSadV), iInterSad);
472 
473       if (i == iBlockWidth - 1 && ((j + 1) % m_ComplexityAnalysisParam.iMbRowInGom == 0 || j == iBlockHeight - 1)) {
474         m_ComplexityAnalysisParam.pGomComplexity[iIdx] = iGomSad;
475         m_ComplexityAnalysisParam.iFrameComplexity += iGomSad;
476         iIdx++;
477         iGomSad = 0;
478       }
479 
480       pTmpRef += 16;
481       pTmpCur += 16;
482     }
483     pPtrX += iRowStrideX;
484     pPtrY += iRowStrideY;
485   }
486   m_ComplexityAnalysisParam.iGomNumInFrame = iIdx;
487 }
488 
489 WELSVP_NAMESPACE_END
490