blob: f9bb297c169238b726ddb43a48cdccb551572a0a [file] [log] [blame]
/*
* Copyright (C) 2007-2008 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
*
* File Name: omxVCM4P2_MotionEstimationMB.c
* OpenMAX DL: v1.0.2
* Revision: 9641
* Date: Thursday, February 7, 2008
*
*
*
*
* Description:
* Contains module for motion search 16x16 macroblock
*
*/
#include "omxtypes.h"
#include "armOMX.h"
#include "omxVC.h"
#include "armVC.h"
#include "armCOMM.h"
/**
* Function: armVCM4P2_BlockMatch_16x16
*
* Description:
* 16x16 block match wrapper function, calls omxVCM4P2_BlockMatch_Integer_16x16.
* If half pel search is enabled it also calls omxVCM4P2_BlockMatch_Half_16x16
*
* Remarks:
*
* Parameters:
* [in] pSrcRefBuf pointer to the reference Y plane; points to the reference MB that
* corresponds to the location of the current macroblock in the current
* plane.
* [in] srcRefStep width of the reference plane
* [in] pRefRect pointer to the valid rectangular in reference plane. Relative to image origin.
* It's not limited to the image boundary, but depended on the padding. For example,
* if you pad 4 pixels outside the image border, then the value for left border
* can be -4
* [in] pSrcCurrBuf pointer to the current macroblock extracted from original plane (linear array,
* 256 entries); must be aligned on an 16-byte boundary.
* [in] pCurrPointPos position of the current macroblock in the current plane
* [in] pSrcPreMV pointer to predicted motion vector; NULL indicates no predicted MV
* [in] pSrcPreSAD pointer to SAD associated with the predicted MV (referenced by pSrcPreMV); may be set to NULL if unavailable.
* [in] pMESpec vendor-specific motion estimation specification structure; must have been allocated
* and then initialized using omxVCM4P2_MEInit prior to calling the block matching
* function.
* [out] pDstMV pointer to estimated MV
* [out] pDstSAD pointer to minimum SAD
* *
* Return Value:
* OMX_Sts_NoErr - no error
* OMX_Sts_BadArgErr - bad arguments
*
*/
static OMXResult armVCM4P2_BlockMatch_16x16(
const OMX_U8 *pSrcRefBuf,
const OMX_INT srcRefStep,
const OMXRect *pRefRect,
const OMX_U8 *pSrcCurrBuf,
const OMXVCM4P2Coordinate *pCurrPointPos,
OMXVCMotionVector *pSrcPreMV,
OMX_INT *pSrcPreSAD,
void *pMESpec,
OMXVCMotionVector *pDstMV,
OMX_INT *pDstSAD
)
{
OMXVCM4P2MEParams *pMEParams = (OMXVCM4P2MEParams *)pMESpec;
OMX_INT rndVal;
rndVal = pMEParams->rndVal;
omxVCM4P2_BlockMatch_Integer_16x16(
pSrcRefBuf,
srcRefStep,
pRefRect,
pSrcCurrBuf,
pCurrPointPos,
pSrcPreMV,
pSrcPreSAD,
pMEParams,
pDstMV,
pDstSAD);
if (pMEParams->halfPelSearchEnable)
{
omxVCM4P2_BlockMatch_Half_16x16(
pSrcRefBuf,
srcRefStep,
pRefRect,
pSrcCurrBuf,
pCurrPointPos,
rndVal,
pDstMV,
pDstSAD);
}
return OMX_Sts_NoErr;
}
/**
* Function: armVCM4P2_BlockMatch_8x8
*
* Description:
* 8x8 block match wrapper function, calls omxVCM4P2_BlockMatch_Integer_8x8.
* If half pel search is enabled it also calls omxVCM4P2_BlockMatch_Half_8x8
*
* Remarks:
*
* Parameters:
* [in] pSrcRefBuf pointer to the reference Y plane; points to the reference MB that
* corresponds to the location of the current macroblock in the current
* plane.
* [in] srcRefStep width of the reference plane
* [in] pRefRect pointer to the valid rectangular in reference plane. Relative to image origin.
* It's not limited to the image boundary, but depended on the padding. For example,
* if you pad 4 pixels outside the image border, then the value for left border
* can be -4
* [in] pSrcCurrBuf pointer to the current macroblock extracted from original plane (linear array,
* 256 entries); must be aligned on an 16-byte boundary.
* [in] pCurrPointPos position of the current macroblock in the current plane
* [in] pSrcPreMV pointer to predicted motion vector; NULL indicates no predicted MV
* [in] pSrcPreSAD pointer to SAD associated with the predicted MV (referenced by pSrcPreMV); may be set to NULL if unavailable.
* [in] pMESpec vendor-specific motion estimation specification structure; must have been allocated
* and then initialized using omxVCM4P2_MEInit prior to calling the block matching
* function.
* [out] pDstMV pointer to estimated MV
* [out] pDstSAD pointer to minimum SAD
* *
* Return Value:
* OMX_Sts_NoErr - no error
* OMX_Sts_BadArgErr - bad arguments
*
*/
static OMXResult armVCM4P2_BlockMatch_8x8(
const OMX_U8 *pSrcRefBuf,
OMX_INT srcRefStep,
const OMXRect *pRefRect,
const OMX_U8 *pSrcCurrBuf,
const OMXVCM4P2Coordinate *pCurrPointPos,
OMXVCMotionVector *pSrcPreMV,
OMX_INT *pSrcPreSAD,
void *pMESpec,
OMXVCMotionVector *pSrcDstMV,
OMX_INT *pDstSAD
)
{
OMXVCM4P2MEParams *pMEParams = (OMXVCM4P2MEParams *)pMESpec;
OMX_INT rndVal;
rndVal = pMEParams->rndVal;
omxVCM4P2_BlockMatch_Integer_8x8(
pSrcRefBuf,
srcRefStep,
pRefRect,
pSrcCurrBuf,
pCurrPointPos,
pSrcPreMV,
pSrcPreSAD,
pMEParams,
pSrcDstMV,
pDstSAD);
if (pMEParams->halfPelSearchEnable)
{
omxVCM4P2_BlockMatch_Half_8x8(
pSrcRefBuf,
srcRefStep,
pRefRect,
pSrcCurrBuf,
pCurrPointPos,
rndVal,
pSrcDstMV,
pDstSAD);
}
return OMX_Sts_NoErr;
}
/**
* Function: omxVCM4P2_MotionEstimationMB (6.2.4.3.1)
*
* Description:
* Performs motion search for a 16x16 macroblock. Selects best motion search
* strategy from among inter-1MV, inter-4MV, and intra modes. Supports
* integer and half pixel resolution.
*
* Input Arguments:
*
* pSrcCurrBuf - pointer to the top-left corner of the current MB in the
* original picture plane; must be aligned on a 16-byte boundary.
* The function does not expect source data outside the region
* bounded by the MB to be available; for example it is not
* necessary for the caller to guarantee the availability of
* pSrcCurrBuf[-SrcCurrStep], i.e., the row of pixels above the MB
* to be processed.
* srcCurrStep - width of the original picture plane, in terms of full
* pixels; must be a multiple of 16.
* pSrcRefBuf - pointer to the reference Y plane; points to the reference
* plane location corresponding to the location of the current
* macroblock in the current plane; must be aligned on a 16-byte
* boundary.
* srcRefStep - width of the reference picture plane, in terms of full
* pixels; must be a multiple of 16.
* pRefRect - reference plane valid region rectangle, specified relative to
* the image origin
* pCurrPointPos - position of the current macroblock in the current plane
* pMESpec - pointer to the vendor-specific motion estimation specification
* structure; must be allocated and then initialized using
* omxVCM4P2_MEInit prior to calling this function.
* pMBInfo - array, of dimension four, containing pointers to information
* associated with four nearby MBs:
* - pMBInfo[0] - pointer to left MB information
* - pMBInfo[1] - pointer to top MB information
* - pMBInfo[2] - pointer to top-left MB information
* - pMBInfo[3] - pointer to top-right MB information
* Any pointer in the array may be set equal to NULL if the
* corresponding MB doesn't exist. For each MB, the following structure
* members are used:
* - mbType - macroblock type, either OMX_VC_INTRA, OMX_VC_INTER, or
* OMX_VC_INTER4V
* - pMV0[2][2] - estimated motion vectors; represented
* in 1/2 pixel units
* - sliceID - number of the slice to which the MB belongs
* pSrcDstMBCurr - pointer to information structure for the current MB.
* The following entries should be set prior to calling the
* function: sliceID - the number of the slice the to which the
* current MB belongs. The structure elements cbpy and cbpc are
* ignored.
*
* Output Arguments:
*
* pSrcDstMBCurr - pointer to updated information structure for the current
* MB after MB-level motion estimation has been completed. The
* following structure members are updated by the ME function:
* - mbType - macroblock type: OMX_VC_INTRA, OMX_VC_INTER, or
* OMX_VC_INTER4V.
* - pMV0[2][2] - estimated motion vectors; represented in
* terms of 1/2 pel units.
* - pMVPred[2][2] - predicted motion vectors; represented
* in terms of 1/2 pel units.
* The structure members cbpy and cbpc are not updated by the function.
* pDstSAD - pointer to the minimum SAD for INTER1V, or sum of minimum SADs
* for INTER4V
* pDstBlockSAD - pointer to an array of SAD values for each of the four
* 8x8 luma blocks in the MB. The block SADs are in scan order for
* each MB.
*
* Return Value:
*
* OMX_Sts_NoErr - no error
* OMX_Sts_BadArgErr - bad arguments. Returned if one or more of the
* following conditions is true:
* - at least one of the following pointers is NULL: pSrcCurrBuf,
* pSrcRefBuf, pRefRect, pCurrPointPos, pMBInter, pMBIntra,
* pSrcDstMBCurr, or pDstSAD.
*
*/
OMXResult omxVCM4P2_MotionEstimationMB (
const OMX_U8 *pSrcCurrBuf,
OMX_S32 srcCurrStep,
const OMX_U8 *pSrcRefBuf,
OMX_S32 srcRefStep,
const OMXRect*pRefRect,
const OMXVCM4P2Coordinate *pCurrPointPos,
void *pMESpec,
const OMXVCM4P2MBInfoPtr *pMBInfo,
OMXVCM4P2MBInfo *pSrcDstMBCurr,
OMX_U16 *pDstSAD,
OMX_U16 *pDstBlockSAD
)
{
OMX_INT intraSAD, average, count, index, x, y;
OMXVCMotionVector dstMV16x16;
OMX_INT dstSAD16x16;
OMX_INT dstSAD8x8;
OMXVCM4P2MEParams *pMEParams;
OMXVCM4P2Coordinate TempCurrPointPos;
OMXVCM4P2Coordinate *pTempCurrPointPos;
OMX_U8 aTempSrcCurrBuf[271];
OMX_U8 *pTempSrcCurrBuf;
OMX_U8 *pDst;
OMX_U8 aDst[71];
OMX_S32 dstStep = 8;
OMX_INT predictType;
OMX_S32 Sad;
const OMX_U8 *pTempSrcRefBuf;
OMXVCMotionVector* pSrcCandMV1[4];
OMXVCMotionVector* pSrcCandMV2[4];
OMXVCMotionVector* pSrcCandMV3[4];
/* Argument error checks */
armRetArgErrIf(!armIs16ByteAligned(pSrcCurrBuf), OMX_Sts_BadArgErr);
armRetArgErrIf(!armIs16ByteAligned(pSrcRefBuf), OMX_Sts_BadArgErr);
armRetArgErrIf(((srcCurrStep % 16) || (srcRefStep % 16)), OMX_Sts_BadArgErr);
armRetArgErrIf(pSrcCurrBuf == NULL, OMX_Sts_BadArgErr);
armRetArgErrIf(pSrcRefBuf == NULL, OMX_Sts_BadArgErr);
armRetArgErrIf(pRefRect == NULL, OMX_Sts_BadArgErr);
armRetArgErrIf(pCurrPointPos == NULL, OMX_Sts_BadArgErr);
armRetArgErrIf(pSrcDstMBCurr == NULL, OMX_Sts_BadArgErr);
armRetArgErrIf(pDstSAD == NULL, OMX_Sts_BadArgErr);
pTempCurrPointPos = &(TempCurrPointPos);
pTempSrcCurrBuf = armAlignTo16Bytes(aTempSrcCurrBuf);
pMEParams = (OMXVCM4P2MEParams *)pMESpec;
pTempCurrPointPos->x = pCurrPointPos->x;
pTempCurrPointPos->y = pCurrPointPos->y;
pSrcDstMBCurr->mbType = OMX_VC_INTER;
/* Preparing a linear buffer for block match */
for (y = 0, index = count = 0; y < 16; y++, index += srcCurrStep - 16)
{
for(x = 0; x < 16; x++, count++, index++)
{
pTempSrcCurrBuf[count] = pSrcCurrBuf[index];
}
}
for(y = 0, index = 0; y < 2; y++)
{
for(x = 0; x < 2; x++,index++)
{
if((pMBInfo[0] != NULL) && (pMBInfo[0]->mbType != OMX_VC_INTRA))
{
pSrcCandMV1[index] = &(pMBInfo[0]->pMV0[y][x]);
}
else
{
pSrcCandMV1[index] = NULL;
}
if((pMBInfo[1] != NULL) && (pMBInfo[1]->mbType != OMX_VC_INTRA))
{
pSrcCandMV2[index] = &(pMBInfo[1]->pMV0[y][x]);
}
else
{
pSrcCandMV2[index] = NULL;
}
if((pMBInfo[3] != NULL) && (pMBInfo[3]->mbType != OMX_VC_INTRA))
{
pSrcCandMV3[index] = &(pMBInfo[3]->pMV0[y][x]);
}
else
{
pSrcCandMV3[index] = NULL;
}
}
}
/* Calculating SAD at MV(0,0) */
armVCCOMM_SAD(pTempSrcCurrBuf,
16,
pSrcRefBuf,
srcRefStep,
&Sad,
16,
16);
*pDstSAD = Sad;
/* Mode decision for NOT_CODED MB */
if(*pDstSAD == 0)
{
pSrcDstMBCurr->pMV0[0][0].dx = 0;
pSrcDstMBCurr->pMV0[0][0].dy = 0;
*pDstSAD = 0;
return OMX_Sts_NoErr;
}
omxVCM4P2_FindMVpred(
&(pSrcDstMBCurr->pMV0[0][0]),
pSrcCandMV1[0],
pSrcCandMV2[0],
pSrcCandMV3[0],
&(pSrcDstMBCurr->pMVPred[0][0]),
NULL,
0);
/* Inter 1 MV */
armVCM4P2_BlockMatch_16x16(
pSrcRefBuf,
srcRefStep,
pRefRect,
pTempSrcCurrBuf,
pCurrPointPos,
&(pSrcDstMBCurr->pMVPred[0][0]),
NULL,
pMEParams,
&dstMV16x16,
&dstSAD16x16);
/* Initialize all with 1 MV values */
pSrcDstMBCurr->pMV0[0][0].dx = dstMV16x16.dx;
pSrcDstMBCurr->pMV0[0][0].dy = dstMV16x16.dy;
pSrcDstMBCurr->pMV0[0][1].dx = dstMV16x16.dx;
pSrcDstMBCurr->pMV0[0][1].dy = dstMV16x16.dy;
pSrcDstMBCurr->pMV0[1][0].dx = dstMV16x16.dx;
pSrcDstMBCurr->pMV0[1][0].dy = dstMV16x16.dy;
pSrcDstMBCurr->pMV0[1][1].dx = dstMV16x16.dx;
pSrcDstMBCurr->pMV0[1][1].dy = dstMV16x16.dy;
*pDstSAD = dstSAD16x16;
if (pMEParams->searchEnable8x8)
{
/* Inter 4MV */
armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
srcRefStep, pRefRect,
pTempSrcCurrBuf, pTempCurrPointPos,
&(pSrcDstMBCurr->pMVPred[0][0]), NULL,
pMEParams, &(pSrcDstMBCurr->pMV0[0][0]),
&dstSAD8x8
);
pDstBlockSAD[0] = dstSAD8x8;
*pDstSAD = dstSAD8x8;
pTempCurrPointPos->x += 8;
pSrcRefBuf += 8;
omxVCM4P2_FindMVpred(
&(pSrcDstMBCurr->pMV0[0][1]),
pSrcCandMV1[1],
pSrcCandMV2[1],
pSrcCandMV3[1],
&(pSrcDstMBCurr->pMVPred[0][1]),
NULL,
1);
armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
srcRefStep, pRefRect,
pTempSrcCurrBuf, pTempCurrPointPos,
&(pSrcDstMBCurr->pMVPred[0][1]), NULL,
pMEParams, &(pSrcDstMBCurr->pMV0[0][1]),
&dstSAD8x8
);
pDstBlockSAD[1] = dstSAD8x8;
*pDstSAD += dstSAD8x8;
pTempCurrPointPos->x -= 8;
pTempCurrPointPos->y += 8;
pSrcRefBuf += (srcRefStep * 8) - 8;
omxVCM4P2_FindMVpred(
&(pSrcDstMBCurr->pMV0[1][0]),
pSrcCandMV1[2],
pSrcCandMV2[2],
pSrcCandMV3[2],
&(pSrcDstMBCurr->pMVPred[1][0]),
NULL,
2);
armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
srcRefStep, pRefRect,
pTempSrcCurrBuf, pTempCurrPointPos,
&(pSrcDstMBCurr->pMVPred[1][0]), NULL,
pMEParams, &(pSrcDstMBCurr->pMV0[1][0]),
&dstSAD8x8
);
pDstBlockSAD[2] = dstSAD8x8;
*pDstSAD += dstSAD8x8;
pTempCurrPointPos->x += 8;
pSrcRefBuf += 8;
omxVCM4P2_FindMVpred(
&(pSrcDstMBCurr->pMV0[1][1]),
pSrcCandMV1[3],
pSrcCandMV2[3],
pSrcCandMV3[3],
&(pSrcDstMBCurr->pMVPred[1][1]),
NULL,
3);
armVCM4P2_BlockMatch_8x8 (pSrcRefBuf,
srcRefStep, pRefRect,
pTempSrcCurrBuf, pTempCurrPointPos,
&(pSrcDstMBCurr->pMVPred[1][1]), NULL,
pMEParams, &(pSrcDstMBCurr->pMV0[1][1]),
&dstSAD8x8
);
pDstBlockSAD[3] = dstSAD8x8;
*pDstSAD += dstSAD8x8;
/* Checking if 4MV is equal to 1MV */
if (
(pSrcDstMBCurr->pMV0[0][0].dx != dstMV16x16.dx) ||
(pSrcDstMBCurr->pMV0[0][0].dy != dstMV16x16.dy) ||
(pSrcDstMBCurr->pMV0[0][1].dx != dstMV16x16.dx) ||
(pSrcDstMBCurr->pMV0[0][1].dy != dstMV16x16.dy) ||
(pSrcDstMBCurr->pMV0[1][0].dx != dstMV16x16.dx) ||
(pSrcDstMBCurr->pMV0[1][0].dy != dstMV16x16.dy) ||
(pSrcDstMBCurr->pMV0[1][1].dx != dstMV16x16.dx) ||
(pSrcDstMBCurr->pMV0[1][1].dy != dstMV16x16.dy)
)
{
/* select the 4 MV */
pSrcDstMBCurr->mbType = OMX_VC_INTER4V;
}
}
/* finding the error in intra mode */
for (count = 0, average = 0; count < 256 ; count++)
{
average = average + pTempSrcCurrBuf[count];
}
average = average/256;
intraSAD = 0;
/* Intra SAD calculation */
for (count = 0; count < 256 ; count++)
{
intraSAD += armAbs ((pTempSrcCurrBuf[count]) - (average));
}
/* Using the MPEG4 VM formula for intra/inter mode decision
Var < (SAD - 2*NB) where NB = N^2 is the number of pixels
of the macroblock.*/
if (intraSAD <= (*pDstSAD - 512))
{
pSrcDstMBCurr->mbType = OMX_VC_INTRA;
pSrcDstMBCurr->pMV0[0][0].dx = 0;
pSrcDstMBCurr->pMV0[0][0].dy = 0;
*pDstSAD = intraSAD;
pDstBlockSAD[0] = 0xFFFF;
pDstBlockSAD[1] = 0xFFFF;
pDstBlockSAD[2] = 0xFFFF;
pDstBlockSAD[3] = 0xFFFF;
}
if(pSrcDstMBCurr->mbType == OMX_VC_INTER)
{
pTempSrcRefBuf = pSrcRefBuf + (srcRefStep * dstMV16x16.dy) + dstMV16x16.dx;
if((dstMV16x16.dx & 0x1) && (dstMV16x16.dy & 0x1))
{
predictType = OMX_VC_HALF_PIXEL_XY;
}
else if(dstMV16x16.dx & 0x1)
{
predictType = OMX_VC_HALF_PIXEL_X;
}
else if(dstMV16x16.dy & 0x1)
{
predictType = OMX_VC_HALF_PIXEL_Y;
}
else
{
predictType = OMX_VC_INTEGER_PIXEL;
}
pDst = armAlignTo8Bytes(&(aDst[0]));
/* Calculating Block SAD at MV(dstMV16x16.dx,dstMV16x16.dy) */
/* Block 0 */
omxVCM4P2_MCReconBlock(pTempSrcRefBuf,
srcRefStep,
NULL,
pDst,
dstStep,
predictType,
pMEParams->rndVal);
armVCCOMM_SAD(pTempSrcCurrBuf,
16,
pDst,
dstStep,
&Sad,
8,
8);
pDstBlockSAD[0] = Sad;
/* Block 1 */
omxVCM4P2_MCReconBlock(pTempSrcRefBuf + 8,
srcRefStep,
NULL,
pDst,
dstStep,
predictType,
pMEParams->rndVal);
armVCCOMM_SAD(pTempSrcCurrBuf + 8,
16,
pDst,
dstStep,
&Sad,
8,
8);
pDstBlockSAD[1] = Sad;
/* Block 2 */
omxVCM4P2_MCReconBlock(pTempSrcRefBuf + (srcRefStep*8),
srcRefStep,
NULL,
pDst,
dstStep,
predictType,
pMEParams->rndVal);
armVCCOMM_SAD(pTempSrcCurrBuf + (16*8),
16,
pDst,
dstStep,
&Sad,
8,
8);
pDstBlockSAD[2] = Sad;
/* Block 3 */
omxVCM4P2_MCReconBlock(pTempSrcRefBuf + (srcRefStep*8) + 8,
srcRefStep,
NULL,
pDst,
dstStep,
predictType,
pMEParams->rndVal);
armVCCOMM_SAD(pTempSrcCurrBuf + (16*8) + 8,
16,
pDst,
dstStep,
&Sad,
8,
8);
pDstBlockSAD[3] = Sad;
}
return OMX_Sts_NoErr;
}
/* End of file */