omxVCM4P2_MotionEstimationMB.c revision 0c1bc742181ded4930842b46e9507372f0b1b963
1/**
2 *
3 * File Name:  omxVCM4P2_MotionEstimationMB.c
4 * OpenMAX DL: v1.0.2
5 * Revision:   9641
6 * Date:       Thursday, February 7, 2008
7 *
8 * (c) Copyright 2007-2008 ARM Limited. All Rights Reserved.
9 *
10 *
11 *
12 * Description:
13 * Contains module for motion search 16x16 macroblock
14 *
15 */
16
17#include "omxtypes.h"
18#include "armOMX.h"
19#include "omxVC.h"
20
21#include "armVC.h"
22#include "armCOMM.h"
23
24/**
25 * Function: armVCM4P2_BlockMatch_16x16
26 *
27 * Description:
28 * 16x16 block match wrapper function, calls omxVCM4P2_BlockMatch_Integer_16x16.
29 * If half pel search is enabled it also calls omxVCM4P2_BlockMatch_Half_16x16
30 *
31 * Remarks:
32 *
33 * Parameters:
34 * [in]	pSrcRefBuf	  pointer to the reference Y plane; points to the reference MB that
35 *                    corresponds to the location of the current macroblock in the current
36 *                    plane.
37 * [in]	srcRefStep	  width of the reference plane
38 * [in]	pRefRect	  pointer to the valid rectangular in reference plane. Relative to image origin.
39 *                    It's not limited to the image boundary, but depended on the padding. For example,
40 *                    if you pad 4 pixels outside the image border, then the value for left border
41 *                    can be -4
42 * [in]	pSrcCurrBuf	  pointer to the current macroblock extracted from original plane (linear array,
43 *                    256 entries); must be aligned on an 16-byte boundary.
44 * [in] pCurrPointPos position of the current macroblock in the current plane
45 * [in] pSrcPreMV	  pointer to predicted motion vector; NULL indicates no predicted MV
46 * [in] pSrcPreSAD	  pointer to SAD associated with the predicted MV (referenced by pSrcPreMV); may be set to NULL if unavailable.
47 * [in] pMESpec		  vendor-specific motion estimation specification structure; must have been allocated
48 *                    and then initialized using omxVCM4P2_MEInit prior to calling the block matching
49 *                    function.
50 * [out] pDstMV	      pointer to estimated MV
51 * [out] pDstSAD	  pointer to minimum SAD
52 * *
53 * Return Value:
54 * OMX_Sts_NoErr - no error
55 * OMX_Sts_BadArgErr - bad arguments
56 *
57 */
58static OMXResult armVCM4P2_BlockMatch_16x16(
59     const OMX_U8 *pSrcRefBuf,
60     const OMX_INT srcRefStep,
61     const OMXRect *pRefRect,
62     const OMX_U8 *pSrcCurrBuf,
63     const OMXVCM4P2Coordinate *pCurrPointPos,
64     OMXVCMotionVector *pSrcPreMV,
65     OMX_INT *pSrcPreSAD,
66     void *pMESpec,
67     OMXVCMotionVector *pDstMV,
68     OMX_INT *pDstSAD
69)
70{
71    OMXVCM4P2MEParams *pMEParams = (OMXVCM4P2MEParams *)pMESpec;
72    OMX_INT rndVal;
73
74    rndVal = pMEParams->rndVal;
75
76    omxVCM4P2_BlockMatch_Integer_16x16(
77        pSrcRefBuf,
78        srcRefStep,
79        pRefRect,
80        pSrcCurrBuf,
81        pCurrPointPos,
82        pSrcPreMV,
83        pSrcPreSAD,
84        pMEParams,
85        pDstMV,
86        pDstSAD);
87
88    if (pMEParams->halfPelSearchEnable)
89    {
90        omxVCM4P2_BlockMatch_Half_16x16(
91            pSrcRefBuf,
92            srcRefStep,
93            pRefRect,
94            pSrcCurrBuf,
95            pCurrPointPos,
96            rndVal,
97            pDstMV,
98            pDstSAD);
99    }
100
101    return OMX_Sts_NoErr;
102}
103
104/**
105 * Function: armVCM4P2_BlockMatch_8x8
106 *
107 * Description:
108 * 8x8 block match wrapper function, calls omxVCM4P2_BlockMatch_Integer_8x8.
109 * If half pel search is enabled it also calls omxVCM4P2_BlockMatch_Half_8x8
110 *
111 * Remarks:
112 *
113 * Parameters:
114 * [in]	pSrcRefBuf	  pointer to the reference Y plane; points to the reference MB that
115 *                    corresponds to the location of the current macroblock in the current
116 *                    plane.
117 * [in]	srcRefStep	  width of the reference plane
118 * [in]	pRefRect	  pointer to the valid rectangular in reference plane. Relative to image origin.
119 *                    It's not limited to the image boundary, but depended on the padding. For example,
120 *                    if you pad 4 pixels outside the image border, then the value for left border
121 *                    can be -4
122 * [in]	pSrcCurrBuf	  pointer to the current macroblock extracted from original plane (linear array,
123 *                    256 entries); must be aligned on an 16-byte boundary.
124 * [in] pCurrPointPos position of the current macroblock in the current plane
125 * [in] pSrcPreMV	  pointer to predicted motion vector; NULL indicates no predicted MV
126 * [in] pSrcPreSAD	  pointer to SAD associated with the predicted MV (referenced by pSrcPreMV); may be set to NULL if unavailable.
127 * [in] pMESpec		  vendor-specific motion estimation specification structure; must have been allocated
128 *                    and then initialized using omxVCM4P2_MEInit prior to calling the block matching
129 *                    function.
130 * [out] pDstMV	      pointer to estimated MV
131 * [out] pDstSAD	  pointer to minimum SAD
132 * *
133 * Return Value:
134 * OMX_Sts_NoErr - no error
135 * OMX_Sts_BadArgErr - bad arguments
136 *
137 */
138static OMXResult armVCM4P2_BlockMatch_8x8(
139     const OMX_U8 *pSrcRefBuf,
140     OMX_INT srcRefStep,
141     const OMXRect *pRefRect,
142     const OMX_U8 *pSrcCurrBuf,
143     const OMXVCM4P2Coordinate *pCurrPointPos,
144     OMXVCMotionVector *pSrcPreMV,
145     OMX_INT *pSrcPreSAD,
146     void *pMESpec,
147     OMXVCMotionVector *pSrcDstMV,
148     OMX_INT *pDstSAD
149)
150{
151    OMXVCM4P2MEParams *pMEParams = (OMXVCM4P2MEParams *)pMESpec;
152    OMX_INT rndVal;
153
154    rndVal = pMEParams->rndVal;
155
156    omxVCM4P2_BlockMatch_Integer_8x8(
157        pSrcRefBuf,
158        srcRefStep,
159        pRefRect,
160        pSrcCurrBuf,
161        pCurrPointPos,
162        pSrcPreMV,
163        pSrcPreSAD,
164        pMEParams,
165        pSrcDstMV,
166        pDstSAD);
167
168    if (pMEParams->halfPelSearchEnable)
169    {
170        omxVCM4P2_BlockMatch_Half_8x8(
171            pSrcRefBuf,
172            srcRefStep,
173            pRefRect,
174            pSrcCurrBuf,
175            pCurrPointPos,
176            rndVal,
177            pSrcDstMV,
178            pDstSAD);
179    }
180
181    return OMX_Sts_NoErr;
182}
183
184
185/**
186 * Function:  omxVCM4P2_MotionEstimationMB   (6.2.4.3.1)
187 *
188 * Description:
189 * Performs motion search for a 16x16 macroblock.  Selects best motion search
190 * strategy from among inter-1MV, inter-4MV, and intra modes.  Supports
191 * integer and half pixel resolution.
192 *
193 * Input Arguments:
194 *
195 *   pSrcCurrBuf - pointer to the top-left corner of the current MB in the
196 *            original picture plane; must be aligned on a 16-byte boundary.
197 *            The function does not expect source data outside the region
198 *            bounded by the MB to be available; for example it is not
199 *            necessary for the caller to guarantee the availability of
200 *            pSrcCurrBuf[-SrcCurrStep], i.e., the row of pixels above the MB
201 *            to be processed.
202 *   srcCurrStep - width of the original picture plane, in terms of full
203 *            pixels; must be a multiple of 16.
204 *   pSrcRefBuf - pointer to the reference Y plane; points to the reference
205 *            plane location corresponding to the location of the current
206 *            macroblock in the current plane; must be aligned on a 16-byte
207 *            boundary.
208 *   srcRefStep - width of the reference picture plane, in terms of full
209 *            pixels; must be a multiple of 16.
210 *   pRefRect - reference plane valid region rectangle, specified relative to
211 *            the image origin
212 *   pCurrPointPos - position of the current macroblock in the current plane
213 *   pMESpec - pointer to the vendor-specific motion estimation specification
214 *            structure; must be allocated and then initialized using
215 *            omxVCM4P2_MEInit prior to calling this function.
216 *   pMBInfo - array, of dimension four, containing pointers to information
217 *            associated with four nearby MBs:
218 *            -   pMBInfo[0] - pointer to left MB information
219 *            -   pMBInfo[1] - pointer to top MB information
220 *            -   pMBInfo[2] - pointer to top-left MB information
221 *            -   pMBInfo[3] - pointer to top-right MB information
222 *            Any pointer in the array may be set equal to NULL if the
223 *            corresponding MB doesn't exist.  For each MB, the following structure
224 *            members are used:
225 *            -   mbType - macroblock type, either OMX_VC_INTRA, OMX_VC_INTER, or
226 *                OMX_VC_INTER4V
227 *            -   pMV0[2][2] - estimated motion vectors; represented
228 *                in 1/2 pixel units
229 *            -   sliceID - number of the slice to which the MB belongs
230 *   pSrcDstMBCurr - pointer to information structure for the current MB.
231 *            The following entries should be set prior to calling the
232 *            function: sliceID - the number of the slice the to which the
233 *            current MB belongs.  The structure elements cbpy and cbpc are
234 *            ignored.
235 *
236 * Output Arguments:
237 *
238 *   pSrcDstMBCurr - pointer to updated information structure for the current
239 *            MB after MB-level motion estimation has been completed.  The
240 *            following structure members are updated by the ME function:
241 *              -  mbType - macroblock type: OMX_VC_INTRA, OMX_VC_INTER, or
242 *                 OMX_VC_INTER4V.
243 *              -  pMV0[2][2] - estimated motion vectors; represented in
244 *                 terms of 1/2 pel units.
245 *              -  pMVPred[2][2] - predicted motion vectors; represented
246 *                 in terms of 1/2 pel units.
247 *            The structure members cbpy and cbpc are not updated by the function.
248 *   pDstSAD - pointer to the minimum SAD for INTER1V, or sum of minimum SADs
249 *            for INTER4V
250 *   pDstBlockSAD - pointer to an array of SAD values for each of the four
251 *            8x8 luma blocks in the MB.  The block SADs are in scan order for
252 *            each MB.
253 *
254 * Return Value:
255 *
256 *    OMX_Sts_NoErr - no error
257 *    OMX_Sts_BadArgErr - bad arguments.  Returned if one or more of the
258 *              following conditions is true:
259 *    -    at least one of the following pointers is NULL: pSrcCurrBuf,
260 *              pSrcRefBuf, pRefRect, pCurrPointPos, pMBInter, pMBIntra,
261 *              pSrcDstMBCurr, or pDstSAD.
262 *
263 */
264
265OMXResult omxVCM4P2_MotionEstimationMB (
266    const OMX_U8 *pSrcCurrBuf,
267    OMX_S32 srcCurrStep,
268    const OMX_U8 *pSrcRefBuf,
269    OMX_S32 srcRefStep,
270    const OMXRect*pRefRect,
271    const OMXVCM4P2Coordinate *pCurrPointPos,
272    void *pMESpec,
273    const OMXVCM4P2MBInfoPtr *pMBInfo,
274    OMXVCM4P2MBInfo *pSrcDstMBCurr,
275    OMX_U16 *pDstSAD,
276    OMX_U16 *pDstBlockSAD
277)
278{
279
280    OMX_INT intraSAD, average, count, index, x, y;
281    OMXVCMotionVector dstMV16x16;
282    OMX_INT           dstSAD16x16;
283    OMX_INT           dstSAD8x8;
284    OMXVCM4P2MEParams  *pMEParams;
285	OMXVCM4P2Coordinate TempCurrPointPos;
286    OMXVCM4P2Coordinate *pTempCurrPointPos;
287    OMX_U8 aTempSrcCurrBuf[271];
288    OMX_U8 *pTempSrcCurrBuf;
289    OMX_U8 *pDst;
290    OMX_U8 aDst[71];
291    OMX_S32 dstStep = 8;
292    OMX_INT predictType;
293	OMX_S32 Sad;
294    const OMX_U8 *pTempSrcRefBuf;
295    OMXVCMotionVector* pSrcCandMV1[4];
296    OMXVCMotionVector* pSrcCandMV2[4];
297    OMXVCMotionVector* pSrcCandMV3[4];
298
299    /* Argument error checks */
300    armRetArgErrIf(!armIs16ByteAligned(pSrcCurrBuf), OMX_Sts_BadArgErr);
301	armRetArgErrIf(!armIs16ByteAligned(pSrcRefBuf), OMX_Sts_BadArgErr);
302    armRetArgErrIf(((srcCurrStep % 16) || (srcRefStep % 16)), OMX_Sts_BadArgErr);
303	armRetArgErrIf(pSrcCurrBuf == NULL, OMX_Sts_BadArgErr);
304	armRetArgErrIf(pSrcRefBuf == NULL, OMX_Sts_BadArgErr);
305    armRetArgErrIf(pRefRect == NULL, OMX_Sts_BadArgErr);
306    armRetArgErrIf(pCurrPointPos == NULL, OMX_Sts_BadArgErr);
307    armRetArgErrIf(pSrcDstMBCurr == NULL, OMX_Sts_BadArgErr);
308    armRetArgErrIf(pDstSAD == NULL, OMX_Sts_BadArgErr);
309
310
311    pTempCurrPointPos = &(TempCurrPointPos);
312    pTempSrcCurrBuf = armAlignTo16Bytes(aTempSrcCurrBuf);
313    pMEParams = (OMXVCM4P2MEParams *)pMESpec;
314    pTempCurrPointPos->x = pCurrPointPos->x;
315    pTempCurrPointPos->y = pCurrPointPos->y;
316    pSrcDstMBCurr->mbType = OMX_VC_INTER;
317
318    /* Preparing a linear buffer for block match */
319    for (y = 0, index = count = 0; y < 16; y++, index += srcCurrStep - 16)
320    {
321        for(x = 0; x < 16; x++, count++, index++)
322        {
323            pTempSrcCurrBuf[count] = pSrcCurrBuf[index];
324        }
325    }
326    for(y = 0, index = 0; y < 2; y++)
327    {
328        for(x = 0; x < 2; x++,index++)
329        {
330            if((pMBInfo[0] != NULL) && (pMBInfo[0]->mbType != OMX_VC_INTRA))
331            {
332               pSrcCandMV1[index] = &(pMBInfo[0]->pMV0[y][x]);
333            }
334            else
335            {
336               pSrcCandMV1[index] = NULL;
337            }
338            if((pMBInfo[1] != NULL) && (pMBInfo[1]->mbType != OMX_VC_INTRA))
339            {
340               pSrcCandMV2[index] = &(pMBInfo[1]->pMV0[y][x]);
341            }
342            else
343            {
344               pSrcCandMV2[index] = NULL;
345            }
346            if((pMBInfo[3] != NULL) && (pMBInfo[3]->mbType != OMX_VC_INTRA))
347            {
348               pSrcCandMV3[index] = &(pMBInfo[3]->pMV0[y][x]);
349            }
350            else
351            {
352               pSrcCandMV3[index] = NULL;
353            }
354        }
355    }
356	/* Calculating SAD at MV(0,0) */
357	armVCCOMM_SAD(pTempSrcCurrBuf,
358					  16,
359					  pSrcRefBuf,
360					  srcRefStep,
361					  &Sad,
362					  16,
363					  16);
364	*pDstSAD = Sad;
365
366    /* Mode decision for NOT_CODED MB */
367	if(*pDstSAD == 0)
368	{
369        pSrcDstMBCurr->pMV0[0][0].dx = 0;
370        pSrcDstMBCurr->pMV0[0][0].dy = 0;
371        *pDstSAD   = 0;
372		return OMX_Sts_NoErr;
373	}
374
375    omxVCM4P2_FindMVpred(
376                    &(pSrcDstMBCurr->pMV0[0][0]),
377                    pSrcCandMV1[0],
378                    pSrcCandMV2[0],
379                    pSrcCandMV3[0],
380                    &(pSrcDstMBCurr->pMVPred[0][0]),
381                    NULL,
382                    0);
383
384    /* Inter 1 MV */
385    armVCM4P2_BlockMatch_16x16(
386        pSrcRefBuf,
387        srcRefStep,
388        pRefRect,
389        pTempSrcCurrBuf,
390        pCurrPointPos,
391        &(pSrcDstMBCurr->pMVPred[0][0]),
392        NULL,
393        pMEParams,
394        &dstMV16x16,
395        &dstSAD16x16);
396
397    /* Initialize all with 1 MV values */
398    pSrcDstMBCurr->pMV0[0][0].dx = dstMV16x16.dx;
399    pSrcDstMBCurr->pMV0[0][0].dy = dstMV16x16.dy;
400    pSrcDstMBCurr->pMV0[0][1].dx = dstMV16x16.dx;
401    pSrcDstMBCurr->pMV0[0][1].dy = dstMV16x16.dy;
402    pSrcDstMBCurr->pMV0[1][0].dx = dstMV16x16.dx;
403    pSrcDstMBCurr->pMV0[1][0].dy = dstMV16x16.dy;
404    pSrcDstMBCurr->pMV0[1][1].dx = dstMV16x16.dx;
405    pSrcDstMBCurr->pMV0[1][1].dy = dstMV16x16.dy;
406
407    *pDstSAD   = dstSAD16x16;
408
409    if (pMEParams->searchEnable8x8)
410    {
411        /* Inter 4MV */
412        armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
413                                      srcRefStep, pRefRect,
414                                      pTempSrcCurrBuf, pTempCurrPointPos,
415                                      &(pSrcDstMBCurr->pMVPred[0][0]), NULL,
416                                      pMEParams, &(pSrcDstMBCurr->pMV0[0][0]),
417                                      &dstSAD8x8
418                                      );
419        pDstBlockSAD[0] = dstSAD8x8;
420        *pDstSAD = dstSAD8x8;
421        pTempCurrPointPos->x += 8;
422        pSrcRefBuf += 8;
423        omxVCM4P2_FindMVpred(
424                    &(pSrcDstMBCurr->pMV0[0][1]),
425                    pSrcCandMV1[1],
426                    pSrcCandMV2[1],
427                    pSrcCandMV3[1],
428                    &(pSrcDstMBCurr->pMVPred[0][1]),
429                    NULL,
430                    1);
431
432        armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
433                                      srcRefStep, pRefRect,
434                                      pTempSrcCurrBuf, pTempCurrPointPos,
435                                      &(pSrcDstMBCurr->pMVPred[0][1]), NULL,
436                                      pMEParams, &(pSrcDstMBCurr->pMV0[0][1]),
437                                      &dstSAD8x8
438                                      );
439        pDstBlockSAD[1] = dstSAD8x8;
440        *pDstSAD += dstSAD8x8;
441        pTempCurrPointPos->x -= 8;
442        pTempCurrPointPos->y += 8;
443        pSrcRefBuf += (srcRefStep * 8) - 8;
444
445        omxVCM4P2_FindMVpred(
446                    &(pSrcDstMBCurr->pMV0[1][0]),
447                    pSrcCandMV1[2],
448                    pSrcCandMV2[2],
449                    pSrcCandMV3[2],
450                    &(pSrcDstMBCurr->pMVPred[1][0]),
451                    NULL,
452                    2);
453        armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
454                                      srcRefStep, pRefRect,
455                                      pTempSrcCurrBuf, pTempCurrPointPos,
456                                      &(pSrcDstMBCurr->pMVPred[1][0]), NULL,
457                                      pMEParams, &(pSrcDstMBCurr->pMV0[1][0]),
458                                      &dstSAD8x8
459                                      );
460        pDstBlockSAD[2] = dstSAD8x8;
461        *pDstSAD += dstSAD8x8;
462        pTempCurrPointPos->x += 8;
463        pSrcRefBuf += 8;
464        omxVCM4P2_FindMVpred(
465                    &(pSrcDstMBCurr->pMV0[1][1]),
466                    pSrcCandMV1[3],
467                    pSrcCandMV2[3],
468                    pSrcCandMV3[3],
469                    &(pSrcDstMBCurr->pMVPred[1][1]),
470                    NULL,
471                    3);
472        armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
473                                      srcRefStep, pRefRect,
474                                      pTempSrcCurrBuf, pTempCurrPointPos,
475                                      &(pSrcDstMBCurr->pMVPred[1][1]), NULL,
476                                      pMEParams, &(pSrcDstMBCurr->pMV0[1][1]),
477                                      &dstSAD8x8
478                                      );
479        pDstBlockSAD[3] = dstSAD8x8;
480        *pDstSAD += dstSAD8x8;
481
482
483        /* Checking if 4MV is equal to 1MV */
484        if (
485            (pSrcDstMBCurr->pMV0[0][0].dx != dstMV16x16.dx) ||
486            (pSrcDstMBCurr->pMV0[0][0].dy != dstMV16x16.dy) ||
487            (pSrcDstMBCurr->pMV0[0][1].dx != dstMV16x16.dx) ||
488            (pSrcDstMBCurr->pMV0[0][1].dy != dstMV16x16.dy) ||
489            (pSrcDstMBCurr->pMV0[1][0].dx != dstMV16x16.dx) ||
490            (pSrcDstMBCurr->pMV0[1][0].dy != dstMV16x16.dy) ||
491            (pSrcDstMBCurr->pMV0[1][1].dx != dstMV16x16.dx) ||
492            (pSrcDstMBCurr->pMV0[1][1].dy != dstMV16x16.dy)
493           )
494        {
495            /* select the 4 MV */
496            pSrcDstMBCurr->mbType = OMX_VC_INTER4V;
497        }
498    }
499
500    /* finding the error in intra mode */
501    for (count = 0, average = 0; count < 256 ; count++)
502    {
503        average = average + pTempSrcCurrBuf[count];
504    }
505    average = average/256;
506
507	intraSAD = 0;
508
509    /* Intra SAD calculation */
510    for (count = 0; count < 256 ; count++)
511    {
512        intraSAD += armAbs ((pTempSrcCurrBuf[count]) - (average));
513    }
514
515	/* Using the MPEG4 VM formula for intra/inter mode decision
516	   Var < (SAD - 2*NB) where NB = N^2 is the number of pixels
517	   of the macroblock.*/
518
519    if (intraSAD <= (*pDstSAD - 512))
520    {
521        pSrcDstMBCurr->mbType = OMX_VC_INTRA;
522        pSrcDstMBCurr->pMV0[0][0].dx = 0;
523        pSrcDstMBCurr->pMV0[0][0].dy = 0;
524        *pDstSAD   = intraSAD;
525        pDstBlockSAD[0] = 0xFFFF;
526        pDstBlockSAD[1] = 0xFFFF;
527        pDstBlockSAD[2] = 0xFFFF;
528        pDstBlockSAD[3] = 0xFFFF;
529    }
530
531    if(pSrcDstMBCurr->mbType == OMX_VC_INTER)
532    {
533      pTempSrcRefBuf = pSrcRefBuf + (srcRefStep * dstMV16x16.dy) + dstMV16x16.dx;
534
535      if((dstMV16x16.dx & 0x1) && (dstMV16x16.dy & 0x1))
536      {
537        predictType = OMX_VC_HALF_PIXEL_XY;
538      }
539      else if(dstMV16x16.dx & 0x1)
540      {
541        predictType = OMX_VC_HALF_PIXEL_X;
542      }
543      else if(dstMV16x16.dy & 0x1)
544      {
545        predictType = OMX_VC_HALF_PIXEL_Y;
546      }
547      else
548      {
549        predictType = OMX_VC_INTEGER_PIXEL;
550      }
551
552      pDst = armAlignTo8Bytes(&(aDst[0]));
553      /* Calculating Block SAD at MV(dstMV16x16.dx,dstMV16x16.dy) */
554	  /* Block 0 */
555      omxVCM4P2_MCReconBlock(pTempSrcRefBuf,
556	                             srcRefStep,
557                                 NULL,
558                                 pDst,
559                                 dstStep,
560                                 predictType,
561                                 pMEParams->rndVal);
562
563      armVCCOMM_SAD(pTempSrcCurrBuf,
564                        16,
565                        pDst,
566                        dstStep,
567                        &Sad,
568                        8,
569                        8);
570      pDstBlockSAD[0] = Sad;
571
572      /* Block 1 */
573      omxVCM4P2_MCReconBlock(pTempSrcRefBuf + 8,
574                                 srcRefStep,
575                                 NULL,
576                                 pDst,
577                                 dstStep,
578                                 predictType,
579                                 pMEParams->rndVal);
580
581      armVCCOMM_SAD(pTempSrcCurrBuf + 8,
582                        16,
583                        pDst,
584                        dstStep,
585                        &Sad,
586                        8,
587                        8);
588      pDstBlockSAD[1] = Sad;
589
590      /* Block 2 */
591      omxVCM4P2_MCReconBlock(pTempSrcRefBuf + (srcRefStep*8),
592                                 srcRefStep,
593                                 NULL,
594                                 pDst,
595                                 dstStep,
596                                 predictType,
597                                 pMEParams->rndVal);
598
599      armVCCOMM_SAD(pTempSrcCurrBuf + (16*8),
600                        16,
601                        pDst,
602                        dstStep,
603                        &Sad,
604                        8,
605                        8);
606      pDstBlockSAD[2] = Sad;
607
608	  /* Block 3 */
609      omxVCM4P2_MCReconBlock(pTempSrcRefBuf + (srcRefStep*8) + 8,
610                                 srcRefStep,
611                                 NULL,
612                                 pDst,
613                                 dstStep,
614                                 predictType,
615                                 pMEParams->rndVal);
616
617      armVCCOMM_SAD(pTempSrcCurrBuf + (16*8) + 8,
618                        16,
619                        pDst,
620                        dstStep,
621                        &Sad,
622                        8,
623                        8);
624      pDstBlockSAD[3] = Sad;
625    }
626    return OMX_Sts_NoErr;
627}
628
629/* End of file */
630
631