1 |
|
/***************************************************************************** |
2 |
|
* |
3 |
|
* XVID MPEG-4 VIDEO CODEC |
4 |
|
* - Global Motion Estimation - |
5 |
|
* |
6 |
|
* Copyright(C) 2003 Christoph Lampert <gruel@web.de> |
7 |
|
* |
8 |
|
* This program is free software ; you can redistribute it and/or modify |
9 |
|
* it under the terms of the GNU General Public License as published by |
10 |
|
* the Free Software Foundation ; either version 2 of the License, or |
11 |
|
* (at your option) any later version. |
12 |
|
* |
13 |
|
* This program is distributed in the hope that it will be useful, |
14 |
|
* but WITHOUT ANY WARRANTY ; without even the implied warranty of |
15 |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
* GNU General Public License for more details. |
17 |
|
* |
18 |
|
* You should have received a copy of the GNU General Public License |
19 |
|
* along with this program ; if not, write to the Free Software |
20 |
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 |
|
* |
22 |
|
* $Id$ |
23 |
|
* |
24 |
|
****************************************************************************/ |
25 |
|
|
26 |
|
#include <assert.h> |
27 |
|
#include <stdio.h> |
28 |
|
#include <stdlib.h> |
29 |
|
#include <string.h> |
30 |
|
#include <math.h> |
31 |
|
|
32 |
|
#include "../encoder.h" |
33 |
|
#include "../prediction/mbprediction.h" |
34 |
|
#include "estimation.h" |
35 |
|
#include "motion.h" |
36 |
|
#include "sad.h" |
37 |
|
#include "gmc.h" |
38 |
|
#include "../utils/emms.h" |
39 |
|
#include "motion_inlines.h" |
40 |
|
|
41 |
|
static void |
42 |
|
CheckCandidate16I(const int x, const int y, SearchData * const data, const unsigned int Direction) |
43 |
|
{ |
44 |
|
int sad; |
45 |
|
const uint8_t * Reference; |
46 |
|
|
47 |
|
if ( (x > data->max_dx) || ( x < data->min_dx) |
48 |
|
|| (y > data->max_dy) || (y < data->min_dy) ) return; |
49 |
|
|
50 |
|
Reference = GetReference(x, y, data); |
51 |
|
|
52 |
|
sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096); |
53 |
|
|
54 |
|
if (sad < data->iMinSAD[0]) { |
55 |
|
data->iMinSAD[0] = sad; |
56 |
|
data->currentMV[0].x = x; data->currentMV[0].y = y; |
57 |
|
data->dir = Direction; |
58 |
|
} |
59 |
|
} |
60 |
|
|
61 |
|
static __inline void |
62 |
|
GMEanalyzeMB ( const uint8_t * const pCur, |
63 |
|
const uint8_t * const pRef, |
64 |
|
const uint8_t * const pRefH, |
65 |
|
const uint8_t * const pRefV, |
66 |
|
const uint8_t * const pRefHV, |
67 |
|
const int x, |
68 |
|
const int y, |
69 |
|
const MBParam * const pParam, |
70 |
|
MACROBLOCK * const pMBs, |
71 |
|
SearchData * const Data) |
72 |
|
{ |
73 |
|
|
74 |
|
MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width]; |
75 |
|
|
76 |
|
Data->iMinSAD[0] = MV_MAX_ERROR; |
77 |
|
|
78 |
|
Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); |
79 |
|
|
80 |
|
get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4, |
81 |
|
pParam->width, pParam->height, 16, 1, 0); |
82 |
|
|
83 |
|
Data->Cur = pCur + 16*(x + y * pParam->edged_width); |
84 |
|
Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width); |
85 |
|
Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width); |
86 |
|
Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width); |
87 |
|
Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width); |
88 |
|
|
89 |
|
Data->currentMV[0].x = Data->currentMV[0].y = 0; |
90 |
|
CheckCandidate16I(0, 0, Data, 255); |
91 |
|
|
92 |
|
if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) ) |
93 |
|
CheckCandidate16I(Data->predMV.x, Data->predMV.y, Data, 255); |
94 |
|
|
95 |
|
xvid_me_DiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255, CheckCandidate16I); |
96 |
|
|
97 |
|
xvid_me_SubpelRefine(Data, CheckCandidate16I); |
98 |
|
|
99 |
|
|
100 |
|
/* for QPel halfpel positions are worse than in halfpel mode :( */ |
101 |
|
/* if (Data->qpel) { |
102 |
|
Data->currentQMV->x = 2*Data->currentMV->x; |
103 |
|
Data->currentQMV->y = 2*Data->currentMV->y; |
104 |
|
Data->qpel_precision = 1; |
105 |
|
get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4, |
106 |
|
pParam->width, pParam->height, iFcode, 2, 0); |
107 |
|
SubpelRefine(Data); |
108 |
|
} |
109 |
|
*/ |
110 |
|
|
111 |
|
pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0]; |
112 |
|
pMB->sad16 = Data->iMinSAD[0]; |
113 |
|
pMB->mode = MODE_INTER; |
114 |
|
pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0); |
115 |
|
return; |
116 |
|
} |
117 |
|
|
118 |
|
|
119 |
|
void |
120 |
|
GMEanalysis(const MBParam * const pParam, |
121 |
|
const FRAMEINFO * const current, |
122 |
|
const FRAMEINFO * const reference, |
123 |
|
const IMAGE * const pRefH, |
124 |
|
const IMAGE * const pRefV, |
125 |
|
const IMAGE * const pRefHV) |
126 |
|
{ |
127 |
|
uint32_t x, y; |
128 |
|
MACROBLOCK * const pMBs = current->mbs; |
129 |
|
const IMAGE * const pCurrent = ¤t->image; |
130 |
|
const IMAGE * const pReference = &reference->image; |
131 |
|
|
132 |
|
SearchData Data; |
133 |
|
memset(&Data, 0, sizeof(SearchData)); |
134 |
|
|
135 |
|
Data.iEdgedWidth = pParam->edged_width; |
136 |
|
Data.rounding = pParam->m_rounding_type; |
137 |
|
|
138 |
|
Data.iFcode = current->fcode; |
139 |
|
|
140 |
|
if (sadInit) (*sadInit) (); |
141 |
|
|
142 |
|
for (y = 0; y < pParam->mb_height; y ++) { |
143 |
|
for (x = 0; x < pParam->mb_width; x ++) { |
144 |
|
GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data); |
145 |
|
} |
146 |
|
} |
147 |
|
return; |
148 |
|
} |
149 |
|
|
150 |
|
WARPPOINTS |
151 |
|
GlobalMotionEst(MACROBLOCK * const pMBs, |
152 |
|
const MBParam * const pParam, |
153 |
|
const FRAMEINFO * const current, |
154 |
|
const FRAMEINFO * const reference, |
155 |
|
const IMAGE * const pRefH, |
156 |
|
const IMAGE * const pRefV, |
157 |
|
const IMAGE * const pRefHV) |
158 |
|
{ |
159 |
|
|
160 |
|
const int deltax=8; /* upper bound for difference between a MV and it's neighbour MVs */ |
161 |
|
const int deltay=8; |
162 |
|
const unsigned int gradx=512; /* lower bound for gradient in MB (ignore "flat" blocks) */ |
163 |
|
const unsigned int grady=512; |
164 |
|
|
165 |
|
double sol[4] = { 0., 0., 0., 0. }; |
166 |
|
|
167 |
|
WARPPOINTS gmc; |
168 |
|
|
169 |
|
uint32_t mx, my; |
170 |
|
|
171 |
|
int MBh = pParam->mb_height; |
172 |
|
int MBw = pParam->mb_width; |
173 |
|
const int minblocks = 9; /* was = /MBh*MBw/32+3 */ /* just some reasonable number 3% + 3 */ |
174 |
|
const int maxblocks = MBh*MBw/4; /* just some reasonable number 3% + 3 */ |
175 |
|
|
176 |
|
int num=0; |
177 |
|
int oldnum; |
178 |
|
|
179 |
|
gmc.duv[0].x = gmc.duv[0].y = gmc.duv[1].x = gmc.duv[1].y = gmc.duv[2].x = gmc.duv[2].y = 0; |
180 |
|
|
181 |
|
GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV); |
182 |
|
|
183 |
|
/* block based ME isn't done, yet, so do a quick presearch */ |
184 |
|
|
185 |
|
/* filter mask of all blocks */ |
186 |
|
|
187 |
|
for (my = 0; my < (uint32_t)MBh; my++) |
188 |
|
for (mx = 0; mx < (uint32_t)MBw; mx++) |
189 |
|
{ |
190 |
|
const int mbnum = mx + my * MBw; |
191 |
|
pMBs[mbnum].mcsel = 0; |
192 |
|
} |
193 |
|
|
194 |
|
|
195 |
|
for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */ |
196 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */ |
197 |
|
{ |
198 |
|
const int mbnum = mx + my * MBw; |
199 |
|
MACROBLOCK *const pMB = &pMBs[mbnum]; |
200 |
|
const VECTOR mv = pMB->mvs[0]; |
201 |
|
|
202 |
|
/* don't use object boundaries */ |
203 |
|
if ( (abs(mv.x - (pMB-1)->mvs[0].x) < deltax) |
204 |
|
&& (abs(mv.y - (pMB-1)->mvs[0].y) < deltay) |
205 |
|
&& (abs(mv.x - (pMB+1)->mvs[0].x) < deltax) |
206 |
|
&& (abs(mv.y - (pMB+1)->mvs[0].y) < deltay) |
207 |
|
&& (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax) |
208 |
|
&& (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay) |
209 |
|
&& (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax) |
210 |
|
&& (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) |
211 |
|
{ const int iEdgedWidth = pParam->edged_width; |
212 |
|
const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx); |
213 |
|
if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx ) |
214 |
|
&& (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) ) |
215 |
|
{ pMB->mcsel = 1; |
216 |
|
num++; |
217 |
|
} |
218 |
|
|
219 |
|
/* only use "structured" blocks */ |
220 |
|
} |
221 |
|
} |
222 |
|
emms(); |
223 |
|
|
224 |
|
/* further filtering would be possible, but during iteration, remaining |
225 |
|
outliers usually are removed, too */ |
226 |
|
|
227 |
|
if (num>= minblocks) |
228 |
|
do { /* until convergence */ |
229 |
|
double DtimesF[4]; |
230 |
|
double a,b,c,n,invdenom; |
231 |
|
double meanx,meany; |
232 |
|
|
233 |
|
a = b = c = n = 0; |
234 |
|
DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.; |
235 |
|
for (my = 1; my < (uint32_t)MBh-1; my++) |
236 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) |
237 |
|
{ |
238 |
|
const int mbnum = mx + my * MBw; |
239 |
|
const VECTOR mv = pMBs[mbnum].mvs[0]; |
240 |
|
|
241 |
|
if (!pMBs[mbnum].mcsel) |
242 |
|
continue; |
243 |
|
|
244 |
|
n++; |
245 |
|
a += 16*mx+8; |
246 |
|
b += 16*my+8; |
247 |
|
c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8); |
248 |
|
|
249 |
|
DtimesF[0] += (double)mv.x; |
250 |
|
DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8); |
251 |
|
DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8); |
252 |
|
DtimesF[3] += (double)mv.y; |
253 |
|
} |
254 |
|
|
255 |
|
invdenom = a*a+b*b-c*n; |
256 |
|
|
257 |
|
/* Solve the system: sol = (D'*E*D)^{-1} D'*E*F */ |
258 |
|
/* D'*E*F has been calculated in the same loop as matrix */ |
259 |
|
|
260 |
|
sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2]; |
261 |
|
sol[1] = a*DtimesF[0] - n*DtimesF[1] + b*DtimesF[3]; |
262 |
|
sol[2] = b*DtimesF[0] - n*DtimesF[2] - a*DtimesF[3]; |
263 |
|
sol[3] = b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3]; |
264 |
|
|
265 |
|
sol[0] /= invdenom; |
266 |
|
sol[1] /= invdenom; |
267 |
|
sol[2] /= invdenom; |
268 |
|
sol[3] /= invdenom; |
269 |
|
|
270 |
|
meanx = meany = 0.; |
271 |
|
oldnum = 0; |
272 |
|
for (my = 1; my < (uint32_t)MBh-1; my++) |
273 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) |
274 |
|
{ |
275 |
|
const int mbnum = mx + my * MBw; |
276 |
|
const VECTOR mv = pMBs[mbnum].mvs[0]; |
277 |
|
|
278 |
|
if (!pMBs[mbnum].mcsel) |
279 |
|
continue; |
280 |
|
|
281 |
|
oldnum++; |
282 |
|
meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ); |
283 |
|
meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ); |
284 |
|
} |
285 |
|
|
286 |
|
if (4*meanx > oldnum) /* better fit than 0.25 (=1/4pel) is useless */ |
287 |
|
meanx /= oldnum; |
288 |
|
else |
289 |
|
meanx = 0.25; |
290 |
|
|
291 |
|
if (4*meany > oldnum) |
292 |
|
meany /= oldnum; |
293 |
|
else |
294 |
|
meany = 0.25; |
295 |
|
|
296 |
|
num = 0; |
297 |
|
for (my = 0; my < (uint32_t)MBh; my++) |
298 |
|
for (mx = 0; mx < (uint32_t)MBw; mx++) |
299 |
|
{ |
300 |
|
const int mbnum = mx + my * MBw; |
301 |
|
const VECTOR mv = pMBs[mbnum].mvs[0]; |
302 |
|
|
303 |
|
if (!pMBs[mbnum].mcsel) |
304 |
|
continue; |
305 |
|
|
306 |
|
if ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx ) |
307 |
|
|| ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) ) |
308 |
|
pMBs[mbnum].mcsel=0; |
309 |
|
else |
310 |
|
num++; |
311 |
|
} |
312 |
|
|
313 |
|
} while ( (oldnum != num) && (num>= minblocks) ); |
314 |
|
|
315 |
|
if (num < minblocks) |
316 |
|
{ |
317 |
|
const int iEdgedWidth = pParam->edged_width; |
318 |
|
num = 0; |
319 |
|
|
320 |
|
/* fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw); |
321 |
|
*/ |
322 |
|
gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0; |
323 |
|
|
324 |
|
if (!(current->motion_flags & XVID_ME_GME_REFINE)) |
325 |
|
return gmc; |
326 |
|
|
327 |
|
for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */ |
328 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */ |
329 |
|
{ |
330 |
|
const int mbnum = mx + my * MBw; |
331 |
|
MACROBLOCK *const pMB = &pMBs[mbnum]; |
332 |
|
const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx); |
333 |
|
if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx ) |
334 |
|
&& (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) ) |
335 |
|
{ pMB->mcsel = 1; |
336 |
|
gmc.duv[0].x += pMB->mvs[0].x; |
337 |
|
gmc.duv[0].y += pMB->mvs[0].y; |
338 |
|
num++; |
339 |
|
} |
340 |
|
} |
341 |
|
|
342 |
|
if (gmc.duv[0].x) |
343 |
|
gmc.duv[0].x /= num; |
344 |
|
if (gmc.duv[0].y) |
345 |
|
gmc.duv[0].y /= num; |
346 |
|
} else { |
347 |
|
|
348 |
|
gmc.duv[0].x=(int)(sol[0]+0.5); |
349 |
|
gmc.duv[0].y=(int)(sol[3]+0.5); |
350 |
|
|
351 |
|
gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5); |
352 |
|
gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5); |
353 |
|
|
354 |
|
gmc.duv[2].x=-gmc.duv[1].y; /* two warp points only */ |
355 |
|
gmc.duv[2].y=gmc.duv[1].x; |
356 |
|
} |
357 |
|
if (num>maxblocks) |
358 |
|
{ for (my = 1; my < (uint32_t)MBh-1; my++) |
359 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) |
360 |
|
{ |
361 |
|
const int mbnum = mx + my * MBw; |
362 |
|
if (pMBs[mbnum-1].mcsel) |
363 |
|
pMBs[mbnum].mcsel=0; |
364 |
|
else |
365 |
|
if (pMBs[mbnum-MBw].mcsel) |
366 |
|
pMBs[mbnum].mcsel=0; |
367 |
|
} |
368 |
|
} |
369 |
|
return gmc; |
370 |
|
} |
371 |
|
|
372 |
|
int |
373 |
|
GlobalMotionEstRefine( |
374 |
|
WARPPOINTS *const startwp, |
375 |
|
MACROBLOCK * const pMBs, |
376 |
|
const MBParam * const pParam, |
377 |
|
const FRAMEINFO * const current, |
378 |
|
const FRAMEINFO * const reference, |
379 |
|
const IMAGE * const pCurr, |
380 |
|
const IMAGE * const pRef, |
381 |
|
const IMAGE * const pRefH, |
382 |
|
const IMAGE * const pRefV, |
383 |
|
const IMAGE * const pRefHV) |
384 |
|
{ |
385 |
|
uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width); |
386 |
|
WARPPOINTS bestwp=*startwp; |
387 |
|
WARPPOINTS centerwp,currwp; |
388 |
|
int gmcminSAD=0; |
389 |
|
int gmcSAD=0; |
390 |
|
int direction; |
391 |
|
#if 0 |
392 |
|
int mx,my; |
393 |
|
#endif |
394 |
|
|
395 |
|
#if 0 |
396 |
|
/* use many blocks... */ |
397 |
|
for (my = 0; my < (uint32_t)pParam->mb_height; my++) { |
398 |
|
for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) { |
399 |
|
const int mbnum = mx + my * pParam->mb_width; |
400 |
|
pMBs[mbnum].mcsel=1; |
401 |
|
} |
402 |
|
} |
403 |
|
#endif |
404 |
|
|
405 |
|
#if 0 |
406 |
|
/* or rather don't use too many blocks... */ |
407 |
|
for (my = 1; my < (uint32_t)MBh-1; my++) { |
408 |
|
for (mx = 1; mx < (uint32_t)MBw-1; mx++) { |
409 |
|
const int mbnum = mx + my * MBw; |
410 |
|
if (MBmask[mbnum-1]) |
411 |
|
MBmask[mbnum-1]=0; |
412 |
|
else |
413 |
|
if (MBmask[mbnum-MBw]) |
414 |
|
MBmask[mbnum-1]=0; |
415 |
|
|
416 |
|
} |
417 |
|
} |
418 |
|
#endif |
419 |
|
|
420 |
|
gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
421 |
|
|
422 |
|
if ( (reference->coding_type == S_VOP) |
423 |
|
&& ( (reference->warp.duv[1].x != bestwp.duv[1].x) |
424 |
|
|| (reference->warp.duv[1].y != bestwp.duv[1].y) |
425 |
|
|| (reference->warp.duv[0].x != bestwp.duv[0].x) |
426 |
|
|| (reference->warp.duv[0].y != bestwp.duv[0].y) |
427 |
|
|| (reference->warp.duv[2].x != bestwp.duv[2].x) |
428 |
|
|| (reference->warp.duv[2].y != bestwp.duv[2].y) ) ) |
429 |
|
{ |
430 |
|
gmcSAD = globalSAD(&reference->warp, pParam, pMBs, |
431 |
|
current, pRef, pCurr, GMCblock); |
432 |
|
|
433 |
|
if (gmcSAD < gmcminSAD) |
434 |
|
{ bestwp = reference->warp; |
435 |
|
gmcminSAD = gmcSAD; |
436 |
|
} |
437 |
|
} |
438 |
|
|
439 |
|
do { |
440 |
|
direction = 0; |
441 |
|
centerwp = bestwp; |
442 |
|
|
443 |
|
currwp = centerwp; |
444 |
|
|
445 |
|
currwp.duv[0].x--; |
446 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
447 |
|
if (gmcSAD < gmcminSAD) |
448 |
|
{ bestwp = currwp; |
449 |
|
gmcminSAD = gmcSAD; |
450 |
|
direction = 1; |
451 |
|
} |
452 |
|
else |
453 |
|
{ |
454 |
|
currwp = centerwp; currwp.duv[0].x++; |
455 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
456 |
|
if (gmcSAD < gmcminSAD) |
457 |
|
{ bestwp = currwp; |
458 |
|
gmcminSAD = gmcSAD; |
459 |
|
direction = 2; |
460 |
|
} |
461 |
|
} |
462 |
|
if (direction) continue; |
463 |
|
|
464 |
|
currwp = centerwp; currwp.duv[0].y--; |
465 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
466 |
|
if (gmcSAD < gmcminSAD) |
467 |
|
{ bestwp = currwp; |
468 |
|
gmcminSAD = gmcSAD; |
469 |
|
direction = 4; |
470 |
|
} |
471 |
|
else |
472 |
|
{ |
473 |
|
currwp = centerwp; currwp.duv[0].y++; |
474 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
475 |
|
if (gmcSAD < gmcminSAD) |
476 |
|
{ bestwp = currwp; |
477 |
|
gmcminSAD = gmcSAD; |
478 |
|
direction = 8; |
479 |
|
} |
480 |
|
} |
481 |
|
if (direction) continue; |
482 |
|
|
483 |
|
currwp = centerwp; currwp.duv[1].x++; |
484 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
485 |
|
if (gmcSAD < gmcminSAD) |
486 |
|
{ bestwp = currwp; |
487 |
|
gmcminSAD = gmcSAD; |
488 |
|
direction = 32; |
489 |
|
} |
490 |
|
currwp.duv[2].y++; |
491 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
492 |
|
if (gmcSAD < gmcminSAD) |
493 |
|
{ bestwp = currwp; |
494 |
|
gmcminSAD = gmcSAD; |
495 |
|
direction = 1024; |
496 |
|
} |
497 |
|
|
498 |
|
currwp = centerwp; currwp.duv[1].x--; |
499 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
500 |
|
if (gmcSAD < gmcminSAD) |
501 |
|
{ bestwp = currwp; |
502 |
|
gmcminSAD = gmcSAD; |
503 |
|
direction = 16; |
504 |
|
} |
505 |
|
else |
506 |
|
{ |
507 |
|
currwp = centerwp; currwp.duv[1].x++; |
508 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
509 |
|
if (gmcSAD < gmcminSAD) |
510 |
|
{ bestwp = currwp; |
511 |
|
gmcminSAD = gmcSAD; |
512 |
|
direction = 32; |
513 |
|
} |
514 |
|
} |
515 |
|
if (direction) continue; |
516 |
|
|
517 |
|
|
518 |
|
currwp = centerwp; currwp.duv[1].y--; |
519 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
520 |
|
if (gmcSAD < gmcminSAD) |
521 |
|
{ bestwp = currwp; |
522 |
|
gmcminSAD = gmcSAD; |
523 |
|
direction = 64; |
524 |
|
} |
525 |
|
else |
526 |
|
{ |
527 |
|
currwp = centerwp; currwp.duv[1].y++; |
528 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
529 |
|
if (gmcSAD < gmcminSAD) |
530 |
|
{ bestwp = currwp; |
531 |
|
gmcminSAD = gmcSAD; |
532 |
|
direction = 128; |
533 |
|
} |
534 |
|
} |
535 |
|
if (direction) continue; |
536 |
|
|
537 |
|
currwp = centerwp; currwp.duv[2].x--; |
538 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
539 |
|
if (gmcSAD < gmcminSAD) |
540 |
|
{ bestwp = currwp; |
541 |
|
gmcminSAD = gmcSAD; |
542 |
|
direction = 256; |
543 |
|
} |
544 |
|
else |
545 |
|
{ |
546 |
|
currwp = centerwp; currwp.duv[2].x++; |
547 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
548 |
|
if (gmcSAD < gmcminSAD) |
549 |
|
{ bestwp = currwp; |
550 |
|
gmcminSAD = gmcSAD; |
551 |
|
direction = 512; |
552 |
|
} |
553 |
|
} |
554 |
|
if (direction) continue; |
555 |
|
|
556 |
|
currwp = centerwp; currwp.duv[2].y--; |
557 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
558 |
|
if (gmcSAD < gmcminSAD) |
559 |
|
{ bestwp = currwp; |
560 |
|
gmcminSAD = gmcSAD; |
561 |
|
direction = 1024; |
562 |
|
} |
563 |
|
else |
564 |
|
{ |
565 |
|
currwp = centerwp; currwp.duv[2].y++; |
566 |
|
gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock); |
567 |
|
if (gmcSAD < gmcminSAD) |
568 |
|
{ bestwp = currwp; |
569 |
|
gmcminSAD = gmcSAD; |
570 |
|
direction = 2048; |
571 |
|
} |
572 |
|
} |
573 |
|
} while (direction); |
574 |
|
free(GMCblock); |
575 |
|
|
576 |
|
*startwp = bestwp; |
577 |
|
|
578 |
|
return gmcminSAD; |
579 |
|
} |
580 |
|
|
581 |
|
int |
582 |
|
globalSAD(const WARPPOINTS *const wp, |
583 |
|
const MBParam * const pParam, |
584 |
|
const MACROBLOCK * const pMBs, |
585 |
|
const FRAMEINFO * const current, |
586 |
|
const IMAGE * const pRef, |
587 |
|
const IMAGE * const pCurr, |
588 |
|
uint8_t *const GMCblock) |
589 |
|
{ |
590 |
|
NEW_GMC_DATA gmc_data; |
591 |
|
int iSAD, gmcSAD=0; |
592 |
|
int num=0; |
593 |
|
unsigned int mx, my; |
594 |
|
|
595 |
|
generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data); |
596 |
|
|
597 |
|
for (my = 0; my < (uint32_t)pParam->mb_height; my++) |
598 |
|
for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) { |
599 |
|
|
600 |
|
const int mbnum = mx + my * pParam->mb_width; |
601 |
|
const int iEdgedWidth = pParam->edged_width; |
602 |
|
|
603 |
|
if (!pMBs[mbnum].mcsel) |
604 |
|
continue; |
605 |
|
|
606 |
|
gmc_data.predict_16x16(&gmc_data, GMCblock, |
607 |
|
pRef->y, |
608 |
|
iEdgedWidth, |
609 |
|
iEdgedWidth, |
610 |
|
mx, my, |
611 |
|
pParam->m_rounding_type); |
612 |
|
|
613 |
|
iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx), |
614 |
|
GMCblock , iEdgedWidth, 65536); |
615 |
|
iSAD -= pMBs[mbnum].sad16; |
616 |
|
|
617 |
|
if (iSAD<0) |
618 |
|
gmcSAD += iSAD; |
619 |
|
num++; |
620 |
|
} |
621 |
|
return gmcSAD; |
622 |
|
} |