Parent Directory | Revision Log
Revision 1550 - (view) (download)
1 : | edgomez | 1382 | /***************************************************************************** |
2 : | * | ||
3 : | * XVID MPEG-4 VIDEO CODEC | ||
4 : | * - Motion Estimation shared functions - | ||
5 : | * | ||
6 : | * Copyright(C) 2002 Christoph Lampert <gruel@web.de> | ||
7 : | * 2002 Michael Militzer <michael@xvid.org> | ||
8 : | * 2002-2003 Radoslaw Czyz <xvid@syskin.cjb.net> | ||
9 : | * | ||
10 : | * This program is free software ; you can redistribute it and/or modify | ||
11 : | * it under the terms of the GNU General Public License as published by | ||
12 : | * the Free Software Foundation ; either version 2 of the License, or | ||
13 : | * (at your option) any later version. | ||
14 : | * | ||
15 : | * This program is distributed in the hope that it will be useful, | ||
16 : | * but WITHOUT ANY WARRANTY ; without even the implied warranty of | ||
17 : | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 : | * GNU General Public License for more details. | ||
19 : | * | ||
20 : | * You should have received a copy of the GNU General Public License | ||
21 : | * along with this program ; if not, write to the Free Software | ||
22 : | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 : | * | ||
24 : | chl | 1550 | * $Id: estimation_common.c,v 1.7 2004-10-03 14:37:18 chl Exp $ |
25 : | edgomez | 1382 | * |
26 : | ****************************************************************************/ | ||
27 : | |||
28 : | #include "../encoder.h" | ||
29 : | #include "../global.h" | ||
30 : | #include "../image/interpolate8x8.h" | ||
31 : | #include "estimation.h" | ||
32 : | #include "motion.h" | ||
33 : | #include "sad.h" | ||
34 : | #include "motion_inlines.h" | ||
35 : | |||
36 : | |||
37 : | /***************************************************************************** | ||
38 : | * Modified rounding tables | ||
39 : | * Original tables see ISO spec tables 7-6 -> 7-9 | ||
40 : | ****************************************************************************/ | ||
41 : | |||
42 : | const uint32_t roundtab[16] = | ||
43 : | {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 }; | ||
44 : | |||
45 : | /* K = 4 */ | ||
46 : | const uint32_t roundtab_76[16] = | ||
47 : | { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 }; | ||
48 : | |||
49 : | /* K = 2 */ | ||
50 : | const uint32_t roundtab_78[8] = | ||
51 : | { 0, 0, 1, 1, 0, 0, 0, 1 }; | ||
52 : | |||
53 : | /* K = 1 */ | ||
54 : | const uint32_t roundtab_79[4] = | ||
55 : | { 0, 1, 0, 0 }; | ||
56 : | |||
57 : | const int xvid_me_lambda_vec16[32] = | ||
58 : | { 0 ,(int)(1.00235 * NEIGH_TEND_16X16 + 0.5), | ||
59 : | (int)(1.15582*NEIGH_TEND_16X16 + 0.5), (int)(1.31976*NEIGH_TEND_16X16 + 0.5), | ||
60 : | (int)(1.49591*NEIGH_TEND_16X16 + 0.5), (int)(1.68601*NEIGH_TEND_16X16 + 0.5), | ||
61 : | (int)(1.89187*NEIGH_TEND_16X16 + 0.5), (int)(2.11542*NEIGH_TEND_16X16 + 0.5), | ||
62 : | (int)(2.35878*NEIGH_TEND_16X16 + 0.5), (int)(2.62429*NEIGH_TEND_16X16 + 0.5), | ||
63 : | (int)(2.91455*NEIGH_TEND_16X16 + 0.5), (int)(3.23253*NEIGH_TEND_16X16 + 0.5), | ||
64 : | (int)(3.58158*NEIGH_TEND_16X16 + 0.5), (int)(3.96555*NEIGH_TEND_16X16 + 0.5), | ||
65 : | (int)(4.38887*NEIGH_TEND_16X16 + 0.5), (int)(4.85673*NEIGH_TEND_16X16 + 0.5), | ||
66 : | (int)(5.37519*NEIGH_TEND_16X16 + 0.5), (int)(5.95144*NEIGH_TEND_16X16 + 0.5), | ||
67 : | (int)(6.59408*NEIGH_TEND_16X16 + 0.5), (int)(7.31349*NEIGH_TEND_16X16 + 0.5), | ||
68 : | (int)(8.12242*NEIGH_TEND_16X16 + 0.5), (int)(9.03669*NEIGH_TEND_16X16 + 0.5), | ||
69 : | (int)(10.0763*NEIGH_TEND_16X16 + 0.5), (int)(11.2669*NEIGH_TEND_16X16 + 0.5), | ||
70 : | (int)(12.6426*NEIGH_TEND_16X16 + 0.5), (int)(14.2493*NEIGH_TEND_16X16 + 0.5), | ||
71 : | (int)(16.1512*NEIGH_TEND_16X16 + 0.5), (int)(18.442*NEIGH_TEND_16X16 + 0.5), | ||
72 : | (int)(21.2656*NEIGH_TEND_16X16 + 0.5), (int)(24.8580*NEIGH_TEND_16X16 + 0.5), | ||
73 : | (int)(29.6436*NEIGH_TEND_16X16 + 0.5), (int)(36.4949*NEIGH_TEND_16X16 + 0.5) | ||
74 : | }; | ||
75 : | |||
76 : | /***************************************************************************** | ||
77 : | * Code | ||
78 : | ****************************************************************************/ | ||
79 : | |||
80 : | int32_t | ||
81 : | xvid_me_ChromaSAD(const int dx, const int dy, SearchData * const data) | ||
82 : | { | ||
83 : | int sad; | ||
84 : | const uint32_t stride = data->iEdgedWidth/2; | ||
85 : | int offset = (dx>>1) + (dy>>1)*stride; | ||
86 : | int next = 1; | ||
87 : | |||
88 : | if (dx == data->chromaX && dy == data->chromaY) | ||
89 : | return data->chromaSAD; /* it has been checked recently */ | ||
90 : | data->chromaX = dx; data->chromaY = dy; /* backup */ | ||
91 : | |||
92 : | switch (((dx & 1) << 1) | (dy & 1)) { | ||
93 : | case 0: | ||
94 : | sad = sad8(data->CurU, data->RefP[4] + offset, stride); | ||
95 : | sad += sad8(data->CurV, data->RefP[5] + offset, stride); | ||
96 : | break; | ||
97 : | case 1: | ||
98 : | next = stride; | ||
99 : | case 2: | ||
100 : | sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + next, stride); | ||
101 : | sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + next, stride); | ||
102 : | break; | ||
103 : | default: | ||
104 : | interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding); | ||
105 : | sad = sad8(data->CurU, data->RefQ, stride); | ||
106 : | |||
107 : | interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding); | ||
108 : | sad += sad8(data->CurV, data->RefQ, stride); | ||
109 : | break; | ||
110 : | } | ||
111 : | data->chromaSAD = sad; /* backup, part 2 */ | ||
112 : | return sad; | ||
113 : | } | ||
114 : | |||
115 : | uint8_t * | ||
116 : | xvid_me_interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data) | ||
117 : | { | ||
118 : | /* create or find a qpel-precision reference picture; return pointer to it */ | ||
119 : | uint8_t * Reference = data->RefQ + 16*dir; | ||
120 : | const uint32_t iEdgedWidth = data->iEdgedWidth; | ||
121 : | const uint32_t rounding = data->rounding; | ||
122 : | const int halfpel_x = x/2; | ||
123 : | const int halfpel_y = y/2; | ||
124 : | const uint8_t *ref1, *ref2, *ref3, *ref4; | ||
125 : | |||
126 : | ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data); | ||
127 : | ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
128 : | switch( ((x&1)<<1) + (y&1) ) { | ||
129 : | case 3: /* x and y in qpel resolution - the "corners" (top left/right and */ | ||
130 : | /* bottom left/right) during qpel refinement */ | ||
131 : | ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data); | ||
132 : | ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data); | ||
133 : | ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data); | ||
134 : | ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
135 : | ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
136 : | ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
137 : | interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding); | ||
138 : | break; | ||
139 : | |||
140 : | case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */ | ||
141 : | ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data); | ||
142 : | ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
143 : | interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8); | ||
144 : | break; | ||
145 : | |||
146 : | case 2: /* x qpel, y halfpel - left or right during qpel refinement */ | ||
147 : | ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data); | ||
148 : | ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth; | ||
149 : | interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8); | ||
150 : | break; | ||
151 : | |||
152 : | default: /* pure halfpel position */ | ||
153 : | return (uint8_t *) ref1; | ||
154 : | |||
155 : | } | ||
156 : | return Reference; | ||
157 : | } | ||
158 : | |||
159 : | uint8_t * | ||
160 : | xvid_me_interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data) | ||
161 : | { | ||
162 : | /* create or find a qpel-precision reference picture; return pointer to it */ | ||
163 : | uint8_t * Reference = data->RefQ + 16*dir; | ||
164 : | const uint32_t iEdgedWidth = data->iEdgedWidth; | ||
165 : | const uint32_t rounding = data->rounding; | ||
166 : | const int halfpel_x = x/2; | ||
167 : | const int halfpel_y = y/2; | ||
168 : | const uint8_t *ref1, *ref2, *ref3, *ref4; | ||
169 : | |||
170 : | ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data); | ||
171 : | switch( ((x&1)<<1) + (y&1) ) { | ||
172 : | case 3: | ||
173 : | /* | ||
174 : | * x and y in qpel resolution - the "corners" (top left/right and | ||
175 : | * bottom left/right) during qpel refinement | ||
176 : | */ | ||
177 : | ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data); | ||
178 : | ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data); | ||
179 : | ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data); | ||
180 : | interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding); | ||
181 : | interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding); | ||
182 : | interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding); | ||
183 : | interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding); | ||
184 : | break; | ||
185 : | |||
186 : | case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */ | ||
187 : | ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data); | ||
188 : | interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8); | ||
189 : | interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8); | ||
190 : | interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8); | ||
191 : | interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8); | ||
192 : | break; | ||
193 : | |||
194 : | case 2: /* x qpel, y halfpel - left or right during qpel refinement */ | ||
195 : | ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data); | ||
196 : | interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8); | ||
197 : | interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8); | ||
198 : | interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8); | ||
199 : | interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8); | ||
200 : | break; | ||
201 : | |||
202 : | |||
203 : | default: /* pure halfpel position */ | ||
204 : | return (uint8_t *) ref1; | ||
205 : | } | ||
206 : | return Reference; | ||
207 : | } | ||
208 : | |||
209 : | void | ||
210 : | xvid_me_AdvDiamondSearch(int x, int y, SearchData * const data, | ||
211 : | int bDirection, CheckFunc * const CheckCandidate) | ||
212 : | { | ||
213 : | |||
214 : | /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ | ||
215 : | |||
216 : | unsigned int * const iDirection = &data->dir; | ||
217 : | |||
218 : | for(;;) { /* forever */ | ||
219 : | *iDirection = 0; | ||
220 : | if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1); | ||
221 : | if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2); | ||
222 : | if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4); | ||
223 : | if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8); | ||
224 : | |||
225 : | /* now we're doing diagonal checks near our candidate */ | ||
226 : | |||
227 : | if (*iDirection) { /* if anything found */ | ||
228 : | bDirection = *iDirection; | ||
229 : | *iDirection = 0; | ||
230 : | x = data->currentMV->x; y = data->currentMV->y; | ||
231 : | if (bDirection & 3) { /* our candidate is left or right */ | ||
232 : | CHECK_CANDIDATE(x, y + iDiamondSize, 8); | ||
233 : | CHECK_CANDIDATE(x, y - iDiamondSize, 4); | ||
234 : | } else { /* what remains here is up or down */ | ||
235 : | CHECK_CANDIDATE(x + iDiamondSize, y, 2); | ||
236 : | CHECK_CANDIDATE(x - iDiamondSize, y, 1); | ||
237 : | } | ||
238 : | |||
239 : | if (*iDirection) { | ||
240 : | bDirection += *iDirection; | ||
241 : | x = data->currentMV->x; y = data->currentMV->y; | ||
242 : | } | ||
243 : | } else { /* about to quit, eh? not so fast.... */ | ||
244 : | switch (bDirection) { | ||
245 : | case 2: | ||
246 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
247 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
248 : | break; | ||
249 : | case 1: | ||
250 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
251 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
252 : | break; | ||
253 : | case 2 + 4: | ||
254 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
255 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
256 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
257 : | break; | ||
258 : | case 4: | ||
259 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
260 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
261 : | break; | ||
262 : | case 8: | ||
263 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
264 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
265 : | break; | ||
266 : | case 1 + 4: | ||
267 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
268 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
269 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
270 : | break; | ||
271 : | case 2 + 8: | ||
272 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
273 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
274 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
275 : | break; | ||
276 : | case 1 + 8: | ||
277 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
278 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
279 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
280 : | break; | ||
281 : | default: /* 1+2+4+8 == we didn't find anything at all */ | ||
282 : | CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4); | ||
283 : | CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8); | ||
284 : | CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4); | ||
285 : | CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8); | ||
286 : | break; | ||
287 : | } | ||
288 : | if (!*iDirection) break; /* ok, the end. really */ | ||
289 : | bDirection = *iDirection; | ||
290 : | x = data->currentMV->x; y = data->currentMV->y; | ||
291 : | } | ||
292 : | } | ||
293 : | } | ||
294 : | |||
295 : | void | ||
296 : | xvid_me_SquareSearch(int x, int y, SearchData * const data, | ||
297 : | int bDirection, CheckFunc * const CheckCandidate) | ||
298 : | { | ||
299 : | unsigned int * const iDirection = &data->dir; | ||
300 : | |||
301 : | do { | ||
302 : | *iDirection = 0; | ||
303 : | if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64); | ||
304 : | if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128); | ||
305 : | if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32); | ||
306 : | if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128); | ||
307 : | if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64); | ||
308 : | if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128); | ||
309 : | if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128); | ||
310 : | if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128); | ||
311 : | |||
312 : | bDirection = *iDirection; | ||
313 : | x = data->currentMV->x; y = data->currentMV->y; | ||
314 : | } while (*iDirection); | ||
315 : | } | ||
316 : | |||
317 : | void | ||
318 : | xvid_me_DiamondSearch(int x, int y, SearchData * const data, | ||
319 : | int bDirection, CheckFunc * const CheckCandidate) | ||
320 : | { | ||
321 : | |||
322 : | /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ | ||
323 : | |||
324 : | unsigned int * const iDirection = &data->dir; | ||
325 : | |||
326 : | do { | ||
327 : | *iDirection = 0; | ||
328 : | if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1); | ||
329 : | if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2); | ||
330 : | if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4); | ||
331 : | if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8); | ||
332 : | |||
333 : | /* now we're doing diagonal checks near our candidate */ | ||
334 : | syskin | 1549 | bDirection = *iDirection; |
335 : | edgomez | 1382 | if (*iDirection) { /* checking if anything found */ |
336 : | x = data->currentMV->x; y = data->currentMV->y; | ||
337 : | if (bDirection & 3) { /* our candidate is left or right */ | ||
338 : | chl | 1550 | *iDirection=4+8; |
339 : | edgomez | 1382 | CHECK_CANDIDATE(x, y + iDiamondSize, 8); |
340 : | CHECK_CANDIDATE(x, y - iDiamondSize, 4); | ||
341 : | } else { /* what remains here is up or down */ | ||
342 : | chl | 1550 | *iDirection=1+2; |
343 : | edgomez | 1382 | CHECK_CANDIDATE(x + iDiamondSize, y, 2); |
344 : | CHECK_CANDIDATE(x - iDiamondSize, y, 1); | ||
345 : | } | ||
346 : | bDirection += *iDirection; | ||
347 : | x = data->currentMV->x; y = data->currentMV->y; | ||
348 : | } | ||
349 : | } | ||
350 : | syskin | 1549 | while (bDirection); |
351 : | edgomez | 1382 | } |
352 : | |||
353 : | void | ||
354 : | syskin | 1478 | xvid_me_SubpelRefine(VECTOR centerMV, SearchData * const data, CheckFunc * const CheckCandidate, int dir) |
355 : | edgomez | 1382 | { |
356 : | /* Do a half-pel or q-pel refinement */ | ||
357 : | |||
358 : | syskin | 1441 | CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, dir); |
359 : | CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, dir); | ||
360 : | CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, dir); | ||
361 : | CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, dir); | ||
362 : | CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, dir); | ||
363 : | CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, dir); | ||
364 : | CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, dir); | ||
365 : | CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, dir); | ||
366 : | edgomez | 1382 | } |
367 : | |||
368 : | syskin | 1441 | #define CHECK_CANDIDATE_2ndBEST(X, Y, DIR) { \ |
369 : | *data->iMinSAD = s_best2; \ | ||
370 : | CheckCandidate((X),(Y), data, direction); \ | ||
371 : | if (data->iMinSAD[0] < s_best) { \ | ||
372 : | s_best2 = s_best; \ | ||
373 : | s_best = data->iMinSAD[0]; \ | ||
374 : | v_best2 = v_best; \ | ||
375 : | v_best.x = X; v_best.y = Y; \ | ||
376 : | dir = DIR; \ | ||
377 : | } else if (data->iMinSAD[0] < s_best2) { \ | ||
378 : | s_best2 = data->iMinSAD[0]; \ | ||
379 : | v_best2.x = X; v_best2.y = Y; \ | ||
380 : | } \ | ||
381 : | } | ||
382 : | |||
383 : | edgomez | 1382 | void |
384 : | syskin | 1441 | FullRefine_Fast(SearchData * data, CheckFunc * CheckCandidate, int direction) |
385 : | edgomez | 1382 | { |
386 : | syskin | 1441 | /* Do a fast h-pel and then q-pel refinement */ |
387 : | |||
388 : | int32_t s_best = data->iMinSAD[0], s_best2 = 256*4096; | ||
389 : | VECTOR v_best, v_best2; | ||
390 : | int dir = 0, xo2, yo2, best_halfpel, b_cbp; | ||
391 : | edgomez | 1382 | |
392 : | syskin | 1441 | int xo = 2*data->currentMV[0].x, yo = 2*data->currentMV[0].y; |
393 : | |||
394 : | data->currentQMV[0].x = v_best.x = xo; | ||
395 : | data->currentQMV[0].y = v_best.y = yo; | ||
396 : | edgomez | 1382 | |
397 : | syskin | 1441 | data->qpel_precision = 1; |
398 : | edgomez | 1382 | |
399 : | syskin | 1441 | /* halfpel refinement: check 8 neighbours, but keep the second best SAD as well */ |
400 : | CHECK_CANDIDATE_2ndBEST(xo - 2, yo, 1+16+64); | ||
401 : | CHECK_CANDIDATE_2ndBEST(xo + 2, yo, 2+32+128); | ||
402 : | CHECK_CANDIDATE_2ndBEST(xo, yo - 2, 4+16+32); | ||
403 : | CHECK_CANDIDATE_2ndBEST(xo, yo + 2, 8+64+128); | ||
404 : | CHECK_CANDIDATE_2ndBEST(xo - 2, yo - 2, 1+4+16+32+64); | ||
405 : | CHECK_CANDIDATE_2ndBEST(xo + 2, yo - 2, 2+4+16+32+128); | ||
406 : | CHECK_CANDIDATE_2ndBEST(xo - 2, yo + 2, 1+8+16+64+128); | ||
407 : | CHECK_CANDIDATE_2ndBEST(xo + 2, yo + 2, 2+8+32+64+128); | ||
408 : | edgomez | 1382 | |
409 : | syskin | 1441 | xo = v_best.x; yo = v_best.y, b_cbp = data->cbp[0]; |
410 : | edgomez | 1382 | |
411 : | syskin | 1441 | /* we need all 8 neighbours *of best hpel position found above* checked for 2nd best |
412 : | let's check the missing ones */ | ||
413 : | edgomez | 1382 | |
414 : | syskin | 1441 | /* on rare occasions, 1st best and 2nd best are far away, and 2nd best is not 1st best's neighbour. |
415 : | to simplify stuff, we'll forget that evil 2nd best and make a full search for a new 2nd best */ | ||
416 : | /* todo. we should check the missing neighbours first, maybe they'll give us 2nd best which is even better | ||
417 : | than the infamous one. in that case, we will not have to re-check the other neighbours */ | ||
418 : | edgomez | 1382 | |
419 : | syskin | 1441 | if (abs(v_best.x - v_best2.x) > 2 || abs(v_best.y - v_best2.y) > 2) { /* v_best2 is useless */ |
420 : | data->iMinSAD[0] = 256*4096; | ||
421 : | dir = ~0; /* all */ | ||
422 : | } else { | ||
423 : | data->iMinSAD[0] = s_best2; | ||
424 : | data->currentQMV[0] = v_best2; | ||
425 : | } | ||
426 : | edgomez | 1382 | |
427 : | syskin | 1441 | if (dir & 1) CHECK_CANDIDATE( xo - 2, yo, direction); |
428 : | if (dir & 2) CHECK_CANDIDATE( xo + 2, yo, direction); | ||
429 : | if (dir & 4) CHECK_CANDIDATE( xo, yo - 2, direction); | ||
430 : | if (dir & 8) CHECK_CANDIDATE( xo, yo + 2, direction); | ||
431 : | if (dir & 16) CHECK_CANDIDATE( xo - 2, yo - 2, direction); | ||
432 : | if (dir & 32) CHECK_CANDIDATE( xo + 2, yo - 2, direction); | ||
433 : | if (dir & 64) CHECK_CANDIDATE( xo - 2, yo + 2, direction); | ||
434 : | if (dir & 128) CHECK_CANDIDATE( xo + 2, yo + 2, direction); | ||
435 : | edgomez | 1382 | |
436 : | syskin | 1441 | /* read the position of 2nd best */ |
437 : | v_best2 = data->currentQMV[0]; | ||
438 : | |||
439 : | /* after second_best has been found, go back to best vector */ | ||
440 : | |||
441 : | data->currentQMV[0].x = xo; | ||
442 : | data->currentQMV[0].y = yo; | ||
443 : | data->cbp[0] = b_cbp; | ||
444 : | |||
445 : | data->currentMV[0].x = xo/2; | ||
446 : | data->currentMV[0].y = yo/2; | ||
447 : | data->iMinSAD[0] = best_halfpel = s_best; | ||
448 : | |||
449 : | xo2 = v_best2.x; | ||
450 : | yo2 = v_best2.y; | ||
451 : | s_best2 = 256*4096; | ||
452 : | |||
453 : | edgomez | 1382 | if (yo == yo2) { |
454 : | syskin | 1441 | CHECK_CANDIDATE_2ndBEST((xo+xo2)>>1, yo, 0); |
455 : | CHECK_CANDIDATE_2ndBEST(xo, yo-1, 0); | ||
456 : | CHECK_CANDIDATE_2ndBEST(xo, yo+1, 0); | ||
457 : | data->currentQMV[0] = v_best; | ||
458 : | data->iMinSAD[0] = s_best; | ||
459 : | edgomez | 1382 | |
460 : | syskin | 1441 | if(best_halfpel <= s_best2) return; |
461 : | edgomez | 1382 | |
462 : | syskin | 1441 | if(data->currentQMV[0].x == v_best2.x) { |
463 : | CHECK_CANDIDATE((xo+xo2)>>1, yo-1, direction); | ||
464 : | CHECK_CANDIDATE((xo+xo2)>>1, yo+1, direction); | ||
465 : | edgomez | 1382 | } else { |
466 : | CHECK_CANDIDATE((xo+xo2)>>1, | ||
467 : | syskin | 1441 | (data->currentQMV[0].x == xo) ? data->currentQMV[0].y : v_best2.y, direction); |
468 : | edgomez | 1382 | } |
469 : | return; | ||
470 : | } | ||
471 : | |||
472 : | if (xo == xo2) { | ||
473 : | syskin | 1441 | CHECK_CANDIDATE_2ndBEST(xo, (yo+yo2)>>1, 0); |
474 : | CHECK_CANDIDATE_2ndBEST(xo-1, yo, 0); | ||
475 : | CHECK_CANDIDATE_2ndBEST(xo+1, yo, 0); | ||
476 : | data->currentQMV[0] = v_best; | ||
477 : | data->iMinSAD[0] = s_best; | ||
478 : | edgomez | 1382 | |
479 : | syskin | 1441 | if(best_halfpel <= s_best2) return; |
480 : | edgomez | 1382 | |
481 : | syskin | 1441 | if(data->currentQMV[0].y == v_best2.y) { |
482 : | CHECK_CANDIDATE(xo-1, (yo+yo2)>>1, direction); | ||
483 : | CHECK_CANDIDATE(xo+1, (yo+yo2)>>1, direction); | ||
484 : | edgomez | 1382 | } else { |
485 : | syskin | 1441 | CHECK_CANDIDATE((data->currentQMV[0].y == yo) ? data->currentQMV[0].x : v_best2.x, (yo+yo2)>>1, direction); |
486 : | edgomez | 1382 | } |
487 : | return; | ||
488 : | } | ||
489 : | |||
490 : | syskin | 1441 | CHECK_CANDIDATE_2ndBEST(xo, (yo+yo2)>>1, 0); |
491 : | CHECK_CANDIDATE_2ndBEST((xo+xo2)>>1, yo, 0); | ||
492 : | data->currentQMV[0] = v_best; | ||
493 : | data->iMinSAD[0] = s_best; | ||
494 : | edgomez | 1382 | |
495 : | syskin | 1441 | if(best_halfpel <= s_best2) return; |
496 : | edgomez | 1382 | |
497 : | syskin | 1441 | CHECK_CANDIDATE((xo+xo2)>>1, (yo+yo2)>>1, direction); |
498 : | |||
499 : | edgomez | 1382 | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |