1 |
/************************************************************************** |
/************************************************************************** |
2 |
* |
* |
3 |
|
* XVID MPEG-4 VIDEO CODEC |
4 |
|
* motion estimation |
5 |
|
* |
6 |
|
* This program is an implementation of a part of one or more MPEG-4 |
7 |
|
* Video tools as specified in ISO/IEC 14496-2 standard. Those intending |
8 |
|
* to use this software module in hardware or software products are |
9 |
|
* advised that its use may infringe existing patents or copyrights, and |
10 |
|
* any such use would be at such party's own risk. The original |
11 |
|
* developer of this software module and his/her company, and subsequent |
12 |
|
* editors and their companies, will have no liability for use of this |
13 |
|
* software or modifications or derivatives thereof. |
14 |
|
* |
15 |
|
* This program is free software; you can redistribute it and/or modify |
16 |
|
* it under the terms of the GNU General Public License as published by |
17 |
|
* the Free Software Foundation; either version 2 of the License, or |
18 |
|
* (at your option) any later version. |
19 |
|
* |
20 |
|
* This program is distributed in the hope that it will be useful, |
21 |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 |
|
* GNU General Public License for more details. |
24 |
|
* |
25 |
|
* You should have received a copy of the GNU General Public License |
26 |
|
* along with this program; if not, write to the Free Software |
27 |
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
28 |
|
* |
29 |
|
*************************************************************************/ |
30 |
|
|
31 |
|
/************************************************************************** |
32 |
|
* |
33 |
* Modifications: |
* Modifications: |
34 |
* |
* |
35 |
* 01.05.2002 updated MotionEstimationBVOP |
* 01.05.2002 updated MotionEstimationBVOP |
77 |
#include "motion.h" |
#include "motion.h" |
78 |
#include "sad.h" |
#include "sad.h" |
79 |
|
|
|
// very large value |
|
|
#define MV_MAX_ERROR (4096 * 256) |
|
|
|
|
|
// stop search if sdelta < THRESHOLD |
|
|
#define MV16_THRESHOLD 192 |
|
|
#define MV8_THRESHOLD 56 |
|
|
|
|
|
#define NEIGH_MOVE_THRESH 0 |
|
|
// how much a block's MV must differ from his neighbour |
|
|
// to be search for INTER4V. The more, the faster... |
|
|
|
|
|
/* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */ |
|
|
/* nb = vop pixels * 2^(bpp-8) */ |
|
|
#define MV16_00_BIAS (128+1) |
|
|
#define MV8_00_BIAS (0) |
|
|
|
|
|
/* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */ |
|
|
#define MV16_INTER_BIAS 512 |
|
|
|
|
|
/* Parameters which control inter/inter4v decision */ |
|
|
#define IMV16X16 5 |
|
|
|
|
|
/* vector map (vlc delta size) smoother parameters */ |
|
|
#define NEIGH_TEND_16X16 2 |
|
|
#define NEIGH_TEND_8X8 2 |
|
|
|
|
|
// fast ((A)/2)*2 |
|
|
#define EVEN(A) (((A)<0?(A)+1:(A)) & ~1) |
|
|
|
|
|
#define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) ) |
|
|
#define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) ) |
|
|
|
|
|
int32_t PMVfastSearch16(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 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); |
|
|
|
|
|
int32_t EPZSSearch16(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 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); |
|
|
|
|
80 |
|
|
|
int32_t PMVfastSearch8(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, |
|
|
const int start_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); |
|
|
|
|
|
int32_t EPZSSearch8(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, |
|
|
const int start_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); |
|
|
|
|
|
|
|
|
typedef int32_t(MainSearch16Func) (const uint8_t * const pRef, |
|
|
const uint8_t * const pRefH, |
|
|
const uint8_t * const pRefV, |
|
|
const uint8_t * const pRefHV, |
|
|
const uint8_t * const cur, |
|
|
const int x, |
|
|
const int y, |
|
|
int32_t startx, |
|
|
int32_t starty, |
|
|
int32_t iMinSAD, |
|
|
VECTOR * const currMV, |
|
|
const VECTOR * const pmv, |
|
|
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 iFcode, |
|
|
const int32_t iQuant, |
|
|
int iFound); |
|
|
|
|
|
typedef MainSearch16Func *MainSearch16FuncPtr; |
|
|
|
|
|
|
|
|
typedef int32_t(MainSearch8Func) (const uint8_t * const pRef, |
|
|
const uint8_t * const pRefH, |
|
|
const uint8_t * const pRefV, |
|
|
const uint8_t * const pRefHV, |
|
|
const uint8_t * const cur, |
|
|
const int x, |
|
|
const int y, |
|
|
int32_t startx, |
|
|
int32_t starty, |
|
|
int32_t iMinSAD, |
|
|
VECTOR * const currMV, |
|
|
const VECTOR * const pmv, |
|
|
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 iFcode, |
|
|
const int32_t iQuant, |
|
|
int iFound); |
|
|
|
|
|
typedef MainSearch8Func *MainSearch8FuncPtr; |
|
81 |
|
|
82 |
static int32_t lambda_vec16[32] = /* rounded values for lambda param for weight of motion bits as in modified H.26L */ |
static int32_t lambda_vec16[32] = /* rounded values for lambda param for weight of motion bits as in modified H.26L */ |
83 |
{ 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5), |
{ 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5), |
155 |
mv_bits(dy, iFcode)); |
mv_bits(dy, iFcode)); |
156 |
} |
} |
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef SEARCH16 |
|
|
#define SEARCH16 PMVfastSearch16 |
|
|
//#define SEARCH16 FullSearch16 |
|
|
//#define SEARCH16 EPZSSearch16 |
|
|
#endif |
|
|
|
|
|
#ifndef SEARCH8 |
|
|
#define SEARCH8 PMVfastSearch8 |
|
|
//#define SEARCH8 EPZSSearch8 |
|
|
#endif |
|
|
|
|
158 |
bool |
bool |
159 |
MotionEstimation(MBParam * const pParam, |
MotionEstimation(MBParam * const pParam, |
160 |
FRAMEINFO * const current, |
FRAMEINFO * const current, |
173 |
|
|
174 |
const VECTOR zeroMV = { 0, 0 }; |
const VECTOR zeroMV = { 0, 0 }; |
175 |
|
|
176 |
|
int64_t time; |
177 |
int32_t x, y; |
int32_t x, y; |
178 |
int32_t iIntra = 0; |
int32_t iIntra = 0; |
179 |
VECTOR pmv; |
VECTOR pmv; |
181 |
if (sadInit) |
if (sadInit) |
182 |
(*sadInit) (); |
(*sadInit) (); |
183 |
|
|
184 |
for (y = 0; y < iHcount; y++) |
for (y = 0; y < iHcount; y++) { |
185 |
for (x = 0; x < iWcount; x++) { |
for (x = 0; x < iWcount; x++) { |
186 |
|
|
187 |
MACROBLOCK *const pMB = &pMBs[x + y * iWcount]; |
MACROBLOCK *const pMB = &pMBs[x + y * iWcount]; |
188 |
|
|
189 |
pMB->sad16 = |
pMB->sad16 = |
277 |
pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16; |
pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16; |
278 |
pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = |
pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = |
279 |
pMB->sad16; |
pMB->sad16; |
|
|
|
280 |
} |
} |
281 |
|
} |
282 |
|
|
283 |
return 0; |
return 0; |
284 |
} |
} |
285 |
|
|
397 |
const int32_t iEdgedWidth = pParam->edged_width; |
const int32_t iEdgedWidth = pParam->edged_width; |
398 |
const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth; |
const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth; |
399 |
int32_t iSAD; |
int32_t iSAD; |
400 |
int32_t pred_x,pred_y; |
VECTOR pred; |
401 |
|
|
402 |
get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y); |
|
403 |
|
pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); |
404 |
|
|
405 |
iSAD = sad16( cur, |
iSAD = sad16( cur, |
406 |
get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth), |
get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth), |
410 |
|
|
411 |
currMV->x = 0; |
currMV->x = 0; |
412 |
currMV->y = 0; |
currMV->y = 0; |
413 |
currPMV->x = -pred_x; |
currPMV->x = -pred.x; |
414 |
currPMV->y = -pred_y; |
currPMV->y = -pred.y; |
415 |
|
|
416 |
return iSAD; |
return iSAD; |
417 |
|
|
1129 |
|
|
1130 |
MainSearch16FuncPtr MainSearchPtr; |
MainSearch16FuncPtr MainSearchPtr; |
1131 |
|
|
|
// const MACROBLOCK * const pMB = pMBs + x + y * iWcount; |
|
1132 |
const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; |
const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; |
1133 |
|
|
1134 |
static int32_t threshA, threshB; |
int32_t threshA, threshB; |
1135 |
int32_t bPredEq; |
int32_t bPredEq; |
1136 |
int32_t iMinSAD, iSAD; |
int32_t iMinSAD, iSAD; |
1137 |
|
|
1150 |
|
|
1151 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
1152 |
bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
1153 |
|
// bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
1154 |
|
|
1155 |
|
/* fprintf(stderr,"pmv: %d %d / %d --- %d %d %d %d %d %d - %d %d %d\n", |
1156 |
|
pmv[0].x,pmv[0].y,psad[0], |
1157 |
|
pmv[1].x,pmv[1].y,pmv[2].x,pmv[2].y,pmv[3].x,pmv[3].y, |
1158 |
|
psad[1],psad[2],psad[3]); |
1159 |
|
*/ |
1160 |
if ((x == 0) && (y == 0)) { |
if ((x == 0) && (y == 0)) { |
1161 |
threshA = 512; |
threshA = 512; |
1162 |
threshB = 1024; |
threshB = 1024; |
|
|
|
1163 |
} else { |
} else { |
1164 |
threshA = psad[0]; |
threshA = psad[0]; |
1165 |
threshB = threshA + 256; |
threshB = threshA + 256; |
1340 |
|
|
1341 |
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
1342 |
|
|
1343 |
|
|
1344 |
|
// fprintf(stderr,"Entering Diamond %d %d (%d):\n",x,y,iMinSAD); |
1345 |
|
|
1346 |
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */ |
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */ |
1347 |
iSAD = |
iSAD = |
1348 |
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x, |
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x, |
1396 |
iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy, |
iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy, |
1397 |
iFcode, iQuant, iEdgedWidth); |
iFcode, iQuant, iEdgedWidth); |
1398 |
|
|
1399 |
|
/*fprintf(stderr,"Chosen for %d %d: %d %d - %d %d\n",x,y,currMV->x,currMV->y,pmv[0].x,pmv[0].y); |
1400 |
|
*/ |
1401 |
PMVfast16_Terminate_without_Refine: |
PMVfast16_Terminate_without_Refine: |
1402 |
currPMV->x = currMV->x - pmv[0].x; |
currPMV->x = currMV->x - pmv[0].x; |
1403 |
currPMV->y = currMV->y - pmv[0].y; |
currPMV->y = currMV->y - pmv[0].y; |
1553 |
// const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount; |
// const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount; |
1554 |
const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount; |
const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount; |
1555 |
|
|
1556 |
static int32_t threshA, threshB; |
int32_t threshA, threshB; |
1557 |
int32_t iFound, bPredEq; |
int32_t iFound, bPredEq; |
1558 |
int32_t iMinSAD, iSAD; |
int32_t iMinSAD, iSAD; |
1559 |
|
|
1577 |
} |
} |
1578 |
|
|
1579 |
/* because we might use IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use IF (dx>max_dx) THEN dx=max_dx; */ |
1580 |
bPredEq = |
bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad); |
1581 |
get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad); |
// bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad); |
1582 |
|
|
1583 |
if ((x == 0) && (y == 0)) { |
if ((x == 0) && (y == 0)) { |
1584 |
threshA = 512 / 4; |
threshA = 512 / 4; |
1865 |
const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; |
const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; |
1866 |
MACROBLOCK *oldMB = NULL; |
MACROBLOCK *oldMB = NULL; |
1867 |
|
|
1868 |
static int32_t thresh2; |
int32_t thresh2; |
1869 |
int32_t bPredEq; |
int32_t bPredEq; |
1870 |
int32_t iMinSAD, iSAD = 9999; |
int32_t iMinSAD, iSAD = 9999; |
1871 |
|
|
1889 |
} |
} |
1890 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
1891 |
bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
1892 |
|
// bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
1893 |
|
|
1894 |
/* Step 4: Calculate SAD around the Median prediction. |
/* Step 4: Calculate SAD around the Median prediction. |
1895 |
MinSAD=SAD |
MinSAD=SAD |
2034 |
|
|
2035 |
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
2036 |
|
|
2037 |
if (MotionFlags & PMV_USESQUARES8) |
if (MotionFlags & PMV_USESQUARES16) |
2038 |
MainSearchPtr = Square16_MainSearch; |
MainSearchPtr = Square16_MainSearch; |
2039 |
else |
else |
2040 |
if (MotionFlags & PMV_ADVANCEDDIAMOND8) |
if (MotionFlags & PMV_ADVANCEDDIAMOND16) |
2041 |
MainSearchPtr = AdvDiamond16_MainSearch; |
MainSearchPtr = AdvDiamond16_MainSearch; |
2042 |
else |
else |
2043 |
MainSearchPtr = Diamond16_MainSearch; |
MainSearchPtr = Diamond16_MainSearch; |
2168 |
} |
} |
2169 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
2170 |
bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv, psad); |
bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv, psad); |
2171 |
|
// bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad); |
2172 |
|
|
2173 |
|
|
2174 |
/* Step 4: Calculate SAD around the Median prediction. |
/* Step 4: Calculate SAD around the Median prediction. |
2402 |
mb->b_mvs[0].y = 0; |
mb->b_mvs[0].y = 0; |
2403 |
continue; |
continue; |
2404 |
} |
} |
2405 |
|
/* force F_SAD16 |
2406 |
|
f_sad16 = 100; |
2407 |
|
b_sad16 = 65535; |
2408 |
|
|
2409 |
|
mb->mode = MODE_FORWARD; |
2410 |
|
mb->mvs[0].x = 1; |
2411 |
|
mb->mvs[0].y = 1; |
2412 |
|
mb->b_mvs[0].x = 1; |
2413 |
|
mb->b_mvs[0].y = 1; |
2414 |
|
continue; |
2415 |
|
^^ force F_SAD16 */ |
2416 |
|
|
2417 |
|
|
2418 |
// forward search |
// forward search |
2419 |
f_sad16 = |
f_sad16 = |
2420 |
SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
2421 |
&frame->image, i, j, frame->motion_flags, |
&frame->image, i, j, frame->motion_flags, |
2422 |
frame->quant, frame->fcode, pParam, f_mbs, |
frame->quant, frame->fcode, pParam, |
2423 |
f_mbs /* todo */ , |
f_mbs, f_mbs, /* todo */ |
2424 |
&mb->mvs[0], &pmv_dontcare); // ignore pmv |
&mb->mvs[0], &pmv_dontcare); // ignore pmv |
2425 |
|
|
2426 |
// backward search |
// backward search |
2427 |
b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, &frame->image, i, j, frame->motion_flags, frame->quant, frame->bcode, pParam, b_mbs, b_mbs, /* todo */ |
b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
2428 |
|
&frame->image, i, j, frame->motion_flags, |
2429 |
|
frame->quant, frame->bcode, pParam, |
2430 |
|
b_mbs, b_mbs, /* todo */ |
2431 |
&mb->b_mvs[0], &pmv_dontcare); // ignore pmv |
&mb->b_mvs[0], &pmv_dontcare); // ignore pmv |
2432 |
|
|
2433 |
// interpolate search (simple, but effective) |
// interpolate search (simple, but effective) |