[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Annotation of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 530 - (view) (download)

1 : Isibaar 3 /**************************************************************************
2 :     *
3 : chl 259 * 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 : Isibaar 3 #include <assert.h>
32 :     #include <stdio.h>
33 : chl 96 #include <stdlib.h>
34 : Isibaar 3
35 :     #include "../encoder.h"
36 :     #include "../utils/mbfunctions.h"
37 :     #include "../prediction/mbprediction.h"
38 :     #include "../global.h"
39 :     #include "../utils/timer.h"
40 : chl 530 #include "motion_est.h"
41 : suxen_drol 118 #include "motion.h"
42 : Isibaar 3 #include "sad.h"
43 :    
44 : chl 530 #define INITIAL_SKIP_THRESH (10)
45 :     #define FINAL_SKIP_THRESH (50)
46 :     #define MAX_SAD00_FOR_SKIP (20)
47 :     #define MAX_CHROMA_SAD_FOR_SKIP (18)
48 :     #define SKIP_THRESH_B (10)
49 : Isibaar 3
50 : chl 530 #define CHECK_CANDIDATE(X,Y,D) { \
51 :     (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
52 : Isibaar 3
53 : chl 530 #define iDiamondSize 2
54 : chl 141
55 : chl 530 //FILE * debug;
56 : chl 141
57 : chl 530 static __inline int
58 :     d_mv_bits(int x, int y, const uint32_t iFcode)
59 : Isibaar 3 {
60 : chl 530 int xb, yb;
61 :    
62 :     if (x == 0) xb = 1;
63 :     else {
64 :     if (x < 0) x = -x;
65 :     x += (1 << (iFcode - 1)) - 1;
66 :     x >>= (iFcode - 1);
67 :     if (x > 32) x = 32;
68 :     xb = mvtab[x] + iFcode;
69 : edgomez 195 }
70 : Isibaar 3
71 : chl 530 if (y == 0) yb = 1;
72 :     else {
73 :     if (y < 0) y = -y;
74 :     y += (1 << (iFcode - 1)) - 1;
75 :     y >>= (iFcode - 1);
76 :     if (y > 32) y = 32;
77 :     yb = mvtab[y] + iFcode;
78 :     }
79 :     return xb + yb;
80 : Isibaar 3 }
81 :    
82 : chl 530 /* CHACK_CANDIATE FUNCTIONS START */
83 : Isibaar 3
84 : chl 530 static void
85 :     CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
86 : Isibaar 3 {
87 : chl 530 int32_t * const sad = data->temp;
88 :     // static int32_t sad[5];
89 :     int t;
90 :     const uint8_t * Reference;
91 : Isibaar 3
92 : chl 530 if (( x > data->max_dx) || ( x < data->min_dx)
93 :     || ( y > data->max_dy) || (y < data->min_dy)) return;
94 : suxen_drol 136
95 : chl 530 switch ( ((x&1)<<1) + (y&1) ) {
96 :     case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
97 :     case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
98 :     case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
99 :     default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
100 :     }
101 : chl 259
102 : chl 530 data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, sad+1);
103 : Isibaar 3
104 : chl 530 t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
105 :     data->temp[0] += lambda_vec16[data->iQuant] * t;
106 :     data->temp[1] += lambda_vec8[data->iQuant] * t;
107 : chl 326
108 : chl 530 if (data->temp[0] < data->iMinSAD[0]) {
109 :     data->iMinSAD[0] = data->temp[0];
110 :     data->currentMV[0].x = x; data->currentMV[0].y = y;
111 :     *dir = Direction; }
112 : chl 184
113 : chl 530 if (data->temp[1] < data->iMinSAD[1]) {
114 :     data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
115 :     if (data->temp[2] < data->iMinSAD[2]) {
116 :     data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
117 :     if (data->temp[3] < data->iMinSAD[3]) {
118 :     data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
119 :     if (data->temp[4] < data->iMinSAD[4]) {
120 :     data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
121 : chl 184
122 : Isibaar 3 }
123 :    
124 : chl 530 static void
125 :     CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
126 :     {
127 :     int32_t sad;
128 :     const uint8_t * Reference;
129 : chl 326
130 : chl 530 if (( x > data->max_dx) || ( x < data->min_dx)
131 :     || ( y > data->max_dy) || (y < data->min_dy)) return;
132 : Isibaar 3
133 : chl 530 switch ( ((x&1)<<1) + (y&1) )
134 :     {
135 :     case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
136 :     case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
137 :     case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
138 :     default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
139 :     }
140 : Isibaar 3
141 : chl 530 sad = lambda_vec16[data->iQuant] *
142 :     d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
143 :     sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
144 : Isibaar 3
145 : chl 530 if (sad < *(data->iMinSAD)) {
146 :     *(data->iMinSAD) = sad;
147 :     data->currentMV[0].x = x; data->currentMV[0].y = y;
148 :     *dir = Direction; }
149 : Isibaar 3 }
150 :    
151 : chl 530 static void
152 :     CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
153 :     {
154 :     int32_t sad;
155 :     const int xb = data->currentMV[1].x;
156 :     const int yb = data->currentMV[1].y;
157 :     const uint8_t *ReferenceF, *ReferenceB;
158 : Isibaar 3
159 : chl 530 if (( xf > data->max_dx) || ( xf < data->min_dx)
160 :     || ( yf > data->max_dy) || (yf < data->min_dy)) return;
161 : Isibaar 3
162 : chl 530 switch ( ((xf&1)<<1) + (yf&1) ) {
163 :     case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
164 :     case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
165 :     case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
166 :     default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
167 :     }
168 : edgomez 195
169 : chl 530 switch ( ((xb&1)<<1) + (yb&1) ) {
170 :     case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
171 :     case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
172 :     case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
173 :     default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
174 :     }
175 : Isibaar 3
176 : chl 530 sad = lambda_vec16[data->iQuant] *
177 :     ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
178 :     d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );
179 : Isibaar 3
180 : chl 530 sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
181 : Isibaar 3
182 : chl 530 if (sad < *(data->iMinSAD)) {
183 :     *(data->iMinSAD) = sad;
184 :     data->currentMV->x = xf; data->currentMV->y = yf;
185 :     *dir = Direction; }
186 : Isibaar 3 }
187 :    
188 : chl 530 static void
189 :     CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
190 : Isibaar 3 {
191 : chl 530 int32_t sad;
192 :     int k;
193 :     const uint8_t *ReferenceF;
194 :     const uint8_t *ReferenceB;
195 :     VECTOR mvs, b_mvs;
196 : Isibaar 3
197 : chl 530 if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
198 : Isibaar 3
199 : chl 530 sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
200 : Isibaar 3
201 : chl 530 for (k = 0; k < 4; k++) {
202 :     mvs.x = data->directmvF[k].x + x;
203 :     b_mvs.x = ((x == 0) ?
204 :     data->directmvB[k].x
205 :     : mvs.x - data->referencemv[k].x);
206 : Isibaar 3
207 : chl 530 mvs.y = data->directmvF[k].y + y;
208 :     b_mvs.y = ((y == 0) ?
209 :     data->directmvB[k].y
210 :     : mvs.y - data->referencemv[k].y);
211 :    
212 :     if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
213 :     || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
214 :     || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
215 :     || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
216 : Isibaar 3
217 : chl 530 switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
218 :     case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
219 :     case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
220 :     case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
221 :     default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
222 :     }
223 : Isibaar 3
224 : chl 530 switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
225 :     case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
226 :     case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
227 :     case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
228 :     default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
229 : chl 344 }
230 : chl 530
231 :     sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
232 :     ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
233 :     ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
234 :     data->iEdgedWidth);
235 :     if (sad > *(data->iMinSAD)) return;
236 : edgomez 78 }
237 : chl 530
238 :     if (sad < *(data->iMinSAD)) {
239 :     *(data->iMinSAD) = sad;
240 :     data->currentMV->x = x; data->currentMV->y = y;
241 :     *dir = Direction; }
242 : Isibaar 3 }
243 :    
244 : chl 530 static void
245 :     CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
246 : chl 96 {
247 : chl 530 int32_t sad;
248 :     const uint8_t *ReferenceF;
249 :     const uint8_t *ReferenceB;
250 :     VECTOR mvs, b_mvs;
251 : chl 96
252 : chl 530 if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;
253 :    
254 :     sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
255 : edgomez 195
256 : chl 530 mvs.x = data->directmvF[0].x + x;
257 :     b_mvs.x = ((x == 0) ?
258 :     data->directmvB[0].x
259 :     : mvs.x - data->referencemv[0].x);
260 : edgomez 195
261 : chl 530 mvs.y = data->directmvF[0].y + y;
262 :     b_mvs.y = ((y == 0) ?
263 :     data->directmvB[0].y
264 :     : mvs.y - data->referencemv[0].y);
265 :    
266 :     if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
267 :     || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
268 :     || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
269 :     || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
270 : chl 96
271 : chl 530 switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
272 :     case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
273 :     case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
274 :     case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
275 :     default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
276 :     }
277 : chl 96
278 : chl 530 switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
279 :     case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
280 :     case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
281 :     case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
282 :     default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
283 :     }
284 :    
285 :     sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
286 : chl 96
287 : chl 530 if (sad < *(data->iMinSAD)) {
288 :     *(data->iMinSAD) = sad;
289 :     data->currentMV->x = x; data->currentMV->y = y;
290 :     *dir = Direction; }
291 :     }
292 : chl 96
293 : chl 530 static void
294 :     CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
295 :     {
296 :     int32_t sad;
297 :     const uint8_t * Reference;
298 : edgomez 195
299 : chl 530 if (( x > data->max_dx) || ( x < data->min_dx)
300 :     || ( y > data->max_dy) || (y < data->min_dy)) return;
301 : chl 96
302 : chl 530 switch ( ((x&1)<<1) + (y&1) )
303 :     {
304 :     case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
305 :     case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
306 :     case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
307 :     default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
308 :     }
309 : edgomez 195
310 : chl 530 sad = sad8(data->Cur, Reference, data->iEdgedWidth);
311 :     sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
312 : edgomez 195
313 : chl 530 if (sad < *(data->iMinSAD)) {
314 :     *(data->iMinSAD) = sad;
315 :     data->currentMV->x = x; data->currentMV->y = y;
316 :     *dir = Direction; }
317 : chl 96 }
318 :    
319 : chl 530 /* CHACK_CANDIATE FUNCTIONS END */
320 : chl 96
321 : chl 530 /* MAINSEARCH FUNCTIONS START */
322 : edgomez 195
323 : chl 530 static void
324 :     AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
325 : chl 181 {
326 :    
327 :     /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
328 :    
329 : chl 530 int iDirection;
330 : edgomez 195
331 :     do {
332 : chl 181 iDirection = 0;
333 : chl 530 if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
334 :     if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
335 :     if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
336 :     if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
337 : chl 181
338 :     /* now we're doing diagonal checks near our candidate */
339 :    
340 : chl 530 if (iDirection) { //checking if anything found
341 : chl 181 bDirection = iDirection;
342 :     iDirection = 0;
343 : chl 530 x = data->currentMV->x; y = data->currentMV->y;
344 :     if (bDirection & 3) { //our candidate is left or right
345 :     CHECK_CANDIDATE(x, y + iDiamondSize, 8);
346 :     CHECK_CANDIDATE(x, y - iDiamondSize, 4);
347 :     } else { // what remains here is up or down
348 :     CHECK_CANDIDATE(x + iDiamondSize, y, 2);
349 :     CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
350 : chl 181
351 : edgomez 195 if (iDirection) {
352 :     bDirection += iDirection;
353 : chl 530 x = data->currentMV->x; y = data->currentMV->y; }
354 :     } else { //about to quit, eh? not so fast....
355 : edgomez 195 switch (bDirection) {
356 : chl 181 case 2:
357 : chl 530 CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
358 :     CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
359 : chl 181 break;
360 :     case 1:
361 : chl 530 CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
362 :     CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
363 : chl 181 break;
364 : edgomez 195 case 2 + 4:
365 : chl 530 CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
366 :     CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
367 :     CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
368 : chl 181 break;
369 :     case 4:
370 : chl 530 CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
371 :     CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
372 : chl 181 break;
373 :     case 8:
374 : chl 530 CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
375 :     CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
376 : chl 181 break;
377 : edgomez 195 case 1 + 4:
378 : chl 530 CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
379 :     CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
380 :     CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
381 : chl 181 break;
382 : edgomez 195 case 2 + 8:
383 : chl 530 CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
384 :     CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
385 :     CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
386 : chl 181 break;
387 : edgomez 195 case 1 + 8:
388 : chl 530 CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
389 :     CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
390 :     CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
391 : chl 181 break;
392 : edgomez 195 default: //1+2+4+8 == we didn't find anything at all
393 : chl 530 CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
394 :     CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
395 :     CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
396 :     CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
397 : chl 181 break;
398 :     }
399 : chl 530 if (!iDirection) break; //ok, the end. really
400 :     bDirection = iDirection;
401 :     x = data->currentMV->x; y = data->currentMV->y;
402 : chl 181 }
403 :     }
404 : edgomez 195 while (1); //forever
405 : chl 181 }
406 :    
407 : chl 530 static void
408 :     SquareSearch(int x, int y, const SearchData * const data, int bDirection)
409 : chl 326 {
410 : chl 530 int iDirection;
411 : chl 326
412 : chl 530 do {
413 :     iDirection = 0;
414 :     if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
415 :     if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
416 :     if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
417 :     if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
418 :     if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
419 :     if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
420 :     if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
421 :     if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
422 : chl 326
423 : chl 530 bDirection = iDirection;
424 :     x = data->currentMV->x; y = data->currentMV->y;
425 :     } while (iDirection);
426 : chl 346 }
427 :    
428 : chl 530 static void
429 :     DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
430 : chl 346 {
431 :    
432 : chl 181 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
433 :    
434 : chl 530 int iDirection;
435 : edgomez 195
436 :     do {
437 : chl 181 iDirection = 0;
438 : chl 530 if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
439 :     if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
440 :     if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
441 :     if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
442 : chl 181
443 :     /* now we're doing diagonal checks near our candidate */
444 :    
445 : chl 530 if (iDirection) { //checking if anything found
446 : chl 181 bDirection = iDirection;
447 :     iDirection = 0;
448 : chl 530 x = data->currentMV->x; y = data->currentMV->y;
449 :     if (bDirection & 3) { //our candidate is left or right
450 :     CHECK_CANDIDATE(x, y + iDiamondSize, 8);
451 :     CHECK_CANDIDATE(x, y - iDiamondSize, 4);
452 :     } else { // what remains here is up or down
453 :     CHECK_CANDIDATE(x + iDiamondSize, y, 2);
454 :     CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
455 : chl 181
456 : chl 530 bDirection += iDirection;
457 :     x = data->currentMV->x; y = data->currentMV->y;
458 : chl 181 }
459 :     }
460 : chl 530 while (iDirection);
461 : chl 181 }
462 :    
463 : chl 530 /* MAINSEARCH FUNCTIONS END */
464 : chl 181
465 : chl 530 /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
466 :    
467 :     static void
468 :     HalfpelRefine(const SearchData * const data)
469 : chl 96 {
470 : chl 530 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
471 : edgomez 195
472 : chl 530 VECTOR backupMV = *(data->currentMV);
473 :     int iDirection; //not needed
474 : chl 96
475 : chl 530 CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
476 :     CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
477 :     CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
478 :     CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
479 : edgomez 195
480 : chl 530 CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
481 :     CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
482 :    
483 :     CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
484 :     CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
485 : chl 96 }
486 :    
487 : chl 530 static __inline int
488 :     SkipDecisionP(const IMAGE * current, const IMAGE * reference,
489 :     const int x, const int y,
490 :     const uint32_t iEdgedWidth, const uint32_t iQuant)
491 : chl 96
492 : Isibaar 3 {
493 : chl 530 /* keep repeating checks for all b-frames before this P frame,
494 :     to make sure that SKIP is possible (todo)
495 :     how: if skip is not possible set sad00 to a very high value */
496 : Isibaar 3
497 : chl 530 uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
498 :     reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
499 :     if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
500 :     sadC += sad8(current->v + x*8 + y*(iEdgedWidth/2)*8,
501 :     reference->v + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
502 :     if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
503 : edgomez 195
504 : chl 530 return 1;
505 :     }
506 : edgomez 195
507 : chl 530 static __inline void
508 :     SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
509 :     {
510 :     pMB->mode = MODE_NOT_CODED;
511 :     pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->mv16.x = 0;
512 :     pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->mv16.y = 0;
513 :     pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
514 : Isibaar 3 }
515 :    
516 : chl 530 bool
517 :     MotionEstimation(MBParam * const pParam,
518 :     FRAMEINFO * const current,
519 :     FRAMEINFO * const reference,
520 :     const IMAGE * const pRefH,
521 :     const IMAGE * const pRefV,
522 :     const IMAGE * const pRefHV,
523 :     const uint32_t iLimit)
524 : Isibaar 3 {
525 : chl 530 MACROBLOCK *const pMBs = current->mbs;
526 :     const IMAGE *const pCurrent = &current->image;
527 :     const IMAGE *const pRef = &reference->image;
528 : Isibaar 3
529 : chl 530 const VECTOR zeroMV = { 0, 0 };
530 : Isibaar 3
531 : chl 530 uint32_t x, y;
532 :     uint32_t iIntra = 0;
533 :     int32_t InterBias;
534 : edgomez 195
535 : chl 530 if (sadInit) (*sadInit) ();
536 : edgomez 195
537 : chl 530 for (y = 0; y < pParam->mb_height; y++) {
538 :     for (x = 0; x < pParam->mb_width; x++) {
539 : Isibaar 3
540 : chl 530 MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
541 :     int32_t sad00 = pMB->sad16
542 :     = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
543 :     pRef->y + (x + y * pParam->edged_width) * 16,
544 :     pParam->edged_width, pMB->sad8 );
545 : edgomez 195
546 : chl 530 if (!(current->global_flags & XVID_LUMIMASKING)) {
547 :     pMB->dquant = NO_CHANGE;
548 :     pMB->quant = current->quant; }
549 : chl 181
550 : chl 530 //initial skip decision
551 : Isibaar 3
552 : chl 530 if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
553 :     && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {
554 :     if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {
555 :     SkipMacroblockP(pMB, sad00);
556 :     continue;
557 :     }
558 :     } else sad00 = 256*4096; // skip not allowed - for final skip decision
559 : Isibaar 3
560 : chl 530 SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
561 :     y, current->motion_flags, pMB->quant,
562 :     current->fcode, pParam, pMBs, reference->mbs,
563 :     current->global_flags & XVID_INTER4V, pMB);
564 : edgomez 195
565 : chl 530 /* final skip decision, a.k.a. "the vector you found, really that good?" */
566 :     if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
567 :     if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
568 :     { SkipMacroblockP(pMB, sad00); continue; }
569 :    
570 :     /* finally, intra decision */
571 : Isibaar 3
572 : chl 530 InterBias = MV16_INTER_BIAS;
573 :     if (pMB->quant > 8) InterBias += 50 * (pMB->quant - 8); // to make high quants work
574 :     if (y != 0)
575 :     if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
576 :     if (x != 0)
577 :     if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
578 : Isibaar 3
579 : chl 530 if (InterBias < pMB->sad16) {
580 :     const int32_t deviation =
581 :     dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
582 :     pParam->edged_width);
583 : Isibaar 3
584 : chl 530 if (deviation < (pMB->sad16 - InterBias)) {
585 :     if (++iIntra >= iLimit) return 1;
586 :     pMB->mode = MODE_INTRA;
587 :     pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
588 :     pMB->mvs[3] = zeroMV;
589 :     pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
590 :     pMB->sad8[3] = 0;
591 :     }
592 :     }
593 :     }
594 : Isibaar 3 }
595 : chl 530 return 0;
596 :     }
597 : Isibaar 3
598 : edgomez 195
599 : chl 530 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
600 : Isibaar 3
601 : chl 530 static __inline int
602 :     make_mask(const VECTOR * const pmv, const int i)
603 :     {
604 :     int mask = 0xFF, j;
605 :     for (j = 0; j < i; j++) {
606 :     if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
607 :     if (pmv[i].x == pmv[j].x) {
608 :     if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
609 :     if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
610 :     } else
611 :     if (pmv[i].y == pmv[j].y) {
612 :     if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
613 :     if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
614 :     }
615 : Isibaar 3 }
616 : chl 530 return mask;
617 :     }
618 : edgomez 195
619 : chl 530 static __inline void
620 :     PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
621 :     const int iHcount, const MACROBLOCK * const prevMB)
622 :     {
623 : edgomez 195
624 : chl 530 //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
625 : edgomez 195
626 : chl 530 if ( (y != 0) && (x != (iWcount-1)) ) { // [5] top-right neighbour
627 :     pmv[5].x = EVEN(pmv[3].x);
628 :     pmv[5].y = EVEN(pmv[3].y); }
629 :     else pmv[5].x = pmv[5].y = 0;
630 : chl 169
631 : chl 530 if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
632 :     else pmv[3].x = pmv[3].y = 0;
633 : Isibaar 3
634 : chl 530 if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
635 :     else pmv[4].x = pmv[4].y = 0;
636 : chl 169
637 : chl 530 // [1] median prediction
638 :     pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
639 : chl 169
640 : chl 530 pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
641 : chl 169
642 : chl 530 pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
643 :     pmv[2].y = EVEN(prevMB->mvs[0].y);
644 : chl 169
645 : chl 530 if ((x != iWcount-1) && (y != iHcount-1)) {
646 :     pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
647 :     pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y); }
648 :     else pmv[6].x = pmv[6].y = 0;
649 :     }
650 : chl 169
651 : chl 530 static void
652 :     SearchP(const uint8_t * const pRef,
653 :     const uint8_t * const pRefH,
654 :     const uint8_t * const pRefV,
655 :     const uint8_t * const pRefHV,
656 :     const IMAGE * const pCur,
657 :     const int x,
658 :     const int y,
659 :     const uint32_t MotionFlags,
660 :     const uint32_t iQuant,
661 :     const uint32_t iFcode,
662 :     const MBParam * const pParam,
663 :     const MACROBLOCK * const pMBs,
664 :     const MACROBLOCK * const prevMBs,
665 :     int inter4v,
666 :     MACROBLOCK * const pMB)
667 :     {
668 : chl 169
669 : chl 530 const int32_t iEdgedWidth = pParam->edged_width;
670 :    
671 :     int i, iDirection = 255, mask, threshA;
672 :     int32_t temp[5];
673 :     VECTOR currentMV[5], pmv[7];
674 :     int32_t psad[4], iMinSAD[5];
675 :     MainSearchFunc * MainSearchPtr;
676 :     SearchData Data;
677 : Isibaar 3
678 : chl 530 get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, psad); //has to be changed to get_pmv(2)()
679 :     get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
680 :     pParam->width, pParam->height, iFcode);
681 : Isibaar 3
682 : chl 530 Data.predMV = pmv[0];
683 :     Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
684 :     Data.iEdgedWidth = iEdgedWidth;
685 :     Data.currentMV = currentMV;
686 :     Data.iMinSAD = iMinSAD;
687 :     Data.Ref = pRef + (x + iEdgedWidth*y)*16;
688 :     Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
689 :     Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
690 :     Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
691 :     Data.temp = temp;
692 : Isibaar 3
693 : chl 530 Data.iQuant = iQuant;
694 :     Data.iFcode = iFcode;
695 : chl 169
696 : chl 530 if (!(MotionFlags & PMV_HALFPEL16)) {
697 :     Data.min_dx = EVEN(Data.min_dx);
698 :     Data.max_dx = EVEN(Data.max_dx);
699 :     Data.min_dy = EVEN(Data.min_dy);
700 :     Data.max_dy = EVEN(Data.max_dy); }
701 : edgomez 195
702 : chl 530 for(i = 0; i < 5; i++) currentMV[i].x = currentMV[i].y = 0;
703 : chl 169
704 : chl 530 i = d_mv_bits(pmv[0].x, pmv[0].y, iFcode);
705 : chl 169
706 : chl 530 iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
707 :     iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
708 :     iMinSAD[2] = pMB->sad8[1];
709 :     iMinSAD[3] = pMB->sad8[2];
710 :     iMinSAD[4] = pMB->sad8[3];
711 : edgomez 195
712 : chl 530 if (pMB->dquant != NO_CHANGE) inter4v = 0;
713 : edgomez 195
714 : chl 530 if ((x == 0) && (y == 0)) threshA = 512;
715 :     else {
716 :     threshA = psad[0] + 20;
717 :     if (threshA < 512) threshA = 512;
718 :     if (threshA > 1024) threshA = 1024; }
719 : Isibaar 3
720 : chl 530 PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
721 :     prevMBs + x + y * pParam->mb_width);
722 : edgomez 195
723 : chl 530 if (inter4v) CheckCandidate = CheckCandidate16;
724 :     else CheckCandidate = CheckCandidate16no4v;
725 : Isibaar 3
726 : chl 530 /* main loop. checking all predictions */
727 :    
728 :     for (i = 1; i < 7; i++) {
729 :     if (!(mask = make_mask(pmv, i)) ) continue;
730 :     CheckCandidate16(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
731 :     if (iMinSAD[0] < threshA) break;
732 :     }
733 :    
734 :     if ((iMinSAD[0] <= threshA) ||
735 :     (MVequal(currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
736 :     (iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
737 :     inter4v = 0;
738 :     if (MotionFlags & PMV_QUICKSTOP16) goto PMVfast16_Terminate_without_Refine;
739 :     if (MotionFlags & PMV_EARLYSTOP16) {
740 :     CheckCandidate = CheckCandidate16no4v; // I sure hope it's faster
741 : chl 96 goto PMVfast16_Terminate_with_Refine;
742 : chl 530 }
743 : edgomez 78 }
744 : Isibaar 3
745 : chl 181 if (MotionFlags & PMV_USESQUARES16)
746 : chl 530 MainSearchPtr = SquareSearch;
747 : edgomez 195 else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
748 : chl 530 MainSearchPtr = AdvDiamondSearch;
749 :     else MainSearchPtr = DiamondSearch;
750 : chl 181
751 : chl 530 (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, iDirection);
752 : Isibaar 3
753 : chl 530 /* extended search, diamond starting in 0,0 and in prediction.
754 :     note that this search is/might be done in halfpel positions,
755 :     which makes it more different than the diamond above */
756 : chl 259
757 : edgomez 195 if (MotionFlags & PMV_EXTSEARCH16) {
758 : chl 530 int32_t bSAD;
759 :     VECTOR startMV = Data.predMV, backupMV = currentMV[0];
760 :     if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
761 :     startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
762 :     if (!(MVequal(startMV, backupMV))) {
763 :     bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;
764 : Isibaar 3
765 : chl 530 CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);
766 :     (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);
767 :     if (bSAD < iMinSAD[0]) {
768 :     currentMV[0] = backupMV;
769 :     iMinSAD[0] = bSAD; }
770 : Isibaar 3 }
771 :    
772 : chl 530 backupMV = currentMV[0];
773 :     if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
774 :     else startMV.x = startMV.y = 0;
775 :     if (!(MVequal(startMV, backupMV))) {
776 :     bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;
777 : edgomez 195
778 : chl 530 CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);
779 :     (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);
780 :     if (bSAD < iMinSAD[0]) {
781 :     currentMV[0] = backupMV;
782 :     iMinSAD[0] = bSAD; }
783 : Isibaar 3 }
784 :     }
785 :    
786 : chl 530 PMVfast16_Terminate_with_Refine:
787 : Isibaar 3
788 : chl 530 if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
789 : Isibaar 3
790 : chl 530 PMVfast16_Terminate_without_Refine:
791 : Isibaar 3
792 : chl 530 if (inter4v)
793 :     for(i = 0; i < 4; i++)
794 :     Search8(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
795 : Isibaar 3
796 : chl 530 if (!(inter4v) ||
797 :     (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
798 :     // INTER MODE
799 :     pMB->mode = MODE_INTER;
800 :     pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]
801 :     = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
802 : Isibaar 3
803 : chl 530 pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
804 :     pMB->sad8[2] = pMB->sad8[3] = iMinSAD[0];
805 : Isibaar 3
806 : chl 530 pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
807 :     pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
808 : edgomez 195 } else {
809 : chl 530 // INTER4V MODE; all other things are already set in Search8
810 :     pMB->mode = MODE_INTER4V;
811 :     pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
812 : edgomez 78 }
813 : chl 530
814 : Isibaar 3 }
815 :    
816 : chl 530 static void
817 :     Search8(const SearchData * const OldData,
818 :     const int x, const int y,
819 :     const uint32_t MotionFlags,
820 :     const MBParam * const pParam,
821 :     MACROBLOCK * const pMB,
822 :     const MACROBLOCK * const pMBs,
823 :     const int block)
824 : chl 345 {
825 : chl 530 SearchData Data;
826 : chl 345
827 : chl 530 Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
828 :     Data.iMinSAD = OldData->iMinSAD + 1 + block;
829 :     Data.currentMV = OldData->currentMV+1+block;
830 :     Data.iFcode = OldData->iFcode;
831 :     Data.iQuant = OldData->iQuant;
832 : chl 345
833 : chl 530 if (block != 0)
834 :     *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
835 :     d_mv_bits( Data.currentMV->x - Data.predMV.x,
836 :     Data.currentMV->y - Data.predMV.y,
837 :     Data.iFcode);
838 : chl 345
839 : chl 530
840 :     if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
841 : chl 345
842 : chl 530 Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
843 :     Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
844 :     Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
845 :     Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
846 : chl 345
847 : chl 530 Data.iEdgedWidth = pParam->edged_width;
848 : chl 345
849 : chl 530 Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
850 :    
851 :     get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
852 :     pParam->width, pParam->height, OldData->iFcode);
853 : chl 345
854 : chl 530 CheckCandidate = CheckCandidate8;
855 : chl 345
856 : chl 530 if (MotionFlags & PMV_EXTSEARCH8) {
857 : chl 345
858 : chl 530 MainSearchFunc *MainSearchPtr;
859 :     if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
860 :     else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
861 :     else MainSearchPtr = DiamondSearch;
862 : chl 345
863 : chl 530 (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255); }
864 : chl 345
865 : chl 530 if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
866 : chl 345 }
867 : chl 530
868 :     pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
869 :     pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
870 :     pMB->mvs[block] = *(Data.currentMV);
871 :     pMB->sad8[block] = 4 * (*(Data.iMinSAD));
872 : chl 345 }
873 :    
874 : chl 530 /* B-frames code starts here */
875 : chl 345
876 : chl 530 static __inline VECTOR
877 :     ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
878 : Isibaar 3 {
879 : chl 530 /* the stupidiest function ever */
880 :     if (mode == MODE_FORWARD) return pMB->mvs[0];
881 :     else return pMB->b_mvs[0];
882 : Isibaar 3 }
883 :    
884 : chl 530 static void __inline
885 :     PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
886 :     const uint32_t iWcount,
887 :     const MACROBLOCK * const pMB,
888 :     const uint32_t mode_curr)
889 : Isibaar 3 {
890 :    
891 : chl 530 // [0] is prediction
892 :     pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
893 : Isibaar 3
894 : chl 530 pmv[1].x = pmv[1].y = 0; // [1] is zero
895 : Isibaar 3
896 : chl 530 pmv[2] = ChoosePred(pMB, mode_curr);
897 :     pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
898 : edgomez 195
899 : chl 530 pmv[3].x = pmv[3].y = 0;
900 :     if ((y != 0)&&(x != (int)(iWcount+1))) { // [3] top-right neighbour
901 :     pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
902 :     pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y); }
903 : Isibaar 3
904 : chl 530 if (y != 0) {
905 :     pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
906 :     pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
907 :     } else pmv[4].x = pmv[4].y = 0;
908 : Isibaar 3
909 : chl 530 if (x != 0) {
910 :     pmv[5] = ChoosePred(pMB-1, mode_curr);
911 :     pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
912 :     } else pmv[5].x = pmv[5].y = 0;
913 : Isibaar 3
914 : chl 530 if ((x != 0)&&(y != 0)) {
915 :     pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
916 :     pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
917 :     } else pmv[6].x = pmv[6].y = 0;
918 : edgomez 195
919 : chl 530 // more?
920 :     }
921 : chl 181
922 : edgomez 170
923 : chl 530 /* search backward or forward, for b-frames */
924 :     static void
925 :     SearchBF( const uint8_t * const pRef,
926 :     const uint8_t * const pRefH,
927 :     const uint8_t * const pRefV,
928 :     const uint8_t * const pRefHV,
929 :     const IMAGE * const pCur,
930 :     const int x, const int y,
931 :     const uint32_t MotionFlags,
932 :     const uint32_t iQuant,
933 :     const uint32_t iFcode,
934 :     const MBParam * const pParam,
935 :     MACROBLOCK * const pMB,
936 :     const VECTOR * const predMV,
937 :     int32_t * const best_sad,
938 :     const int32_t mode_current)
939 :     {
940 : Isibaar 3
941 : chl 530 const int32_t iEdgedWidth = pParam->edged_width;
942 :    
943 :     int i, iDirection, mask;
944 :     VECTOR currentMV, pmv[7];
945 :     MainSearchFunc *MainSearchPtr;
946 :     int32_t iMinSAD = MV_MAX_ERROR;
947 :     SearchData Data;
948 : Isibaar 3
949 : chl 530 Data.iMinSAD = &iMinSAD;
950 :     Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
951 :     Data.iEdgedWidth = iEdgedWidth;
952 :     Data.currentMV = &currentMV;
953 :     Data.iMinSAD = &iMinSAD;
954 :     Data.Ref = pRef + (x + y * iEdgedWidth) * 16;
955 :     Data.RefH = pRefH + (x + y * iEdgedWidth) * 16;
956 :     Data.RefV = pRefV + (x + y * iEdgedWidth) * 16;
957 :     Data.RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
958 : Isibaar 3
959 : chl 530 Data.iQuant = iQuant;
960 :     Data.iFcode = iFcode;
961 :     Data.predMV = *predMV;
962 : edgomez 195
963 : chl 530 get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
964 :     pParam->width, pParam->height, iFcode);
965 : Isibaar 3
966 : chl 530 if (!(MotionFlags & PMV_HALFPEL16)) {
967 :     Data.min_dx = EVEN(Data.min_dx);
968 :     Data.max_dx = EVEN(Data.max_dx);
969 :     Data.min_dy = EVEN(Data.min_dy);
970 :     Data.max_dy = EVEN(Data.max_dy); } // no-halpel and b-frames. do we need it?
971 : edgomez 195
972 : Isibaar 3
973 : chl 530 pmv[0] = Data.predMV;
974 :     PreparePredictionsBF(pmv, x, y, pParam->mb_width,
975 :     pMB, mode_current);
976 : Isibaar 3
977 : chl 530 currentMV.x = currentMV.y = 0;
978 : Isibaar 3
979 : chl 530 CheckCandidate = CheckCandidate16no4v;
980 : chl 181
981 : chl 530 // main loop. checking all predictions
982 :     for (i = 0; i < 8; i++) {
983 :     if (!(mask = make_mask(pmv, i)) ) continue;
984 :     CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
985 : edgomez 78 }
986 : Isibaar 3
987 : chl 530 if (MotionFlags & PMV_USESQUARES16)
988 :     MainSearchPtr = SquareSearch;
989 :     else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
990 :     MainSearchPtr = AdvDiamondSearch;
991 :     else MainSearchPtr = DiamondSearch;
992 : chl 96
993 : chl 530 (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);
994 : chl 169
995 : chl 530 if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
996 : chl 169
997 : chl 530 // three bits are needed to code backward mode. four for forward
998 :     // we treat the bits just like they were vector's
999 :     if (mode_current == MODE_FORWARD) iMinSAD += 4 * lambda_vec16[iQuant];
1000 :     else iMinSAD += 3 * lambda_vec16[iQuant];
1001 : chl 169
1002 :    
1003 : chl 530 if (iMinSAD < *best_sad) {
1004 :     *best_sad = iMinSAD;
1005 :     pMB->mode = mode_current;
1006 :     pMB->pmvs[0].x = currentMV.x - predMV->x;
1007 :     pMB->pmvs[0].y = currentMV.y - predMV->y;
1008 :     if (mode_current == MODE_FORWARD) pMB->mvs[0] = currentMV;
1009 :     else pMB->b_mvs[0] = currentMV;
1010 : chl 169 }
1011 : chl 530
1012 :     }
1013 : chl 169
1014 : chl 530 static int32_t
1015 :     SearchDirect(const uint8_t * const f_Ref,
1016 :     const uint8_t * const f_RefH,
1017 :     const uint8_t * const f_RefV,
1018 :     const uint8_t * const f_RefHV,
1019 :     const uint8_t * const b_Ref,
1020 :     const uint8_t * const b_RefH,
1021 :     const uint8_t * const b_RefV,
1022 :     const uint8_t * const b_RefHV,
1023 :     const IMAGE * const pCur,
1024 :     const int x, const int y,
1025 :     const uint32_t MotionFlags,
1026 :     const uint32_t iQuant,
1027 :     const int32_t TRB, const int32_t TRD,
1028 :     const MBParam * const pParam,
1029 :     MACROBLOCK * const pMB,
1030 :     const MACROBLOCK * const b_mb,
1031 :     int32_t * const best_sad)
1032 : edgomez 195
1033 : chl 530 {
1034 :     const uint32_t iEdgedWidth = pParam->edged_width;
1035 :     int32_t iMinSAD = 0, skip_sad;
1036 :     int k;
1037 :     VECTOR currentMV;
1038 :     MainSearchFunc *MainSearchPtr;
1039 :     SearchData Data;
1040 : Isibaar 3
1041 : chl 530 Data.iMinSAD = &iMinSAD;
1042 :     Data.Cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1043 :     Data.iEdgedWidth = iEdgedWidth;
1044 :     Data.currentMV = &currentMV;
1045 :     Data.iQuant = iQuant;
1046 :     Data.referencemv = b_mb->mvs;
1047 : chl 140
1048 : chl 530 Data.Ref= f_Ref + (x + iEdgedWidth*y) * 16;
1049 :     Data.RefH = f_RefH + (x + iEdgedWidth*y) * 16;
1050 :     Data.RefV = f_RefV + (x + iEdgedWidth*y) * 16;
1051 :     Data.RefHV = f_RefHV + (x + iEdgedWidth*y) * 16;
1052 :     Data.bRef = b_Ref + (x + iEdgedWidth*y) * 16;
1053 :     Data.bRefH = b_RefH + (x + iEdgedWidth*y) * 16;
1054 :     Data.bRefV = b_RefV + (x + iEdgedWidth*y) * 16;
1055 :     Data.bRefHV = b_RefHV + (x + iEdgedWidth*y) * 16;
1056 :     /*
1057 :     //What we do here is a complicated version of CheckCandidateDirect(0,0);
1058 :     get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16, pParam->width, pParam->height, 19);
1059 : chl 140
1060 : Isibaar 3 */
1061 : chl 530 Data.max_dx = 2 * pParam->width - 2 * (x) * 16;
1062 :     Data.max_dy = 2 * pParam->height - 2 * (y) * 16;
1063 :     Data.min_dx = -(2 * 16 + 2 * (x) * 16);
1064 :     Data.min_dy = -(2 * 16 + 2 * (y) * 16);
1065 : Isibaar 3
1066 : chl 530 for (k = 0; k < 4; k++) {
1067 :     pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);
1068 :     pMB->b_mvs[k].x = Data.directmvB[k].x = ((TRB - TRD) * Data.referencemv[k].x) / TRD;
1069 :     pMB->mvs[k].y = Data.directmvF[k].y = ((TRB * Data.referencemv[k].y) / TRD);
1070 :     pMB->b_mvs[k].y = Data.directmvB[k].y = ((TRB - TRD) * Data.referencemv[k].y) / TRD;
1071 : Isibaar 3
1072 : chl 530 if (( pMB->mvs[k].x > Data.max_dx ) || ( pMB->mvs[k].x < Data.min_dx )
1073 :     || ( pMB->mvs[k].y > Data.max_dy ) || ( pMB->mvs[k].y < Data.min_dy )
1074 :     || ( pMB->b_mvs[k].x > Data.max_dx ) || ( pMB->b_mvs[k].x < Data.min_dx )
1075 :     || ( pMB->b_mvs[k].y > Data.max_dy ) || ( pMB->b_mvs[k].y < Data.min_dy )) {
1076 :     /*
1077 :     fprintf(debug, "\nERROR - out of range : vector %d,%d and %d,%d\n", pMB->mvs[k].x, pMB->mvs[k].y,pMB->b_mvs[k].x,pMB->b_mvs[k].y );
1078 :     fprintf(debug, " range is x: %d..%d y: %d..%d \n", Data.min_dx,Data.max_dx,Data.min_dy,Data.max_dy);
1079 :     fprintf(debug,"macroblock %d, %d \n", x, y);
1080 :     fprintf(debug, "direct MV is %d,%d \n", directmv[k].x, directmv[k].y);
1081 : Isibaar 3 */
1082 : chl 530 *best_sad = 256*4096; // in that case, we won't use direct mode
1083 :     pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1084 :     pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0; /* because backwards and interpol might rely on this */
1085 :     return 0; }
1086 : Isibaar 3
1087 :    
1088 : chl 530 if (b_mb->mode != MODE_INTER4V) {
1089 :     iMinSAD = sad16bi(Data.Cur,
1090 :     get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,
1091 :     x, y, 16, &pMB->mvs[0], iEdgedWidth),
1092 :     get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,
1093 :     x, y, 16, &pMB->b_mvs[0], iEdgedWidth), iEdgedWidth);
1094 : edgomez 195
1095 : chl 530 Data.directmvF[1] = Data.directmvF[2] = Data.directmvF[3] = Data.directmvF[0];
1096 :     Data.directmvB[1] = Data.directmvB[2] = Data.directmvB[3] = Data.directmvB[0];
1097 :     break;
1098 : Isibaar 3 }
1099 : chl 530 iMinSAD += sad8bi(Data.Cur + (k&1)*8 + (k>>1)* 8 * iEdgedWidth,
1100 :     get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,
1101 :     (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->mvs[k], iEdgedWidth),
1102 :     get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,
1103 :     (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->b_mvs[k], iEdgedWidth),
1104 :     iEdgedWidth);
1105 :     }
1106 : Isibaar 3
1107 : chl 530 // skip decision
1108 :     if (iMinSAD < (int32_t)iQuant * SKIP_THRESH_B) {
1109 :     pMB->mode = MODE_DIRECT_NONE_MV;
1110 :     return iMinSAD; }
1111 : Isibaar 3
1112 : chl 530 skip_sad = iMinSAD;
1113 :     iMinSAD += 2 * lambda_vec16[iQuant]; // 2 bits needed to code vector 0,0
1114 :     currentMV.x = currentMV.y = 0;
1115 :     if (b_mb->mode == MODE_INTER4V)
1116 :     CheckCandidate = CheckCandidateDirect;
1117 :     else CheckCandidate = CheckCandidateDirectno4v;
1118 : edgomez 195
1119 : chl 530 // DIRECT MODE DELTA VECTOR SEARCH.
1120 :     // This has to be made more effective, but at the moment I'm happy it's running at all
1121 : Isibaar 3
1122 : chl 530 if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1123 :     else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1124 :     else MainSearchPtr = DiamondSearch;
1125 : edgomez 195
1126 : chl 530 (*MainSearchPtr)(0, 0, &Data, 255);
1127 : Isibaar 3
1128 : chl 530 HalfpelRefine(&Data);
1129 : Isibaar 3
1130 : chl 530 iMinSAD += 1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's
1131 :     *best_sad = iMinSAD;
1132 : Isibaar 3
1133 : chl 530 if (b_mb->mode == MODE_INTER4V)
1134 :     pMB->mode = MODE_DIRECT;
1135 :     else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1136 : edgomez 195
1137 : chl 530 pMB->pmvs[3] = currentMV;
1138 : edgomez 195
1139 : chl 530 for (k = 0; k < 4; k++) {
1140 :     pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;
1141 :     pMB->b_mvs[k].x = ((currentMV.x == 0)
1142 :     ? Data.directmvB[k].x
1143 :     : pMB->mvs[k].x - Data.referencemv[k].x);
1144 :     pMB->mvs[k].y = (Data.directmvF[k].y + currentMV.y);
1145 :     pMB->b_mvs[k].y = ((currentMV.y == 0)
1146 :     ? Data.directmvB[k].y
1147 :     : pMB->mvs[k].y - Data.referencemv[k].y);
1148 :     if (b_mb->mode != MODE_INTER4V) {
1149 :     pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1150 :     pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1151 :     break;
1152 :     }
1153 :     }
1154 :     return 0;//skip_sad;
1155 : Isibaar 3 }
1156 : chl 96
1157 : chl 530 static __inline void
1158 :     SearchInterpolate(const uint8_t * const f_Ref,
1159 :     const uint8_t * const f_RefH,
1160 :     const uint8_t * const f_RefV,
1161 :     const uint8_t * const f_RefHV,
1162 :     const uint8_t * const b_Ref,
1163 :     const uint8_t * const b_RefH,
1164 :     const uint8_t * const b_RefV,
1165 :     const uint8_t * const b_RefHV,
1166 :     const IMAGE * const pCur,
1167 :     const int x, const int y,
1168 :     const uint32_t fcode,
1169 :     const uint32_t bcode,
1170 :     const uint32_t MotionFlags,
1171 :     const uint32_t iQuant,
1172 :     const MBParam * const pParam,
1173 :     const VECTOR * const f_predMV,
1174 :     const VECTOR * const b_predMV,
1175 :     MACROBLOCK * const pMB,
1176 :     int32_t * const best_sad)
1177 :    
1178 : chl 96 {
1179 : chl 530 /* Interpolated MC motion vector search, this is tedious and more complicated because there are
1180 :     two values for everything, always one for backward and one for forward ME. Still, we don't gain
1181 :     much from this search, maybe it should simply be skipped and simply current i_sad16 value used
1182 :     as "optimal". */
1183 : chl 96
1184 : edgomez 195 const int32_t iEdgedWidth = pParam->edged_width;
1185 : chl 96
1186 : chl 530 int iDirection, i, j;
1187 :     int32_t iMinSAD = 256*4096;
1188 :     VECTOR currentMV[3];
1189 :     SearchData fData, bData;
1190 : chl 96
1191 : edgomez 195
1192 : chl 530 fData.iMinSAD = bData.iMinSAD = &iMinSAD;
1193 : edgomez 195
1194 : chl 530 fData.Cur = bData.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1195 :     fData.iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1196 :     fData.currentMV = currentMV; bData.currentMV = currentMV + 1;
1197 :     fData.iQuant = bData.iQuant = iQuant;
1198 :     fData.iFcode = bData.bFcode = fcode; fData.bFcode = bData.iFcode = bcode;
1199 : chl 96
1200 : edgomez 195
1201 : chl 530 bData.bRef = fData.Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1202 :     bData.bRefH = fData.RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1203 :     bData.bRefV = fData.RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1204 :     bData.bRefHV = fData.RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1205 :     bData.Ref = fData.bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1206 :     bData.RefH = fData.bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1207 :     bData.RefV = fData.bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1208 :     bData.RefHV = fData.bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1209 : edgomez 195
1210 : chl 530 bData.bpredMV = fData.predMV = *f_predMV;
1211 :     fData.bpredMV = bData.predMV = *b_predMV;
1212 : chl 96
1213 :    
1214 : chl 530 currentMV[0] = pMB->mvs[0];
1215 :     currentMV[1] = pMB->b_mvs[0];
1216 :     get_range(&fData.min_dx, &fData.max_dx, &fData.min_dy, &fData.max_dy, x, y, 16, pParam->width, pParam->height, fcode);
1217 :     get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);
1218 : chl 96
1219 : chl 530 CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);
1220 : chl 96
1221 : chl 530 //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1222 : chl 96
1223 : chl 530 do {
1224 :     iDirection = 255;
1225 :     // forward MV moves
1226 :     i = currentMV[0].x; j = currentMV[0].y;
1227 : chl 96
1228 : chl 530 CheckCandidateInt(i + 2, j, 0, &iDirection, &fData);
1229 :     CheckCandidateInt(i, j + 2, 0, &iDirection, &fData);
1230 :     CheckCandidateInt(i - 2, j, 0, &iDirection, &fData);
1231 :     CheckCandidateInt(i, j - 2, 0, &iDirection, &fData);
1232 : chl 96
1233 : chl 530 // backward MV moves
1234 :     i = currentMV[1].x; j = currentMV[1].y;
1235 :     currentMV[2] = currentMV[0];
1236 : chl 326
1237 : chl 530 CheckCandidateInt(i + 2, j, 0, &iDirection, &bData);
1238 :     CheckCandidateInt(i, j + 2, 0, &iDirection, &bData);
1239 :     CheckCandidateInt(i - 2, j, 0, &iDirection, &bData);
1240 :     CheckCandidateInt(i, j - 2, 0, &iDirection, &bData);
1241 : chl 96
1242 : chl 530 } while (!(iDirection));
1243 : edgomez 195
1244 : chl 530 /* halfpel refinement. luckly we can use normal halfpel function for it */
1245 : edgomez 195
1246 : chl 530 if (MotionFlags & PMV_HALFPELREFINE16) {
1247 :     CheckCandidate = CheckCandidateInt;
1248 :     HalfpelRefine(&fData);
1249 :     currentMV[2] = currentMV[0];
1250 :     HalfpelRefine(&bData);
1251 : edgomez 195 }
1252 : chl 96
1253 : chl 530 // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1254 :     iMinSAD += 2 * lambda_vec16[iQuant];
1255 :     if (iMinSAD < *best_sad) {
1256 :     *best_sad = iMinSAD;
1257 :     pMB->mvs[0] = currentMV[0];
1258 :     pMB->b_mvs[0] = currentMV[1];
1259 :     pMB->mode = MODE_INTERPOLATE;
1260 : chl 96
1261 : chl 530 pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1262 :     pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1263 :     pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1264 :     pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1265 :     }
1266 :     }
1267 : chl 96
1268 : chl 530 void
1269 :     MotionEstimationBVOP(MBParam * const pParam,
1270 :     FRAMEINFO * const frame,
1271 :     const int32_t time_bp,
1272 :     const int32_t time_pp,
1273 :     // forward (past) reference
1274 :     const MACROBLOCK * const f_mbs,
1275 :     const IMAGE * const f_ref,
1276 :     const IMAGE * const f_refH,
1277 :     const IMAGE * const f_refV,
1278 :     const IMAGE * const f_refHV,
1279 :     // backward (future) reference
1280 :     const MACROBLOCK * const b_mbs,
1281 :     const IMAGE * const b_ref,
1282 :     const IMAGE * const b_refH,
1283 :     const IMAGE * const b_refV,
1284 :     const IMAGE * const b_refHV)
1285 :     {
1286 :     uint32_t i, j;
1287 :     int32_t best_sad, skip_sad;
1288 :     int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1289 :     static const VECTOR zeroMV={0,0};
1290 : chl 96
1291 : chl 530 VECTOR f_predMV, b_predMV; /* there is no prediction for direct mode*/
1292 : chl 96
1293 : chl 530 const int32_t TRB = time_pp - time_bp;
1294 :     const int32_t TRD = time_pp;
1295 : chl 96
1296 : chl 530 // note: i==horizontal, j==vertical
1297 : chl 96
1298 : chl 530 for (j = 0; j < pParam->mb_height; j++) {
1299 : chl 96
1300 : chl 530 f_predMV = b_predMV = zeroMV; /* prediction is reset at left boundary */
1301 : edgomez 195
1302 : chl 530 for (i = 0; i < pParam->mb_width; i++) {
1303 :     MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1304 :     const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1305 : edgomez 195
1306 : chl 530 /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1307 :     if (b_mb->mode == MODE_NOT_CODED) {
1308 :     pMB->mode = MODE_NOT_CODED;
1309 :     continue;
1310 : chl 96 }
1311 :    
1312 : chl 530 /* direct search comes first, because it (1) checks for SKIP-mode
1313 :     and (2) sets very good predictions for forward and backward search */
1314 : chl 96
1315 : chl 530 skip_sad = SearchDirect(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1316 :     b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1317 :     &frame->image,
1318 :     i, j,
1319 :     frame->motion_flags,
1320 :     frame->quant,
1321 :     TRB, TRD,
1322 :     pParam,
1323 :     pMB, b_mb,
1324 :     &best_sad);
1325 : chl 96
1326 : chl 530 if (!(frame->global_flags & XVID_HALFPEL)) best_sad = skip_sad = 256*4096;
1327 :     else
1328 :     if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1329 : chl 96
1330 : chl 530 // best_sad = 256*4096; //uncomment to disable Directsearch.
1331 :     // To disable any other mode, just comment the function call
1332 : chl 96
1333 : chl 530 // forward search
1334 :     SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1335 :     &frame->image, i, j,
1336 :     frame->motion_flags,
1337 :     frame->quant, frame->fcode, pParam,
1338 :     pMB, &f_predMV, &best_sad,
1339 :     MODE_FORWARD);
1340 : chl 96
1341 : chl 530 // backward search
1342 :     SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1343 :     &frame->image, i, j,
1344 :     frame->motion_flags,
1345 :     frame->quant, frame->bcode, pParam,
1346 :     pMB, &b_predMV, &best_sad,
1347 :     MODE_BACKWARD);
1348 : chl 96
1349 : chl 530 // interpolate search comes last, because it uses data from forward and backward as prediction
1350 : chl 96
1351 : chl 530 SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1352 :     b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1353 :     &frame->image,
1354 :     i, j,
1355 :     frame->fcode, frame->bcode,
1356 :     frame->motion_flags,
1357 :     frame->quant, pParam,
1358 :     &f_predMV, &b_predMV,
1359 :     pMB, &best_sad);
1360 : chl 96
1361 : chl 530 switch (pMB->mode) {
1362 :     case MODE_FORWARD:
1363 :     f_count++;
1364 :     f_predMV = pMB->mvs[0];
1365 :     break;
1366 :     case MODE_BACKWARD:
1367 :     b_count++;
1368 :     b_predMV = pMB->b_mvs[0];
1369 :     break;
1370 :     case MODE_INTERPOLATE:
1371 :     i_count++;
1372 :     f_predMV = pMB->mvs[0];
1373 :     b_predMV = pMB->b_mvs[0];
1374 :     break;
1375 :     case MODE_DIRECT:
1376 :     case MODE_DIRECT_NO4V:
1377 :     d_count++;
1378 :     break;
1379 :     default:
1380 :     break;
1381 : chl 96 }
1382 :     }
1383 :     }
1384 :    
1385 : chl 530 // fprintf(debug,"B-Stat: F: %04d B: %04d I: %04d D: %04d, N: %04d\n",
1386 :     // f_count,b_count,i_count,d_count,n_count);
1387 : chl 96
1388 :     }
1389 :    
1390 : chl 530 /* Hinted ME starts here */
1391 : chl 96
1392 : chl 530 static __inline void
1393 :     Search8hinted( const SearchData * const OldData,
1394 :     const int x, const int y,
1395 :     const uint32_t MotionFlags,
1396 :     const MBParam * const pParam,
1397 :     MACROBLOCK * const pMB,
1398 :     const MACROBLOCK * const pMBs,
1399 :     const int block)
1400 : chl 96 {
1401 : chl 530 SearchData Data;
1402 :     MainSearchFunc *MainSearchPtr;
1403 : chl 141
1404 : chl 530 Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1405 :     Data.iMinSAD = OldData->iMinSAD + 1 + block;
1406 :     Data.currentMV = OldData->currentMV+1+block;
1407 :     Data.iFcode = OldData->iFcode;
1408 :     Data.iQuant = OldData->iQuant;
1409 : chl 96
1410 : chl 530 Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1411 :     Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1412 :     Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1413 :     Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1414 :     Data.iEdgedWidth = pParam->edged_width;
1415 :     Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1416 : chl 96
1417 : chl 530 CheckCandidate = CheckCandidate8;
1418 : edgomez 195
1419 : chl 530 if (block != 0)
1420 :     *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
1421 :     d_mv_bits( Data.currentMV->x - Data.predMV.x,
1422 :     Data.currentMV->y - Data.predMV.y,
1423 :     Data.iFcode);
1424 : edgomez 195
1425 :    
1426 : chl 530 get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
1427 :     pParam->width, pParam->height, OldData->iFcode);
1428 : chl 96
1429 : chl 530 if (pMB->mode == MODE_INTER4V) {
1430 :     int dummy;
1431 :     CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1432 : chl 96
1433 : chl 530 if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1434 :     else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1435 :     else MainSearchPtr = DiamondSearch;
1436 : chl 96
1437 : chl 530 (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
1438 : edgomez 195
1439 : chl 530 if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
1440 : chl 96
1441 : chl 530 pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1442 :     pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1443 :     pMB->mvs[block] = *(Data.currentMV);
1444 :     pMB->sad8[block] = 4 * (*(Data.iMinSAD));
1445 : chl 96 }
1446 :    
1447 : suxen_drol 118
1448 : chl 530 static void
1449 :     SearchPhinted ( const uint8_t * const pRef,
1450 : chl 289 const uint8_t * const pRefH,
1451 :     const uint8_t * const pRefV,
1452 :     const uint8_t * const pRefHV,
1453 :     const IMAGE * const pCur,
1454 :     const int x,
1455 :     const int y,
1456 :     const uint32_t MotionFlags,
1457 :     const uint32_t iQuant,
1458 :     const uint32_t iFcode,
1459 :     const MBParam * const pParam,
1460 :     const MACROBLOCK * const pMBs,
1461 : chl 530 int inter4v,
1462 :     MACROBLOCK * const pMB)
1463 : chl 289 {
1464 : chl 530
1465 : chl 289 const int32_t iEdgedWidth = pParam->edged_width;
1466 : chl 530
1467 :     int i;
1468 :     VECTOR currentMV[5];
1469 :     int32_t iMinSAD[5];
1470 :     int32_t temp[5];
1471 :     MainSearchFunc * MainSearchPtr;
1472 :     SearchData Data;
1473 : suxen_drol 118
1474 : chl 530 Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1475 :     get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1476 :     pParam->width, pParam->height, iFcode);
1477 : suxen_drol 118
1478 : chl 530 Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1479 :     Data.iEdgedWidth = iEdgedWidth;
1480 :     Data.currentMV = currentMV;
1481 :     Data.iMinSAD = iMinSAD;
1482 :     Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1483 :     Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
1484 :     Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
1485 :     Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1486 :     Data.temp = temp;
1487 :     Data.iQuant = iQuant;
1488 :     Data.iFcode = iFcode;
1489 : chl 326
1490 : chl 530 if (!(MotionFlags & PMV_HALFPEL16)) {
1491 :     Data.min_dx = EVEN(Data.min_dx);
1492 :     Data.max_dx = EVEN(Data.max_dx);
1493 :     Data.min_dy = EVEN(Data.min_dy);
1494 :     Data.max_dy = EVEN(Data.max_dy);
1495 :     }
1496 : chl 289
1497 : chl 530 for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;
1498 : chl 289
1499 : chl 530 if (pMB->dquant != NO_CHANGE) inter4v = 0;
1500 : chl 289
1501 : chl 530 if (inter4v)
1502 :     CheckCandidate = CheckCandidate16;
1503 :     else CheckCandidate = CheckCandidate16no4v;
1504 : chl 289
1505 :    
1506 : chl 530 pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1507 :     pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1508 :     if (pMB->mvs[0].x > Data.max_dx) pMB->mvs[0].x = Data.max_dx; // this is in case iFcode changed
1509 :     if (pMB->mvs[0].x < Data.min_dx) pMB->mvs[0].x = Data.min_dx;
1510 :     if (pMB->mvs[0].y > Data.max_dy) pMB->mvs[0].y = Data.max_dy;
1511 :     if (pMB->mvs[0].y < Data.min_dy) pMB->mvs[0].y = Data.min_dy;
1512 : chl 370
1513 : chl 530 CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);
1514 : chl 289
1515 : chl 530 if (pMB->mode == MODE_INTER4V)
1516 :     for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1517 :     pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1518 :     pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1519 :     if (!(make_mask(pMB->mvs, i)))
1520 :     CheckCandidate16(pMB->mvs[i].x, pMB->mvs[i].y, 0, &i, &Data);
1521 : chl 289 }
1522 :    
1523 :     if (MotionFlags & PMV_USESQUARES16)
1524 : chl 530 MainSearchPtr = SquareSearch;
1525 : chl 289 else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1526 : chl 530 MainSearchPtr = AdvDiamondSearch;
1527 :     else MainSearchPtr = DiamondSearch;
1528 : chl 289
1529 : chl 530 (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);
1530 : chl 289
1531 : chl 530 if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
1532 : chl 289
1533 : chl 530 if (inter4v)
1534 :     for(i = 0; i < 4; i++)
1535 :     Search8hinted(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
1536 : chl 289
1537 : chl 530 if (!(inter4v) ||
1538 :     (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1539 :     // INTER MODE
1540 : chl 289
1541 : chl 530 pMB->mode = MODE_INTER;
1542 :     pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]
1543 :     = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
1544 : chl 289
1545 : chl 530 pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1546 :     pMB->sad8[2] = pMB->sad8[3] = iMinSAD[0];
1547 : chl 289
1548 : chl 530 pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
1549 :     pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
1550 :     } else {
1551 :     // INTER4V MODE; all other things are already set in Search8hinted
1552 :     pMB->mode = MODE_INTER4V;
1553 :     pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
1554 : chl 289 }
1555 :    
1556 :     }
1557 :    
1558 : edgomez 195 void
1559 : chl 530 MotionEstimationHinted( MBParam * const pParam,
1560 :     FRAMEINFO * const current,
1561 :     FRAMEINFO * const reference,
1562 :     const IMAGE * const pRefH,
1563 :     const IMAGE * const pRefV,
1564 :     const IMAGE * const pRefHV)
1565 : suxen_drol 118 {
1566 : chl 530 MACROBLOCK *const pMBs = current->mbs;
1567 :     const IMAGE *const pCurrent = &current->image;
1568 :     const IMAGE *const pRef = &reference->image;
1569 : suxen_drol 118
1570 : chl 530 uint32_t x, y;
1571 : chl 312
1572 : chl 530 if (sadInit) (*sadInit) ();
1573 : suxen_drol 118
1574 : chl 530 for (y = 0; y < pParam->mb_height; y++) {
1575 :     for (x = 0; x < pParam->mb_width; x++) {
1576 :     int32_t sad00;
1577 : chl 312
1578 : chl 530 MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1579 : suxen_drol 118
1580 : chl 530 //intra mode is copied from the first pass. At least for the time being
1581 :     if ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1582 : chl 346
1583 : chl 530 if (!(current->global_flags & XVID_LUMIMASKING)) {
1584 :     pMB->dquant = NO_CHANGE;
1585 :     pMB->quant = current->quant; }
1586 : chl 341
1587 : chl 530 if (pMB->dquant == NO_CHANGE) //no skip otherwise, anyway
1588 :     sad00 = pMB->sad16
1589 :     = sad16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1590 :     pRef->y + (x + y * pParam->edged_width) * 16,
1591 :     pParam->edged_width, 256*4096 );
1592 :     else sad00 = 256*4096;
1593 : chl 317
1594 : suxen_drol 118
1595 : chl 530 //initial skip decision
1596 : chl 317
1597 : chl 530 if ( (pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
1598 :     && ( //(pMB->mode == MODE_NOT_CODED) ||
1599 :     (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant) )) ) {
1600 :     if (sad00 < pMB->quant * INITIAL_SKIP_THRESH) {
1601 :     SkipMacroblockP(pMB, sad00);
1602 :     continue; } //skipped
1603 : suxen_drol 118 }
1604 : chl 530 else sad00 = 256*4096;
1605 : suxen_drol 118
1606 : chl 530 if (pMB->mode == MODE_NOT_CODED)
1607 :     SearchP( pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1608 :     y, current->motion_flags, pMB->quant,
1609 :     current->fcode, pParam, pMBs, reference->mbs,
1610 :     current->global_flags & XVID_INTER4V, pMB);
1611 : chl 326
1612 :     else
1613 : chl 530 SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1614 :     y, current->motion_flags, pMB->quant,
1615 :     current->fcode, pParam, pMBs,
1616 :     current->global_flags & XVID_INTER4V, pMB);
1617 : chl 326
1618 : chl 530 /* final skip decision, a.k.a. "the vector you found, really that good?" */
1619 :     if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
1620 :     if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
1621 :     SkipMacroblockP(pMB, sad00);
1622 : chl 326
1623 : suxen_drol 118 }
1624 :     }
1625 :     }
1626 : chl 530

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4