4 |
* - Motion Estimation module - |
* - Motion Estimation module - |
5 |
* |
* |
6 |
* Copyright(C) 2002 Christoph Lampert <gruel@web.de> |
* Copyright(C) 2002 Christoph Lampert <gruel@web.de> |
7 |
* Copyright(C) 2002 Michael Militzer <michael@xvid.org> |
* 2002 Michael Militzer <michael@xvid.org> |
|
* Copyright(C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr> |
|
8 |
* |
* |
9 |
* This program is an implementation of a part of one or more MPEG-4 |
* This file is part of XviD, a free MPEG-4 video encoder/decoder |
|
* Video tools as specified in ISO/IEC 14496-2 standard. Those intending |
|
|
* to use this software module in hardware or software products are |
|
|
* advised that its use may infringe existing patents or copyrights, and |
|
|
* any such use would be at such party's own risk. The original |
|
|
* developer of this software module and his/her company, and subsequent |
|
|
* editors and their companies, will have no liability for use of this |
|
|
* software or modifications or derivatives thereof. |
|
10 |
* |
* |
11 |
* This program is free software; you can redistribute it and/or modify |
* XviD is free software; you can redistribute it and/or modify it |
12 |
* it under the terms of the GNU General Public License as published by |
* under the terms of the GNU General Public License as published by |
13 |
* the Free Software Foundation; either version 2 of the License, or |
* the Free Software Foundation; either version 2 of the License, or |
14 |
* (at your option) any later version. |
* (at your option) any later version. |
15 |
* |
* |
22 |
* along with this program; if not, write to the Free Software |
* along with this program; if not, write to the Free Software |
23 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 |
* |
* |
25 |
|
* Under section 8 of the GNU General Public License, the copyright |
26 |
|
* holders of XVID explicitly forbid distribution in the following |
27 |
|
* countries: |
28 |
|
* |
29 |
|
* - Japan |
30 |
|
* - United States of America |
31 |
|
* |
32 |
|
* Linking XviD statically or dynamically with other modules is making a |
33 |
|
* combined work based on XviD. Thus, the terms and conditions of the |
34 |
|
* GNU General Public License cover the whole combination. |
35 |
|
* |
36 |
|
* As a special exception, the copyright holders of XviD give you |
37 |
|
* permission to link XviD with independent modules that communicate with |
38 |
|
* XviD solely through the VFW1.1 and DShow interfaces, regardless of the |
39 |
|
* license terms of these independent modules, and to copy and distribute |
40 |
|
* the resulting combined work under terms of your choice, provided that |
41 |
|
* every copy of the combined work is accompanied by a complete copy of |
42 |
|
* the source code of XviD (the version of XviD used to produce the |
43 |
|
* combined work), being distributed under the terms of the GNU General |
44 |
|
* Public License plus this exception. An independent module is a module |
45 |
|
* which is not derived from or based on XviD. |
46 |
|
* |
47 |
|
* Note that people who make modified versions of XviD are not obligated |
48 |
|
* to grant this special exception for their modified versions; it is |
49 |
|
* their choice whether to do so. The GNU General Public License gives |
50 |
|
* permission to release a modified version without this exception; this |
51 |
|
* exception also makes it possible to release a modified version which |
52 |
|
* carries forward this exception. |
53 |
|
* |
54 |
|
* $Id$ |
55 |
|
* |
56 |
*************************************************************************/ |
*************************************************************************/ |
57 |
|
|
58 |
#include <assert.h> |
#include <assert.h> |
176 |
|
|
177 |
MACROBLOCK *const pMB = &pMBs[x + y * iWcount]; |
MACROBLOCK *const pMB = &pMBs[x + y * iWcount]; |
178 |
|
|
|
if (pMB->mode == MODE_NOT_CODED) |
|
|
continue; |
|
|
|
|
179 |
predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); |
predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); |
180 |
|
|
181 |
pMB->sad16 = |
pMB->sad16 = |
379 |
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
380 |
} |
} |
381 |
|
|
382 |
|
#if 0 |
383 |
/* too slow and not fully functional at the moment */ |
/* too slow and not fully functional at the moment */ |
|
/* |
|
384 |
int32_t ZeroSearch16( |
int32_t ZeroSearch16( |
385 |
const uint8_t * const pRef, |
const uint8_t * const pRef, |
386 |
const uint8_t * const pRefH, |
const uint8_t * const pRefH, |
419 |
return iSAD; |
return iSAD; |
420 |
|
|
421 |
} |
} |
422 |
*/ |
#endif /* 0 */ |
423 |
|
|
424 |
int32_t |
int32_t |
425 |
Diamond16_MainSearch(const uint8_t * const pRef, |
Diamond16_MainSearch(const uint8_t * const pRef, |
862 |
} |
} |
863 |
while (1); //forever |
while (1); //forever |
864 |
} |
} |
|
return iMinSAD; |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_F_INTERPOL(X,Y) { \ |
|
|
if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \ |
|
|
&& ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16bi( cur, \ |
|
|
get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth), \ |
|
|
get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth), \ |
|
|
iEdgedWidth); \ |
|
|
iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\ |
|
|
iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \ |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \ |
|
|
if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \ |
|
|
&& ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16bi( cur, \ |
|
|
get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth), \ |
|
|
get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth), \ |
|
|
iEdgedWidth); \ |
|
|
iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\ |
|
|
iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \ |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_B_INTERPOL(X,Y) { \ |
|
|
if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \ |
|
|
&& ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16bi( cur, \ |
|
|
get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth), \ |
|
|
get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth), \ |
|
|
iEdgedWidth); \ |
|
|
iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\ |
|
|
iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \ |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \ |
|
|
if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \ |
|
|
&& ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16bi( cur, \ |
|
|
get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth), \ |
|
|
get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth), \ |
|
|
iEdgedWidth); \ |
|
|
iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\ |
|
|
iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \ |
|
|
} |
|
|
|
|
|
int32_t |
|
|
Diamond16_InterpolMainSearch(const uint8_t * const f_pRef, |
|
|
const uint8_t * const f_pRefH, |
|
|
const uint8_t * const f_pRefV, |
|
|
const uint8_t * const f_pRefHV, |
|
|
|
|
|
const uint8_t * const cur, |
|
|
|
|
|
const uint8_t * const b_pRef, |
|
|
const uint8_t * const b_pRefH, |
|
|
const uint8_t * const b_pRefV, |
|
|
const uint8_t * const b_pRefHV, |
|
|
|
|
|
const int x, |
|
|
const int y, |
|
|
|
|
|
const int f_start_x, |
|
|
const int f_start_y, |
|
|
const int b_start_x, |
|
|
const int b_start_y, |
|
|
|
|
|
int iMinSAD, |
|
|
VECTOR * const f_currMV, |
|
|
VECTOR * const b_currMV, |
|
|
|
|
|
const int f_center_x, |
|
|
const int f_center_y, |
|
|
const int b_center_x, |
|
|
const int b_center_y, |
|
|
|
|
|
const int32_t f_min_dx, |
|
|
const int32_t f_max_dx, |
|
|
const int32_t f_min_dy, |
|
|
const int32_t f_max_dy, |
|
|
|
|
|
const int32_t b_min_dx, |
|
|
const int32_t b_max_dx, |
|
|
const int32_t b_min_dy, |
|
|
const int32_t b_max_dy, |
|
|
|
|
|
const int32_t iEdgedWidth, |
|
|
const int32_t iDiamondSize, |
|
|
|
|
|
const int32_t f_iFcode, |
|
|
const int32_t b_iFcode, |
|
|
|
|
|
const int32_t iQuant, |
|
|
int iFound) |
|
|
{ |
|
|
/* Do a diamond search around given starting point, return SAD of best */ |
|
|
|
|
|
int32_t iSAD; |
|
|
|
|
|
VECTOR f_backupMV; |
|
|
VECTOR b_backupMV; |
|
|
|
|
|
f_currMV->x = f_start_x; |
|
|
f_currMV->y = f_start_y; |
|
|
b_currMV->x = b_start_x; |
|
|
b_currMV->y = b_start_y; |
|
|
|
|
|
do |
|
|
{ |
|
|
iFound = 1; |
|
|
|
|
|
f_backupMV = *f_currMV; |
|
|
|
|
|
CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y); |
|
|
CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y); |
|
|
CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize); |
|
|
CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize); |
|
|
|
|
|
b_backupMV = *b_currMV; |
|
|
|
|
|
CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y); |
|
|
CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y); |
|
|
CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize); |
|
|
CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize); |
|
|
|
|
|
} while (!iFound); |
|
|
|
|
|
return iMinSAD; |
|
|
} |
|
|
|
|
|
/* Sorry, these MACROS really got too large... I'll turn them into function soon! */ |
|
|
|
|
|
#define CHECK_MV16_DIRECT_FOUND(X,Y) \ |
|
|
if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \ |
|
|
{ int k;\ |
|
|
VECTOR mvs,b_mvs; \ |
|
|
iSAD = 0;\ |
|
|
for (k = 0; k < 4; k++) { \ |
|
|
mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X)); \ |
|
|
b_mvs.x = (int32_t) (((X) == 0) \ |
|
|
? ((TRB - TRD) * directmv[k].x) / TRD \ |
|
|
: mvs.x - directmv[k].x); \ |
|
|
\ |
|
|
mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y)); \ |
|
|
b_mvs.y = (int32_t) (((Y) == 0) \ |
|
|
? ((TRB - TRD) * directmv[k].y) / TRD \ |
|
|
: mvs.y - directmv[k].y); \ |
|
|
\ |
|
|
if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \ |
|
|
&& (mvs.y <= max_dy) && (mvs.y >= min_dy) \ |
|
|
&& (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx) \ |
|
|
&& (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \ |
|
|
iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth, \ |
|
|
get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \ |
|
|
mvs.x, mvs.y, iEdgedWidth), \ |
|
|
get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \ |
|
|
b_mvs.x, b_mvs.y, iEdgedWidth), \ |
|
|
iEdgedWidth); \ |
|
|
} \ |
|
|
else \ |
|
|
iSAD = 65535; \ |
|
|
} \ |
|
|
iSAD += calc_delta_16((X),(Y), 1, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \ |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int32_t |
|
|
Diamond16_DirectMainSearch( |
|
|
const uint8_t * const f_pRef, |
|
|
const uint8_t * const f_pRefH, |
|
|
const uint8_t * const f_pRefV, |
|
|
const uint8_t * const f_pRefHV, |
|
|
|
|
|
const uint8_t * const cur, |
|
|
|
|
|
const uint8_t * const b_pRef, |
|
|
const uint8_t * const b_pRefH, |
|
|
const uint8_t * const b_pRefV, |
|
|
const uint8_t * const b_pRefHV, |
|
|
|
|
|
const int x, |
|
|
const int y, |
|
|
|
|
|
const int TRB, |
|
|
const int TRD, |
|
|
|
|
|
const int start_x, |
|
|
const int start_y, |
|
|
|
|
|
int iMinSAD, |
|
|
VECTOR * const currMV, |
|
|
const VECTOR * const directmv, |
|
|
|
|
|
const int32_t min_dx, |
|
|
const int32_t max_dx, |
|
|
const int32_t min_dy, |
|
|
const int32_t max_dy, |
|
|
|
|
|
const int32_t iEdgedWidth, |
|
|
const int32_t iDiamondSize, |
|
|
|
|
|
const int32_t iQuant, |
|
|
int iFound) |
|
|
{ |
|
|
/* Do a diamond search around given starting point, return SAD of best */ |
|
|
|
|
|
int32_t iSAD; |
|
|
|
|
|
VECTOR backupMV; |
|
|
|
|
|
currMV->x = start_x; |
|
|
currMV->y = start_y; |
|
|
|
|
|
/* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */ |
|
|
|
|
|
do |
|
|
{ |
|
|
iFound = 1; |
|
|
|
|
|
backupMV = *currMV; |
|
|
|
|
|
CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y); |
|
|
CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y); |
|
|
CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize); |
|
|
CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize); |
|
|
|
|
|
} while (!iFound); |
|
865 |
|
|
866 |
return iMinSAD; |
return iMinSAD; |
867 |
} |
} |
868 |
|
|
|
|
|
869 |
int32_t |
int32_t |
870 |
AdvDiamond8_MainSearch(const uint8_t * const pRef, |
AdvDiamond8_MainSearch(const uint8_t * const pRef, |
871 |
const uint8_t * const pRefH, |
const uint8_t * const pRefH, |
2559 |
currPMV->y = currMV->y - center_y; |
currPMV->y = currMV->y - center_y; |
2560 |
return iMinSAD; |
return iMinSAD; |
2561 |
} |
} |
|
|
|
|
|
|
|
|
|
|
int32_t |
|
|
PMVfastIntSearch16(const uint8_t * const pRef, |
|
|
const uint8_t * const pRefH, |
|
|
const uint8_t * const pRefV, |
|
|
const uint8_t * const pRefHV, |
|
|
const IMAGE * const pCur, |
|
|
const int x, |
|
|
const int y, |
|
|
const int start_x, /* start should be most likely vector */ |
|
|
const int start_y, |
|
|
const int center_x, /* center is from where length of MVs is measured */ |
|
|
const int center_y, |
|
|
const uint32_t MotionFlags, |
|
|
const uint32_t iQuant, |
|
|
const uint32_t iFcode, |
|
|
const MBParam * const pParam, |
|
|
const MACROBLOCK * const pMBs, |
|
|
const MACROBLOCK * const prevMBs, |
|
|
VECTOR * const currMV, |
|
|
VECTOR * const currPMV) |
|
|
{ |
|
|
const uint32_t iWcount = pParam->mb_width; |
|
|
const int32_t iWidth = pParam->width; |
|
|
const int32_t iHeight = pParam->height; |
|
|
const int32_t iEdgedWidth = pParam->edged_width; |
|
|
|
|
|
const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth; |
|
|
const VECTOR zeroMV = { 0, 0 }; |
|
|
|
|
|
int32_t iDiamondSize; |
|
|
|
|
|
int32_t min_dx; |
|
|
int32_t max_dx; |
|
|
int32_t min_dy; |
|
|
int32_t max_dy; |
|
|
|
|
|
int32_t iFound; |
|
|
|
|
|
VECTOR newMV; |
|
|
VECTOR backupMV; |
|
|
|
|
|
VECTOR pmv[4]; |
|
|
int32_t psad[4]; |
|
|
|
|
|
MainSearch16FuncPtr MainSearchPtr; |
|
|
|
|
|
MACROBLOCK *const prevMB = (MACROBLOCK *const)prevMBs + x + y * iWcount; |
|
|
MACROBLOCK *const pMB = (MACROBLOCK *const)(pMBs + x + y * iWcount); |
|
|
|
|
|
int32_t threshA, threshB; |
|
|
int32_t bPredEq; |
|
|
int32_t iMinSAD, iSAD; |
|
|
|
|
|
|
|
|
/* Get maximum range */ |
|
|
get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight, |
|
|
iFcode); |
|
|
|
|
|
/* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */ |
|
|
|
|
|
if ((x == 0) && (y == 0)) { |
|
|
threshA = 512; |
|
|
threshB = 1024; |
|
|
|
|
|
bPredEq = 0; |
|
|
psad[0] = psad[1] = psad[2] = psad[3] = 0; |
|
|
*currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV; |
|
|
|
|
|
} else { |
|
|
|
|
|
bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
|
|
|
|
|
threshA = psad[0]; |
|
|
threshB = threshA + 256; |
|
|
if (threshA < 512) |
|
|
threshA = 512; |
|
|
if (threshA > 1024) |
|
|
threshA = 1024; |
|
|
if (threshB > 1792) |
|
|
threshB = 1792; |
|
|
|
|
|
*currMV = pmv[0]; /* current best := prediction */ |
|
|
} |
|
|
|
|
|
iFound = 0; |
|
|
|
|
|
/* Step 4: Calculate SAD around the Median prediction. |
|
|
MinSAD=SAD |
|
|
If Motion Vector equal to Previous frame motion vector |
|
|
and MinSAD<PrevFrmSAD goto Step 10. |
|
|
If SAD<=256 goto Step 10. |
|
|
*/ |
|
|
|
|
|
if (currMV->x > max_dx) { |
|
|
currMV->x = EVEN(max_dx); |
|
|
} |
|
|
if (currMV->x < min_dx) { |
|
|
currMV->x = EVEN(min_dx); |
|
|
} |
|
|
if (currMV->y > max_dy) { |
|
|
currMV->y = EVEN(max_dy); |
|
|
} |
|
|
if (currMV->y < min_dy) { |
|
|
currMV->y = EVEN(min_dy); |
|
|
} |
|
|
|
|
|
iMinSAD = |
|
|
sad16(cur, |
|
|
get_iref_mv(pRef, x, y, 16, currMV, |
|
|
iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); |
|
|
iMinSAD += |
|
|
calc_delta_16(currMV->x - center_x, currMV->y - center_y, |
|
|
(uint8_t) iFcode, iQuant); |
|
|
|
|
|
if ((iMinSAD < 256) || |
|
|
((MVequal(*currMV, prevMB->i_mvs[0])) && |
|
|
((int32_t) iMinSAD < prevMB->i_sad16))) { |
|
|
if (iMinSAD < (int)(2 * iQuant)) // high chances for SKIP-mode |
|
|
{ |
|
|
if (!MVzero(*currMV)) { |
|
|
iMinSAD += MV16_00_BIAS; |
|
|
CHECK_MV16_ZERO; // (0,0) saves space for letterboxed pictures |
|
|
iMinSAD -= MV16_00_BIAS; |
|
|
} |
|
|
} |
|
|
|
|
|
if (MotionFlags & PMV_EARLYSTOP16) |
|
|
goto PMVfastInt16_Terminate_with_Refine; |
|
|
} |
|
|
|
|
|
|
|
|
/* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion |
|
|
vector of the median. |
|
|
If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2 |
|
|
*/ |
|
|
|
|
|
if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0]))) |
|
|
iFound = 2; |
|
|
|
|
|
/* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search. |
|
|
Otherwise select large Diamond Search. |
|
|
*/ |
|
|
|
|
|
if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq)) |
|
|
iDiamondSize = 2; // halfpel units! |
|
|
else |
|
|
iDiamondSize = 4; // halfpel units! |
|
|
|
|
|
/* |
|
|
Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block. |
|
|
Also calculate (0,0) but do not subtract offset. |
|
|
Let MinSAD be the smallest SAD up to this point. |
|
|
If MV is (0,0) subtract offset. |
|
|
*/ |
|
|
|
|
|
// (0,0) is often a good choice |
|
|
|
|
|
if (!MVzero(pmv[0])) |
|
|
CHECK_MV16_ZERO; |
|
|
|
|
|
// previous frame MV is always possible |
|
|
|
|
|
if (!MVzero(prevMB->i_mvs[0])) |
|
|
if (!MVequal(prevMB->i_mvs[0], pmv[0])) |
|
|
CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y); |
|
|
|
|
|
// left neighbour, if allowed |
|
|
|
|
|
if (!MVzero(pmv[1])) |
|
|
if (!MVequal(pmv[1], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[1], pmv[0])) |
|
|
CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y); |
|
|
|
|
|
// top neighbour, if allowed |
|
|
if (!MVzero(pmv[2])) |
|
|
if (!MVequal(pmv[2], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[2], pmv[0])) |
|
|
if (!MVequal(pmv[2], pmv[1])) |
|
|
CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y); |
|
|
|
|
|
// top right neighbour, if allowed |
|
|
if (!MVzero(pmv[3])) |
|
|
if (!MVequal(pmv[3], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[3], pmv[0])) |
|
|
if (!MVequal(pmv[3], pmv[1])) |
|
|
if (!MVequal(pmv[3], pmv[2])) |
|
|
CHECK_MV16_CANDIDATE(pmv[3].x, |
|
|
pmv[3].y); |
|
|
|
|
|
if ((MVzero(*currMV)) && |
|
|
(!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ ) |
|
|
iMinSAD -= MV16_00_BIAS; |
|
|
|
|
|
|
|
|
/* Step 6: If MinSAD <= thresa goto Step 10. |
|
|
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
|
|
*/ |
|
|
|
|
|
if ((iMinSAD <= threshA) || |
|
|
(MVequal(*currMV, prevMB->i_mvs[0]) && |
|
|
((int32_t) iMinSAD < prevMB->i_sad16))) { |
|
|
|
|
|
if (MotionFlags & PMV_EARLYSTOP16) |
|
|
goto PMVfastInt16_Terminate_with_Refine; |
|
|
} |
|
|
|
|
|
|
|
|
/************ (Diamond Search) **************/ |
|
|
/* |
|
|
Step 7: Perform Diamond search, with either the small or large diamond. |
|
|
If Found=2 only examine one Diamond pattern, and afterwards goto step 10 |
|
|
Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond. |
|
|
If center then goto step 10. |
|
|
Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center. |
|
|
Refine by using small diamond and goto step 10. |
|
|
*/ |
|
|
|
|
|
if (MotionFlags & PMV_USESQUARES16) |
|
|
MainSearchPtr = Square16_MainSearch; |
|
|
else if (MotionFlags & PMV_ADVANCEDDIAMOND16) |
|
|
MainSearchPtr = AdvDiamond16_MainSearch; |
|
|
else |
|
|
MainSearchPtr = Diamond16_MainSearch; |
|
|
|
|
|
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
|
|
|
|
|
|
|
|
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */ |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x, |
|
|
currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, |
|
|
min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, |
|
|
iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
|
|
|
if (MotionFlags & PMV_EXTSEARCH16) { |
|
|
/* extended: search (up to) two more times: orignal prediction and (0,0) */ |
|
|
|
|
|
if (!(MVequal(pmv[0], backupMV))) { |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, |
|
|
pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y, |
|
|
min_dx, max_dx, min_dy, max_dy, iEdgedWidth, |
|
|
iDiamondSize, iFcode, iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
} |
|
|
|
|
|
if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) { |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0, |
|
|
iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy, |
|
|
max_dy, iEdgedWidth, iDiamondSize, iFcode, |
|
|
iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
Step 10: The motion vector is chosen according to the block corresponding to MinSAD. |
|
|
*/ |
|
|
|
|
|
PMVfastInt16_Terminate_with_Refine: |
|
|
|
|
|
pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV; |
|
|
pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD; |
|
|
|
|
|
if (MotionFlags & PMV_HALFPELREFINE16) // perform final half-pel step |
|
|
iMinSAD = |
|
|
Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV, |
|
|
iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy, |
|
|
iFcode, iQuant, iEdgedWidth); |
|
|
|
|
|
pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); // get _REAL_ prediction (halfpel possible) |
|
|
|
|
|
currPMV->x = currMV->x - center_x; |
|
|
currPMV->y = currMV->y - center_y; |
|
|
return iMinSAD; |
|
|
} |
|
|
|
|