adaptive quantization (lumi/temporal & spatial complexity masking)
[ffmpeg.git] / libavcodec / motion_est.c
1 /*
2  * Motion estimation 
3  * Copyright (c) 2000,2001 Fabrice Bellard.
4  * Copyright (c) 2002 Michael Niedermayer
5  * 
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
22  */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include "avcodec.h"
26 #include "dsputil.h"
27 #include "mpegvideo.h"
28
29 #define SQ(a) ((a)*(a))
30 #define INTER_BIAS      257
31
32 #define P_LAST P[0]
33 #define P_LEFT P[1]
34 #define P_TOP P[2]
35 #define P_TOPRIGHT P[3]
36 #define P_MEDIAN P[4]
37 #define P_LAST_LEFT P[5]
38 #define P_LAST_RIGHT P[6]
39 #define P_LAST_TOP P[7]
40 #define P_LAST_BOTTOM P[8]
41 #define P_MV1 P[9]
42
43
44 static int pix_dev(UINT8 * pix, int line_size, int mean)
45 {
46     int s, i, j;
47
48     s = 0;
49     for (i = 0; i < 16; i++) {
50         for (j = 0; j < 16; j += 8) {
51             s += ABS(pix[0]-mean);
52             s += ABS(pix[1]-mean);
53             s += ABS(pix[2]-mean);
54             s += ABS(pix[3]-mean);
55             s += ABS(pix[4]-mean);
56             s += ABS(pix[5]-mean);
57             s += ABS(pix[6]-mean);
58             s += ABS(pix[7]-mean);
59             pix += 8;
60         }
61         pix += line_size - 16;
62     }
63     return s;
64 }
65
66 static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size)
67 {
68     int s, i, j;
69     UINT32 *sq = squareTbl + 256;
70
71     s = 0;
72     for (i = 0; i < 16; i++) {
73         for (j = 0; j < 16; j += 8) {
74             s += sq[pix1[0] - pix2[0]];
75             s += sq[pix1[1] - pix2[1]];
76             s += sq[pix1[2] - pix2[2]];
77             s += sq[pix1[3] - pix2[3]];
78             s += sq[pix1[4] - pix2[4]];
79             s += sq[pix1[5] - pix2[5]];
80             s += sq[pix1[6] - pix2[6]];
81             s += sq[pix1[7] - pix2[7]];
82             pix1 += 8;
83             pix2 += 8;
84         }
85         pix1 += line_size - 16;
86         pix2 += line_size - 16;
87     }
88     return s;
89 }
90
91 static void no_motion_search(MpegEncContext * s,
92                              int *mx_ptr, int *my_ptr)
93 {
94     *mx_ptr = 16 * s->mb_x;
95     *my_ptr = 16 * s->mb_y;
96 }
97
98 static int full_motion_search(MpegEncContext * s,
99                               int *mx_ptr, int *my_ptr, int range,
100                               int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture)
101 {
102     int x1, y1, x2, y2, xx, yy, x, y;
103     int mx, my, dmin, d;
104     UINT8 *pix;
105
106     xx = 16 * s->mb_x;
107     yy = 16 * s->mb_y;
108     x1 = xx - range + 1;        /* we loose one pixel to avoid boundary pb with half pixel pred */
109     if (x1 < xmin)
110         x1 = xmin;
111     x2 = xx + range - 1;
112     if (x2 > xmax)
113         x2 = xmax;
114     y1 = yy - range + 1;
115     if (y1 < ymin)
116         y1 = ymin;
117     y2 = yy + range - 1;
118     if (y2 > ymax)
119         y2 = ymax;
120     pix = s->new_picture[0] + (yy * s->linesize) + xx;
121     dmin = 0x7fffffff;
122     mx = 0;
123     my = 0;
124     for (y = y1; y <= y2; y++) {
125         for (x = x1; x <= x2; x++) {
126             d = pix_abs16x16(pix, ref_picture + (y * s->linesize) + x,
127                              s->linesize);
128             if (d < dmin ||
129                 (d == dmin &&
130                  (abs(x - xx) + abs(y - yy)) <
131                  (abs(mx - xx) + abs(my - yy)))) {
132                 dmin = d;
133                 mx = x;
134                 my = y;
135             }
136         }
137     }
138
139     *mx_ptr = mx;
140     *my_ptr = my;
141
142 #if 0
143     if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
144         *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
145         fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
146     }
147 #endif
148     return dmin;
149 }
150
151
152 static int log_motion_search(MpegEncContext * s,
153                              int *mx_ptr, int *my_ptr, int range,
154                              int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture)
155 {
156     int x1, y1, x2, y2, xx, yy, x, y;
157     int mx, my, dmin, d;
158     UINT8 *pix;
159
160     xx = s->mb_x << 4;
161     yy = s->mb_y << 4;
162
163     /* Left limit */
164     x1 = xx - range;
165     if (x1 < xmin)
166         x1 = xmin;
167
168     /* Right limit */
169     x2 = xx + range;
170     if (x2 > xmax)
171         x2 = xmax;
172
173     /* Upper limit */
174     y1 = yy - range;
175     if (y1 < ymin)
176         y1 = ymin;
177
178     /* Lower limit */
179     y2 = yy + range;
180     if (y2 > ymax)
181         y2 = ymax;
182
183     pix = s->new_picture[0] + (yy * s->linesize) + xx;
184     dmin = 0x7fffffff;
185     mx = 0;
186     my = 0;
187
188     do {
189         for (y = y1; y <= y2; y += range) {
190             for (x = x1; x <= x2; x += range) {
191                 d = pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize);
192                 if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
193                     dmin = d;
194                     mx = x;
195                     my = y;
196                 }
197             }
198         }
199
200         range = range >> 1;
201
202         x1 = mx - range;
203         if (x1 < xmin)
204             x1 = xmin;
205
206         x2 = mx + range;
207         if (x2 > xmax)
208             x2 = xmax;
209
210         y1 = my - range;
211         if (y1 < ymin)
212             y1 = ymin;
213
214         y2 = my + range;
215         if (y2 > ymax)
216             y2 = ymax;
217
218     } while (range >= 1);
219
220 #ifdef DEBUG
221     fprintf(stderr, "log       - MX: %d\tMY: %d\n", mx, my);
222 #endif
223     *mx_ptr = mx;
224     *my_ptr = my;
225     return dmin;
226 }
227
228 static int phods_motion_search(MpegEncContext * s,
229                                int *mx_ptr, int *my_ptr, int range,
230                                int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture)
231 {
232     int x1, y1, x2, y2, xx, yy, x, y, lastx, d;
233     int mx, my, dminx, dminy;
234     UINT8 *pix;
235
236     xx = s->mb_x << 4;
237     yy = s->mb_y << 4;
238
239     /* Left limit */
240     x1 = xx - range;
241     if (x1 < xmin)
242         x1 = xmin;
243
244     /* Right limit */
245     x2 = xx + range;
246     if (x2 > xmax)
247         x2 = xmax;
248
249     /* Upper limit */
250     y1 = yy - range;
251     if (y1 < ymin)
252         y1 = ymin;
253
254     /* Lower limit */
255     y2 = yy + range;
256     if (y2 > ymax)
257         y2 = ymax;
258
259     pix = s->new_picture[0] + (yy * s->linesize) + xx;
260     mx = 0;
261     my = 0;
262
263     x = xx;
264     y = yy;
265     do {
266         dminx = 0x7fffffff;
267         dminy = 0x7fffffff;
268
269         lastx = x;
270         for (x = x1; x <= x2; x += range) {
271             d = pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize);
272             if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
273                 dminx = d;
274                 mx = x;
275             }
276         }
277
278         x = lastx;
279         for (y = y1; y <= y2; y += range) {
280             d = pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize);
281             if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
282                 dminy = d;
283                 my = y;
284             }
285         }
286
287         range = range >> 1;
288
289         x = mx;
290         y = my;
291         x1 = mx - range;
292         if (x1 < xmin)
293             x1 = xmin;
294
295         x2 = mx + range;
296         if (x2 > xmax)
297             x2 = xmax;
298
299         y1 = my - range;
300         if (y1 < ymin)
301             y1 = ymin;
302
303         y2 = my + range;
304         if (y2 > ymax)
305             y2 = ymax;
306
307     } while (range >= 1);
308
309 #ifdef DEBUG
310     fprintf(stderr, "phods     - MX: %d\tMY: %d\n", mx, my);
311 #endif
312
313     /* half pixel search */
314     *mx_ptr = mx;
315     *my_ptr = my;
316     return dminy;
317 }
318
319
320 #define Z_THRESHOLD 256
321
322 #define CHECK_MV(x,y)\
323 {\
324     const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
325     const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
326     if(map[index]!=key){\
327         d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\
328         d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
329         COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\
330         map[index]= key;\
331         score_map[index]= d;\
332     }\
333 }
334
335 #define CHECK_MV_DIR(x,y,new_dir)\
336 {\
337     const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
338     const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
339     if(map[index]!=key){\
340         d = pix_abs(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\
341         d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
342         if(d<dmin){\
343             best[0]=x;\
344             best[1]=y;\
345             dmin=d;\
346             next_dir= new_dir;\
347         }\
348         map[index]= key;\
349         score_map[index]= d;\
350     }\
351 }
352
353 #define CHECK_MV4(x,y)\
354 {\
355     const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
356     const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
357     if(map[index]!=key){\
358         d = pix_abs8x8(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\
359         d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
360         COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\
361         map[index]= key;\
362         score_map[index]= d;\
363     }\
364 }
365
366 #define check(x,y,S,v)\
367 if( (x)<(xmin<<(S)) ) printf("%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
368 if( (x)>(xmax<<(S)) ) printf("%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
369 if( (y)<(ymin<<(S)) ) printf("%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
370 if( (y)>(ymax<<(S)) ) printf("%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\
371
372
373 static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin,
374                                        UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
375                                        int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
376                                        int xmin, int ymin, int xmax, int ymax, int shift,
377                                        uint32_t *map, uint16_t *score_map, int map_generation,
378                                        op_pixels_abs_func pix_abs)
379 {
380     int next_dir=-1;
381
382     for(;;){
383         int d;
384         const int dir= next_dir;
385         const int x= best[0];
386         const int y= best[1];
387         next_dir=-1;
388
389 //printf("%d", dir);
390         if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y  , 0)
391         if(dir!=3 && y>ymin) CHECK_MV_DIR(x  , y-1, 1)
392         if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y  , 2)
393         if(dir!=1 && y<ymax) CHECK_MV_DIR(x  , y+1, 3)
394
395         if(next_dir==-1){
396             return dmin;
397         }
398     }
399
400 /*    for(;;){
401         int d;
402         const int x= best[0];
403         const int y= best[1];
404         const int last_min=dmin;
405         if(x>xmin) CHECK_MV(x-1, y  )
406         if(y>xmin) CHECK_MV(x  , y-1)
407         if(x<xmax) CHECK_MV(x+1, y  )
408         if(y<xmax) CHECK_MV(x  , y+1)
409         if(x>xmin && y>ymin) CHECK_MV(x-1, y-1)
410         if(x>xmin && y<ymax) CHECK_MV(x-1, y+1)
411         if(x<xmax && y>ymin) CHECK_MV(x+1, y-1)
412         if(x<xmax && y<ymax) CHECK_MV(x+1, y+1)
413         if(x-1>xmin) CHECK_MV(x-2, y  )
414         if(y-1>xmin) CHECK_MV(x  , y-2)
415         if(x+1<xmax) CHECK_MV(x+2, y  )
416         if(y+1<xmax) CHECK_MV(x  , y+2)
417         if(x-1>xmin && y-1>ymin) CHECK_MV(x-2, y-2)
418         if(x-1>xmin && y+1<ymax) CHECK_MV(x-2, y+2)
419         if(x+1<xmax && y-1>ymin) CHECK_MV(x+2, y-2)
420         if(x+1<xmax && y+1<ymax) CHECK_MV(x+2, y+2)
421         if(dmin==last_min) return dmin;
422     }
423     */
424 }
425
426 #if 1
427 #define SNAKE_1 3
428 #define SNAKE_2 2
429 #else
430 #define SNAKE_1 7
431 #define SNAKE_2 3
432 #endif
433 static inline int snake_search(MpegEncContext * s, int *best, int dmin,
434                                        UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
435                                        int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
436                                        int xmin, int ymin, int xmax, int ymax, int shift,
437                                        uint32_t *map, uint16_t *score_map,int map_generation,
438                                        op_pixels_abs_func pix_abs)
439 {
440     int dir=0;
441     int c=1;
442     static int x_dir[8]= {1,1,0,-1,-1,-1, 0, 1};
443     static int y_dir[8]= {0,1,1, 1, 0,-1,-1,-1};
444     int fails=0;
445     int last_d[2]={dmin, dmin};
446
447 /*static int good=0;
448 static int bad=0;
449 static int point=0;
450
451 point++;
452 if(256*256*256*64%point==0)
453 {
454     printf("%d %d %d\n", good, bad, point);
455 }*/
456
457     for(;;){
458         int x= best[0];
459         int y= best[1];
460         int d;
461         x+=x_dir[dir];
462         y+=y_dir[dir];
463         if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){
464             const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;
465             const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);
466             if(map[index]!=key){
467                 d = pix_abs(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);
468                 d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;
469                 map[index]=key;
470                 score_map[index]=d;
471             }else
472                 d= dmin+1;
473         }else{
474             d = dmin + 10000; //FIXME smarter boundary handling
475         }
476         if(d<dmin){
477             best[0]=x;
478             best[1]=y;
479             dmin=d;
480
481             if(last_d[1] - last_d[0] > last_d[0] - d) c= -c;
482             dir+=c;
483
484             fails=0;
485 //good++;
486             last_d[1]=last_d[0];
487             last_d[0]=d;
488         }else{
489 //bad++;
490             if(fails){
491                 if(fails>=SNAKE_1+1) return dmin;
492             }else{
493                 if(dir&1) dir-= c*3;
494                 else      c= -c;
495 //                c= -c;
496             }
497             dir+=c*SNAKE_2;
498             fails++;
499         }
500         dir&=7;
501     }
502 }
503
504 static inline int cross_search(MpegEncContext * s, int *best, int dmin,
505                                        UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
506                                        int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
507                                        int xmin, int ymin, int xmax, int ymax, int shift,
508                                        uint32_t *map, uint16_t *score_map,int map_generation,
509                                        op_pixels_abs_func pix_abs)
510 {
511     static int x_dir[4]= {-1, 0, 1, 0};
512     static int y_dir[4]= { 0,-1, 0, 1};
513     int improvement[2]={100000, 100000};
514     int dirs[2]={2, 3};
515     int dir;
516     int last_dir= -1;
517     
518     for(;;){
519         dir= dirs[ improvement[0] > improvement[1] ? 0 : 1 ];
520         if(improvement[dir&1]==-1) return dmin;
521         
522         {
523             const int x= best[0] + x_dir[dir];
524             const int y= best[1] + y_dir[dir];
525             const int key= (y<<ME_MAP_MV_BITS) + x + map_generation;
526             const int index= ((y<<ME_MAP_SHIFT) + x)&(ME_MAP_SIZE-1);
527             int d;
528             if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){
529                 if(map[index]!=key){
530                     d = pix_abs(new_pic, old_pic + x + y*pic_stride, pic_stride);
531                     d += (mv_penalty[(x<<shift)-pred_x] + mv_penalty[(y<<shift)-pred_y])*quant;
532                     map[index]=key;
533                     score_map[index]=d;
534                     if(d<dmin){
535                         improvement[dir&1]= dmin-d;
536                         improvement[(dir&1)^1]++;
537                         dmin=d;
538                         best[0]= x;
539                         best[1]= y;
540                         last_dir=dir;
541                         continue;
542                     }
543                 }else{
544                     d= score_map[index];
545                 }
546             }else{
547                 d= dmin + 1000; //FIXME is this a good idea?
548             }
549             /* evaluated point was cached or checked and worse */
550
551             if(last_dir==dir){
552                 improvement[dir&1]= -1;
553             }else{
554                 improvement[dir&1]= d-dmin;
555                 last_dir= dirs[dir&1]= dir^2;
556             }
557         }
558     }
559 }
560
561 static inline int update_map_generation(MpegEncContext * s)
562 {
563     s->me_map_generation+= 1<<(ME_MAP_MV_BITS*2);
564     if(s->me_map_generation==0){
565         s->me_map_generation= 1<<(ME_MAP_MV_BITS*2);
566         memset(s->me_map, 0, sizeof(uint32_t)*ME_MAP_SIZE);
567     }
568     return s->me_map_generation;
569 }
570
571 static int epzs_motion_search(MpegEncContext * s,
572                              int *mx_ptr, int *my_ptr,
573                              int P[10][2], int pred_x, int pred_y,
574                              int xmin, int ymin, int xmax, int ymax, uint8_t * ref_picture)
575 {
576     int best[2]={0, 0};
577     int d, dmin; 
578     UINT8 *new_pic, *old_pic;
579     const int pic_stride= s->linesize;
580     const int pic_xy= (s->mb_y*pic_stride + s->mb_x)*16;
581     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
582     int quant= s->qscale; // qscale of the prev frame
583     const int shift= 1+s->quarter_sample;
584     uint32_t *map= s->me_map;
585     uint16_t *score_map= s->me_score_map;
586     int map_generation;
587
588     new_pic = s->new_picture[0] + pic_xy;
589     old_pic = ref_picture + pic_xy;
590     
591     map_generation= update_map_generation(s);
592
593     dmin = pix_abs16x16(new_pic, old_pic, pic_stride);
594     map[0]= map_generation;
595     score_map[0]= dmin;
596
597     /* first line */
598     if ((s->mb_y == 0 || s->first_slice_line)) {
599         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
600         CHECK_MV(P_LAST[0]>>shift, P_LAST[1]>>shift)
601     }else{
602         if(dmin<256 && ( P_LEFT[0]    |P_LEFT[1]
603                         |P_TOP[0]     |P_TOP[1]
604                         |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){
605             *mx_ptr= 0;
606             *my_ptr= 0;
607             s->skip_me=1;
608             return dmin;
609         }
610         CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
611         if(dmin>256*2){
612             CHECK_MV(P_LAST[0]    >>shift, P_LAST[1]    >>shift)
613             CHECK_MV(P_LEFT[0]    >>shift, P_LEFT[1]    >>shift)
614             CHECK_MV(P_TOP[0]     >>shift, P_TOP[1]     >>shift)
615             CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
616         }
617     }
618     if(dmin>256*4){
619         CHECK_MV(P_LAST_RIGHT[0] >>shift, P_LAST_RIGHT[1] >>shift)
620         CHECK_MV(P_LAST_BOTTOM[0]>>shift, P_LAST_BOTTOM[1]>>shift)
621     }
622 #if 0 //doest only slow things down
623     if(dmin>512*3){
624         int step;
625         dmin= score_map[0];
626         best[0]= best[1]=0;
627         for(step=128; step>0; step>>=1){
628             const int step2= step;
629             int y;
630             for(y=-step2+best[1]; y<=step2+best[1]; y+=step){
631                 int x;
632                 if(y<ymin || y>ymax) continue;
633
634                 for(x=-step2+best[0]; x<=step2+best[0]; x+=step){
635                     if(x<xmin || x>xmax) continue;
636                     if(x==best[0] && y==best[1]) continue;
637                     CHECK_MV(x,y)
638                 }
639             }
640         }
641     }
642 #endif
643 //check(best[0],best[1],0, b0)
644     if(s->me_method==ME_EPZS)
645         dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, 
646                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, 
647                                    shift, map, score_map, map_generation, pix_abs16x16);
648     else
649         dmin=         cross_search(s, best, dmin, new_pic, old_pic, pic_stride, 
650                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, 
651                                    shift, map, score_map, map_generation, pix_abs16x16);
652 //check(best[0],best[1],0, b1)
653     *mx_ptr= best[0];
654     *my_ptr= best[1];    
655
656 //    printf("%d %d %d \n", best[0], best[1], dmin);
657     return dmin;
658 }
659
660 static int epzs_motion_search4(MpegEncContext * s, int block,
661                              int *mx_ptr, int *my_ptr,
662                              int P[10][2], int pred_x, int pred_y,
663                              int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture)
664 {
665     int best[2]={0, 0};
666     int d, dmin; 
667     UINT8 *new_pic, *old_pic;
668     const int pic_stride= s->linesize;
669     const int pic_xy= ((s->mb_y*2 + (block>>1))*pic_stride + s->mb_x*2 + (block&1))*8;
670     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
671     int quant= s->qscale; // qscale of the prev frame
672     const int shift= 1+s->quarter_sample;
673     uint32_t *map= s->me_map;
674     uint16_t *score_map= s->me_score_map;
675     int map_generation;
676
677     new_pic = s->new_picture[0] + pic_xy;
678     old_pic = ref_picture + pic_xy;
679
680     map_generation= update_map_generation(s);
681
682     dmin = 1000000;
683 //printf("%d %d %d %d //",xmin, ymin, xmax, ymax); 
684     /* first line */
685     if ((s->mb_y == 0 || s->first_slice_line) && block<2) {
686         CHECK_MV4(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
687         CHECK_MV4(P_LAST[0]>>shift, P_LAST[1]>>shift)
688         CHECK_MV4(P_MV1[0]>>shift, P_MV1[1]>>shift)
689     }else{
690         CHECK_MV4(P_MV1[0]>>shift, P_MV1[1]>>shift)
691         //FIXME try some early stop
692         if(dmin>64*2){
693             CHECK_MV4(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
694             CHECK_MV4(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
695             CHECK_MV4(P_TOP[0]>>shift, P_TOP[1]>>shift)
696             CHECK_MV4(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
697             CHECK_MV4(P_LAST[0]>>shift, P_LAST[1]>>shift)
698         }
699     }
700     if(dmin>64*4){
701         CHECK_MV4(P_LAST_RIGHT[0]>>shift, P_LAST_RIGHT[1]>>shift)
702         CHECK_MV4(P_LAST_BOTTOM[0]>>shift, P_LAST_BOTTOM[1]>>shift)
703     }
704
705     if(s->me_method==ME_EPZS)
706         dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, 
707                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, 
708                                    shift, map, score_map, map_generation, pix_abs8x8);
709     else
710         dmin=         cross_search(s, best, dmin, new_pic, old_pic, pic_stride, 
711                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, 
712                                    shift, map, score_map, map_generation, pix_abs8x8);
713
714     *mx_ptr= best[0];
715     *my_ptr= best[1];    
716
717 //    printf("%d %d %d \n", best[0], best[1], dmin);
718     return dmin;
719 }
720
721 #define CHECK_HALF_MV(suffix, x, y) \
722 {\
723     d= pix_abs_ ## suffix(pix, ptr+((x)>>1), s->linesize);\
724     d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\
725     COPY3_IF_LT(dminh, d, dx, x, dy, y)\
726 }
727
728     
729 /* The idea would be to make half pel ME after Inter/Intra decision to 
730    save time. */
731 static inline int halfpel_motion_search(MpegEncContext * s,
732                                   int *mx_ptr, int *my_ptr, int dmin,
733                                   int xmin, int ymin, int xmax, int ymax,
734                                   int pred_x, int pred_y, uint8_t *ref_picture,
735                                   op_pixels_abs_func pix_abs_x2, 
736                                   op_pixels_abs_func pix_abs_y2, op_pixels_abs_func pix_abs_xy2, int n)
737 {
738     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
739     const int quant= s->qscale;
740     int mx, my, xx, yy, dminh;
741     UINT8 *pix, *ptr;
742
743     if(s->skip_me){
744         *mx_ptr = 0;
745         *my_ptr = 0;
746         return dmin;
747     }else
748
749     xx = 16 * s->mb_x + 8*(n&1);
750     yy = 16 * s->mb_y + 8*(n>>1);
751     pix =  s->new_picture[0] + (yy * s->linesize) + xx;
752
753     mx = *mx_ptr;
754     my = *my_ptr;
755     ptr = ref_picture + ((yy + my) * s->linesize) + (xx + mx);
756     
757     dminh = dmin;
758
759     if (mx > xmin && mx < xmax && 
760         my > ymin && my < ymax) {
761         int dx=0, dy=0;
762         int d, pen_x, pen_y; 
763
764         mx<<=1;
765         my<<=1;
766         
767         pen_x= pred_x + mx;
768         pen_y= pred_y + my;
769
770         ptr-= s->linesize;
771         CHECK_HALF_MV(xy2, -1, -1)
772         CHECK_HALF_MV(y2 ,  0, -1)
773         CHECK_HALF_MV(xy2, +1, -1)
774         
775         ptr+= s->linesize;
776         CHECK_HALF_MV(x2 , -1,  0)
777         CHECK_HALF_MV(x2 , +1,  0)
778         CHECK_HALF_MV(xy2, -1, +1)
779         CHECK_HALF_MV(y2 ,  0, +1)
780         CHECK_HALF_MV(xy2, +1, +1)
781
782         mx+=dx;
783         my+=dy;
784     }else{
785         mx<<=1;
786         my<<=1;
787     }
788
789     *mx_ptr = mx;
790     *my_ptr = my;
791     return dminh;
792 }
793
794 static inline int fast_halfpel_motion_search(MpegEncContext * s,
795                                   int *mx_ptr, int *my_ptr, int dmin,
796                                   int xmin, int ymin, int xmax, int ymax,
797                                   int pred_x, int pred_y, uint8_t *ref_picture,
798                                   op_pixels_abs_func pix_abs_x2, 
799                                   op_pixels_abs_func pix_abs_y2, op_pixels_abs_func pix_abs_xy2, int n)
800 {
801     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
802     uint16_t *score_map= s->me_score_map;
803     const int quant= s->qscale;
804     int mx, my, xx, yy, dminh;
805     UINT8 *pix, *ptr;
806
807     if(s->skip_me){
808 //    printf("S");
809         *mx_ptr = 0;
810         *my_ptr = 0;
811         return dmin;
812     }
813 //    printf("N");
814         
815     xx = 16 * s->mb_x + 8*(n&1);
816     yy = 16 * s->mb_y + 8*(n>>1);
817     pix =  s->new_picture[0] + (yy * s->linesize) + xx;
818
819     mx = *mx_ptr;
820     my = *my_ptr;
821     ptr = ref_picture + ((yy + my) * s->linesize) + (xx + mx);
822     
823     dminh = dmin;
824
825     if (mx > xmin && mx < xmax && 
826         my > ymin && my < ymax) {
827         int dx=0, dy=0;
828         int d, pen_x, pen_y; 
829         const int index= (my<<ME_MAP_SHIFT) + mx;
830         const int t= score_map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)];
831         const int l= score_map[(index- 1               )&(ME_MAP_SIZE-1)];
832         const int r= score_map[(index+ 1               )&(ME_MAP_SIZE-1)];
833         const int b= score_map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)];
834         mx<<=1;
835         my<<=1;
836
837         
838         pen_x= pred_x + mx;
839         pen_y= pred_y + my;
840
841         ptr-= s->linesize;
842         if(t<=b){
843             CHECK_HALF_MV(y2 ,  0, -1)
844             if(l<=r){
845                 CHECK_HALF_MV(xy2, -1, -1)
846                 if(t+r<=b+l){
847                     CHECK_HALF_MV(xy2, +1, -1)
848                     ptr+= s->linesize;
849                 }else{
850                     ptr+= s->linesize;
851                     CHECK_HALF_MV(xy2, -1, +1)
852                 }
853                 CHECK_HALF_MV(x2 , -1,  0)
854             }else{
855                 CHECK_HALF_MV(xy2, +1, -1)
856                 if(t+l<=b+r){
857                     CHECK_HALF_MV(xy2, -1, -1)
858                     ptr+= s->linesize;
859                 }else{
860                     ptr+= s->linesize;
861                     CHECK_HALF_MV(xy2, +1, +1)
862                 }
863                 CHECK_HALF_MV(x2 , +1,  0)
864             }
865         }else{
866             if(l<=r){
867                 if(t+l<=b+r){
868                     CHECK_HALF_MV(xy2, -1, -1)
869                     ptr+= s->linesize;
870                 }else{
871                     ptr+= s->linesize;
872                     CHECK_HALF_MV(xy2, +1, +1)
873                 }
874                 CHECK_HALF_MV(x2 , -1,  0)
875                 CHECK_HALF_MV(xy2, -1, +1)
876             }else{
877                 if(t+r<=b+l){
878                     CHECK_HALF_MV(xy2, +1, -1)
879                     ptr+= s->linesize;
880                 }else{
881                     ptr+= s->linesize;
882                     CHECK_HALF_MV(xy2, -1, +1)
883                 }
884                 CHECK_HALF_MV(x2 , +1,  0)
885                 CHECK_HALF_MV(xy2, +1, +1)
886             }
887             CHECK_HALF_MV(y2 ,  0, +1)
888         }
889         mx+=dx;
890         my+=dy;
891
892     }else{
893         mx<<=1;
894         my<<=1;
895     }
896
897     *mx_ptr = mx;
898     *my_ptr = my;
899     return dminh;
900 }
901
902 static inline void set_p_mv_tables(MpegEncContext * s, int mx, int my, int mv4)
903 {
904     const int xy= s->mb_x + 1 + (s->mb_y + 1)*(s->mb_width + 2);
905     
906     s->p_mv_table[xy][0] = mx;
907     s->p_mv_table[xy][1] = my;
908
909     /* has allready been set to the 4 MV if 4MV is done */
910     if(mv4){
911         int mot_xy= s->block_index[0];
912
913         s->motion_val[mot_xy  ][0]= mx;
914         s->motion_val[mot_xy  ][1]= my;
915         s->motion_val[mot_xy+1][0]= mx;
916         s->motion_val[mot_xy+1][1]= my;
917
918         mot_xy += s->block_wrap[0];
919         s->motion_val[mot_xy  ][0]= mx;
920         s->motion_val[mot_xy  ][1]= my;
921         s->motion_val[mot_xy+1][0]= mx;
922         s->motion_val[mot_xy+1][1]= my;
923     }
924 }
925
926 static inline void get_limits(MpegEncContext *s, int *range, int *xmin, int *ymin, int *xmax, int *ymax, int f_code)
927 {
928     *range = 8 * (1 << (f_code - 1));
929     /* XXX: temporary kludge to avoid overflow for msmpeg4 */
930     if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
931         *range *= 2;
932
933     if (s->unrestricted_mv) {
934         *xmin = -16;
935         *ymin = -16;
936         if (s->h263_plus)
937             *range *= 2;
938         if(s->avctx==NULL || s->avctx->codec->id!=CODEC_ID_MPEG4){
939             *xmax = s->mb_width*16;
940             *ymax = s->mb_height*16;
941         }else {
942             /* XXX: dunno if this is correct but ffmpeg4 decoder wont like it otherwise 
943                     (cuz the drawn edge isnt large enough))*/
944             *xmax = s->width;
945             *ymax = s->height;
946         }
947     } else {
948         *xmin = 0;
949         *ymin = 0;
950         *xmax = s->mb_width*16 - 16;
951         *ymax = s->mb_height*16 - 16;
952     }
953 }
954
955 static inline int mv4_search(MpegEncContext *s, int xmin, int ymin, int xmax, int ymax, int mx, int my, int shift)
956 {
957     int block;
958     int P[10][2];
959     uint8_t *ref_picture= s->last_picture[0];
960     int dmin_sum=0;
961
962     for(block=0; block<4; block++){
963         int mx4, my4;
964         int pred_x4, pred_y4;
965         int dmin4;
966         static const int off[4]= {2, 1, 1, -1};
967         const int mot_stride = s->block_wrap[0];
968         const int mot_xy = s->block_index[block];
969 //        const int block_x= (block&1);
970 //        const int block_y= (block>>1);
971 #if 1 // this saves us a bit of cliping work and shouldnt affect compression in a negative way
972         const int rel_xmin4= xmin;
973         const int rel_xmax4= xmax;
974         const int rel_ymin4= ymin;
975         const int rel_ymax4= ymax;
976 #else
977         const int rel_xmin4= xmin - block_x*8;
978         const int rel_xmax4= xmax - block_x*8 + 8;
979         const int rel_ymin4= ymin - block_y*8;
980         const int rel_ymax4= ymax - block_y*8 + 8;
981 #endif
982         P_LAST[0] = s->motion_val[mot_xy    ][0];
983         P_LAST[1] = s->motion_val[mot_xy    ][1];
984         P_LEFT[0] = s->motion_val[mot_xy - 1][0];
985         P_LEFT[1] = s->motion_val[mot_xy - 1][1];
986         P_LAST_RIGHT[0] = s->motion_val[mot_xy + 1][0];
987         P_LAST_RIGHT[1] = s->motion_val[mot_xy + 1][1];
988         P_LAST_BOTTOM[0]= s->motion_val[mot_xy + 1*mot_stride][0];
989         P_LAST_BOTTOM[1]= s->motion_val[mot_xy + 1*mot_stride][1];
990
991         if(P_LEFT[0]       > (rel_xmax4<<shift)) P_LEFT[0]       = (rel_xmax4<<shift);
992         if(P_LAST_RIGHT[0] < (rel_xmin4<<shift)) P_LAST_RIGHT[0] = (rel_xmin4<<shift);
993         if(P_LAST_BOTTOM[1]< (rel_ymin4<<shift)) P_LAST_BOTTOM[1]= (rel_ymin4<<shift);
994
995         /* special case for first line */
996         if ((s->mb_y == 0 || s->first_slice_line) && block<2) {
997             pred_x4= P_LEFT[0];
998             pred_y4= P_LEFT[1];
999         } else {
1000             P_TOP[0]      = s->motion_val[mot_xy - mot_stride             ][0];
1001             P_TOP[1]      = s->motion_val[mot_xy - mot_stride             ][1];
1002             P_TOPRIGHT[0] = s->motion_val[mot_xy - mot_stride + off[block]][0];
1003             P_TOPRIGHT[1] = s->motion_val[mot_xy - mot_stride + off[block]][1];
1004             if(P_TOP[1]      > (rel_ymax4<<shift)) P_TOP[1]     = (rel_ymax4<<shift);
1005             if(P_TOPRIGHT[0] < (rel_xmin4<<shift)) P_TOPRIGHT[0]= (rel_xmin4<<shift);
1006             if(P_TOPRIGHT[0] > (rel_xmax4<<shift)) P_TOPRIGHT[0]= (rel_xmax4<<shift);
1007             if(P_TOPRIGHT[1] > (rel_ymax4<<shift)) P_TOPRIGHT[1]= (rel_ymax4<<shift);
1008     
1009             P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
1010             P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
1011
1012             if(s->out_format == FMT_H263){
1013                 pred_x4 = P_MEDIAN[0];
1014                 pred_y4 = P_MEDIAN[1];
1015             }else { /* mpeg1 at least */
1016                 pred_x4= P_LEFT[0];
1017                 pred_y4= P_LEFT[1];
1018             }
1019         }
1020         P_MV1[0]= mx;
1021         P_MV1[1]= my;
1022
1023         dmin4 = epzs_motion_search4(s, block, &mx4, &my4, P, pred_x4, pred_y4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4, ref_picture);
1024
1025         dmin4= fast_halfpel_motion_search(s, &mx4, &my4, dmin4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4, 
1026                                    pred_x4, pred_y4, ref_picture, pix_abs8x8_x2, 
1027                                    pix_abs8x8_y2, pix_abs8x8_xy2, block);
1028  
1029         s->motion_val[ s->block_index[block] ][0]= mx4;
1030         s->motion_val[ s->block_index[block] ][1]= my4;
1031         dmin_sum+= dmin4;
1032     }
1033     return dmin_sum;
1034 }
1035
1036 void ff_estimate_p_frame_motion(MpegEncContext * s,
1037                                 int mb_x, int mb_y)
1038 {
1039     UINT8 *pix, *ppix;
1040     int sum, varc, vard, mx, my, range, dmin, xx, yy;
1041     int xmin, ymin, xmax, ymax;
1042     int rel_xmin, rel_ymin, rel_xmax, rel_ymax;
1043     int pred_x=0, pred_y=0;
1044     int P[10][2];
1045     const int shift= 1+s->quarter_sample;
1046     int mb_type=0;
1047     uint8_t *ref_picture= s->last_picture[0];
1048
1049     get_limits(s, &range, &xmin, &ymin, &xmax, &ymax, s->f_code);
1050     rel_xmin= xmin - mb_x*16;
1051     rel_xmax= xmax - mb_x*16;
1052     rel_ymin= ymin - mb_y*16;
1053     rel_ymax= ymax - mb_y*16;
1054     s->skip_me=0;
1055
1056     switch(s->me_method) {
1057     case ME_ZERO:
1058     default:
1059         no_motion_search(s, &mx, &my);
1060         mx-= mb_x*16;
1061         my-= mb_y*16;
1062         dmin = 0;
1063         break;
1064     case ME_FULL:
1065         dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax, ref_picture);
1066         mx-= mb_x*16;
1067         my-= mb_y*16;
1068         break;
1069     case ME_LOG:
1070         dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax, ref_picture);
1071         mx-= mb_x*16;
1072         my-= mb_y*16;
1073         break;
1074     case ME_PHODS:
1075         dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax, ref_picture);
1076         mx-= mb_x*16;
1077         my-= mb_y*16;
1078         break;
1079     case ME_X1:
1080     case ME_EPZS:
1081        {
1082             const int mot_stride = s->block_wrap[0];
1083             const int mot_xy = s->block_index[0];
1084
1085             P_LAST[0]       = s->motion_val[mot_xy    ][0];
1086             P_LAST[1]       = s->motion_val[mot_xy    ][1];
1087             P_LEFT[0]       = s->motion_val[mot_xy - 1][0];
1088             P_LEFT[1]       = s->motion_val[mot_xy - 1][1];
1089             P_LAST_RIGHT[0] = s->motion_val[mot_xy + 2][0];
1090             P_LAST_RIGHT[1] = s->motion_val[mot_xy + 2][1];
1091             P_LAST_BOTTOM[0]= s->motion_val[mot_xy + 2*mot_stride][0];
1092             P_LAST_BOTTOM[1]= s->motion_val[mot_xy + 2*mot_stride][1];
1093
1094             if(P_LEFT[0]       > (rel_xmax<<shift)) P_LEFT[0]       = (rel_xmax<<shift);
1095             if(P_LAST_RIGHT[0] < (rel_xmin<<shift)) P_LAST_RIGHT[0] = (rel_xmin<<shift);
1096             if(P_LAST_BOTTOM[1]< (rel_ymin<<shift)) P_LAST_BOTTOM[1]= (rel_ymin<<shift);
1097
1098             /* special case for first line */
1099             if ((mb_y == 0 || s->first_slice_line)) {
1100                 pred_x= P_LEFT[0];
1101                 pred_y= P_LEFT[1];
1102             } else {
1103                 P_TOP[0]      = s->motion_val[mot_xy - mot_stride    ][0];
1104                 P_TOP[1]      = s->motion_val[mot_xy - mot_stride    ][1];
1105                 P_TOPRIGHT[0] = s->motion_val[mot_xy - mot_stride + 2][0];
1106                 P_TOPRIGHT[1] = s->motion_val[mot_xy - mot_stride + 2][1];
1107                 if(P_TOP[1]      > (rel_ymax<<shift)) P_TOP[1]     = (rel_ymax<<shift);
1108                 if(P_TOPRIGHT[0] < (rel_xmin<<shift)) P_TOPRIGHT[0]= (rel_xmin<<shift);
1109                 if(P_TOPRIGHT[1] > (rel_ymax<<shift)) P_TOPRIGHT[1]= (rel_ymax<<shift);
1110         
1111                 P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
1112                 P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
1113
1114                 if(s->out_format == FMT_H263){
1115                     pred_x = P_MEDIAN[0];
1116                     pred_y = P_MEDIAN[1];
1117                 }else { /* mpeg1 at least */
1118                     pred_x= P_LEFT[0];
1119                     pred_y= P_LEFT[1];
1120                 }
1121             }
1122         }
1123         dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax, ref_picture);
1124  
1125         break;
1126     }
1127
1128     /* intra / predictive decision */
1129     xx = mb_x * 16;
1130     yy = mb_y * 16;
1131
1132     pix = s->new_picture[0] + (yy * s->linesize) + xx;
1133     /* At this point (mx,my) are full-pell and the relative displacement */
1134     ppix = ref_picture + ((yy+my) * s->linesize) + (xx+mx);
1135     
1136     sum = pix_sum(pix, s->linesize);
1137     
1138     sum= (sum+8)>>4;
1139     varc = (pix_norm1(pix, s->linesize) - sum*sum + 500 + 128)>>8;
1140     vard = (pix_norm(pix, ppix, s->linesize)+128)>>8;
1141
1142 //printf("%d %d %d %X %X %X\n", s->mb_width, mb_x, mb_y,(int)s, (int)s->mb_var, (int)s->mc_mb_var); fflush(stdout);
1143     s->mb_var   [s->mb_width * mb_y + mb_x] = varc;
1144     s->mc_mb_var[s->mb_width * mb_y + mb_x] = vard;
1145     s->mb_mean  [s->mb_width * mb_y + mb_x] = (sum+7)>>4;
1146     s->mb_var_sum    += varc;
1147     s->mc_mb_var_sum += vard;
1148 //printf("E%d %d %d %X %X %X\n", s->mb_width, mb_x, mb_y,(int)s, (int)s->mb_var, (int)s->mc_mb_var); fflush(stdout);
1149     
1150 #if 0
1151     printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n",
1152            varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
1153 #endif
1154     if(s->flags&CODEC_FLAG_HQ){
1155         if (vard <= 64 || vard < varc)
1156             s->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
1157         else
1158             s->scene_change_score+= 20;
1159
1160         if (vard*2 + 200 > varc)
1161             mb_type|= MB_TYPE_INTRA;
1162         if (varc*2 + 200 > vard){
1163             mb_type|= MB_TYPE_INTER;
1164             if(s->me_method >= ME_EPZS)
1165                 fast_halfpel_motion_search(s, &mx, &my, dmin, rel_xmin, rel_ymin, rel_xmax, rel_ymax, 
1166                                            pred_x, pred_y, ref_picture, pix_abs16x16_x2, pix_abs16x16_y2, 
1167                                            pix_abs16x16_xy2, 0);
1168             else
1169                 halfpel_motion_search(     s, &mx, &my, dmin, rel_xmin, rel_ymin, rel_xmax, rel_ymax, 
1170                                            pred_x, pred_y, ref_picture, pix_abs16x16_x2, pix_abs16x16_y2, 
1171                                            pix_abs16x16_xy2, 0);                                           
1172         }else{
1173             mx <<=1;
1174             my <<=1;
1175         }
1176         if((s->flags&CODEC_FLAG_4MV)
1177            && !s->skip_me && varc>50 && vard>10){
1178             mv4_search(s, rel_xmin, rel_ymin, rel_xmax, rel_ymax, mx, my, shift);
1179             mb_type|=MB_TYPE_INTER4V;
1180
1181             set_p_mv_tables(s, mx, my, 0);
1182         }else
1183             set_p_mv_tables(s, mx, my, 1);
1184     }else{
1185         if (vard <= 64 || vard < varc) {
1186             s->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
1187             mb_type|= MB_TYPE_INTER;
1188             if (s->me_method != ME_ZERO) {
1189                 if(s->me_method >= ME_EPZS)
1190                     dmin= fast_halfpel_motion_search(s, &mx, &my, dmin, rel_xmin, rel_ymin, rel_xmax, rel_ymax, 
1191                                            pred_x, pred_y, ref_picture, pix_abs16x16_x2, pix_abs16x16_y2, 
1192                                            pix_abs16x16_xy2, 0);
1193                 else
1194                     dmin= halfpel_motion_search(s, &mx, &my, dmin, rel_xmin, rel_ymin, rel_xmax, rel_ymax, 
1195                                            pred_x, pred_y, ref_picture, pix_abs16x16_x2, pix_abs16x16_y2, 
1196                                            pix_abs16x16_xy2, 0);
1197                 if((s->flags&CODEC_FLAG_4MV)
1198                    && !s->skip_me && varc>50 && vard>10){
1199                     int dmin4= mv4_search(s, rel_xmin, rel_ymin, rel_xmax, rel_ymax, mx, my, shift);
1200                     if(dmin4 + 128 <dmin)
1201                         mb_type= MB_TYPE_INTER4V;
1202                 }
1203                 set_p_mv_tables(s, mx, my, mb_type!=MB_TYPE_INTER4V);
1204
1205             } else {
1206                 mx <<=1;
1207                 my <<=1;
1208             }
1209 #if 0
1210             if (vard < 10) {
1211                 skip++;
1212                 fprintf(stderr,"\nEarly skip: %d vard: %2d varc: %5d dmin: %d", 
1213                                 skip, vard, varc, dmin);
1214             }
1215 #endif
1216         }else{
1217             s->scene_change_score+= 20;
1218             mb_type|= MB_TYPE_INTRA;
1219             mx = 0;
1220             my = 0;
1221         }
1222     }
1223
1224     s->mb_type[mb_y*s->mb_width + mb_x]= mb_type;
1225 }
1226
1227 int ff_estimate_motion_b(MpegEncContext * s,
1228                        int mb_x, int mb_y, int16_t (*mv_table)[2], uint8_t *ref_picture, int f_code)
1229 {
1230     int mx, my, range, dmin;
1231     int xmin, ymin, xmax, ymax;
1232     int rel_xmin, rel_ymin, rel_xmax, rel_ymax;
1233     int pred_x=0, pred_y=0;
1234     int P[10][2];
1235     const int shift= 1+s->quarter_sample;
1236     const int mot_stride = s->mb_width + 2;
1237     const int mot_xy = (mb_y + 1)*mot_stride + mb_x + 1;
1238     
1239     get_limits(s, &range, &xmin, &ymin, &xmax, &ymax, f_code);
1240     rel_xmin= xmin - mb_x*16;
1241     rel_xmax= xmax - mb_x*16;
1242     rel_ymin= ymin - mb_y*16;
1243     rel_ymax= ymax - mb_y*16;
1244
1245     switch(s->me_method) {
1246     case ME_ZERO:
1247     default:
1248         no_motion_search(s, &mx, &my);
1249         dmin = 0;
1250         mx-= mb_x*16;
1251         my-= mb_y*16;
1252         break;
1253     case ME_FULL:
1254         dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax, ref_picture);
1255         mx-= mb_x*16;
1256         my-= mb_y*16;
1257         break;
1258     case ME_LOG:
1259         dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax, ref_picture);
1260         mx-= mb_x*16;
1261         my-= mb_y*16;
1262         break;
1263     case ME_PHODS:
1264         dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax, ref_picture);
1265         mx-= mb_x*16;
1266         my-= mb_y*16;
1267         break;
1268     case ME_X1:
1269     case ME_EPZS:
1270        {
1271
1272             P_LAST[0]        = mv_table[mot_xy    ][0];
1273             P_LAST[1]        = mv_table[mot_xy    ][1];
1274             P_LEFT[0]        = mv_table[mot_xy - 1][0];
1275             P_LEFT[1]        = mv_table[mot_xy - 1][1];
1276             P_LAST_RIGHT[0]  = mv_table[mot_xy + 1][0];
1277             P_LAST_RIGHT[1]  = mv_table[mot_xy + 1][1];
1278             P_LAST_BOTTOM[0] = mv_table[mot_xy + mot_stride][0];
1279             P_LAST_BOTTOM[1] = mv_table[mot_xy + mot_stride][1];
1280
1281             if(P_LEFT[0]       > (rel_xmax<<shift)) P_LEFT[0]       = (rel_xmax<<shift);
1282             if(P_LAST_RIGHT[0] < (rel_xmin<<shift)) P_LAST_RIGHT[0] = (rel_xmin<<shift);
1283             if(P_LAST_BOTTOM[1]< (rel_ymin<<shift)) P_LAST_BOTTOM[1]= (rel_ymin<<shift);
1284
1285             /* special case for first line */
1286             if ((mb_y == 0 || s->first_slice_line)) {
1287             } else {
1288                 P_TOP[0] = mv_table[mot_xy - mot_stride             ][0];
1289                 P_TOP[1] = mv_table[mot_xy - mot_stride             ][1];
1290                 P_TOPRIGHT[0] = mv_table[mot_xy - mot_stride + 1         ][0];
1291                 P_TOPRIGHT[1] = mv_table[mot_xy - mot_stride + 1         ][1];
1292                 if(P_TOP[1] > (rel_ymax<<shift)) P_TOP[1]= (rel_ymax<<shift);
1293                 if(P_TOPRIGHT[0] < (rel_xmin<<shift)) P_TOPRIGHT[0]= (rel_xmin<<shift);
1294                 if(P_TOPRIGHT[1] > (rel_ymax<<shift)) P_TOPRIGHT[1]= (rel_ymax<<shift);
1295         
1296                 P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
1297                 P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
1298             }
1299             pred_x= P_LEFT[0];
1300             pred_y= P_LEFT[1];
1301         }
1302         dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax, ref_picture);
1303  
1304         break;
1305     }
1306     
1307     dmin= fast_halfpel_motion_search(s, &mx, &my, dmin, rel_xmin, rel_ymin, rel_xmax, rel_ymax, 
1308                                 pred_x, pred_y, ref_picture, pix_abs16x16_x2, pix_abs16x16_y2, 
1309                                 pix_abs16x16_xy2, 0);
1310 //printf("%d %d %d %d//", s->mb_x, s->mb_y, mx, my);
1311 //    s->mb_type[mb_y*s->mb_width + mb_x]= mb_type;
1312     mv_table[mot_xy][0]= mx;
1313     mv_table[mot_xy][1]= my;
1314     return dmin;
1315 }
1316
1317
1318 static inline int check_bidir_mv(MpegEncContext * s,
1319                    int mb_x, int mb_y,
1320                    int motion_fx, int motion_fy,
1321                    int motion_bx, int motion_by,
1322                    int pred_fx, int pred_fy,
1323                    int pred_bx, int pred_by)
1324 {
1325     //FIXME optimize?
1326     //FIXME direct mode penalty
1327     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
1328     uint8_t *dest_y = s->me_scratchpad;
1329     uint8_t *ptr;
1330     int dxy;
1331     int src_x, src_y;
1332     int fbmin;
1333
1334     fbmin = (mv_penalty[motion_fx-pred_fx] + mv_penalty[motion_fy-pred_fy])*s->qscale;
1335
1336     dxy = ((motion_fy & 1) << 1) | (motion_fx & 1);
1337     src_x = mb_x * 16 + (motion_fx >> 1);
1338     src_y = mb_y * 16 + (motion_fy >> 1);
1339             
1340     ptr = s->last_picture[0] + (src_y * s->linesize) + src_x;
1341     put_pixels_tab[0][dxy](dest_y    , ptr    , s->linesize, 16);
1342     
1343     fbmin += (mv_penalty[motion_bx-pred_bx] + mv_penalty[motion_by-pred_by])*s->qscale;
1344
1345     dxy = ((motion_by & 1) << 1) | (motion_bx & 1);
1346     src_x = mb_x * 16 + (motion_bx >> 1);
1347     src_y = mb_y * 16 + (motion_by >> 1);
1348             
1349     ptr = s->next_picture[0] + (src_y * s->linesize) + src_x;
1350     avg_pixels_tab[0][dxy](dest_y    , ptr    , s->linesize, 16);
1351     
1352     fbmin += pix_abs16x16(s->new_picture[0] + mb_x*16 + mb_y*16*s->linesize, dest_y, s->linesize);
1353     return fbmin;
1354 }
1355
1356 /* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/
1357 static inline int bidir_refine(MpegEncContext * s,
1358                                   int mb_x, int mb_y)
1359 {
1360     const int mot_stride = s->mb_width + 2;
1361     const int xy = (mb_y + 1)*mot_stride + mb_x + 1;
1362     int fbmin;
1363     int pred_fx= s->b_bidir_forw_mv_table[xy-1][0];
1364     int pred_fy= s->b_bidir_forw_mv_table[xy-1][1];
1365     int pred_bx= s->b_bidir_back_mv_table[xy-1][0];
1366     int pred_by= s->b_bidir_back_mv_table[xy-1][1];
1367     int motion_fx= s->b_bidir_forw_mv_table[xy][0]= s->b_forw_mv_table[xy][0];
1368     int motion_fy= s->b_bidir_forw_mv_table[xy][1]= s->b_forw_mv_table[xy][1];
1369     int motion_bx= s->b_bidir_back_mv_table[xy][0]= s->b_back_mv_table[xy][0];
1370     int motion_by= s->b_bidir_back_mv_table[xy][1]= s->b_back_mv_table[xy][1];
1371
1372     //FIXME do refinement and add flag
1373     
1374     fbmin= check_bidir_mv(s, mb_x, mb_y, 
1375                           motion_fx, motion_fy,
1376                           motion_bx, motion_by,
1377                           pred_fx, pred_fy,
1378                           pred_bx, pred_by);
1379
1380    return fbmin;
1381 }
1382
1383 static inline int direct_search(MpegEncContext * s,
1384                                 int mb_x, int mb_y)
1385 {
1386     int P[10][2];
1387     const int mot_stride = s->mb_width + 2;
1388     const int mot_xy = (mb_y + 1)*mot_stride + mb_x + 1;
1389     int dmin, dmin2;
1390     int motion_fx, motion_fy, motion_bx, motion_by, motion_bx0, motion_by0;
1391     int motion_dx, motion_dy;
1392     const int motion_px= s->p_mv_table[mot_xy][0];
1393     const int motion_py= s->p_mv_table[mot_xy][1];
1394     const int time_pp= s->pp_time;
1395     const int time_pb= s->pb_time;
1396     const int time_bp= time_pp - time_pb;
1397     int bx, by;
1398     int mx, my, mx2, my2;
1399     uint8_t *ref_picture= s->me_scratchpad - (mb_x - 1 + (mb_y - 1)*s->linesize)*16;
1400     int16_t (*mv_table)[2]= s->b_direct_mv_table;
1401 /*    uint16_t *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; */ // f_code of the prev frame
1402
1403     /* thanks to iso-mpeg the rounding is different for the zero vector, so we need to handle that ... */
1404     motion_fx= (motion_px*time_pb)/time_pp;
1405     motion_fy= (motion_py*time_pb)/time_pp;
1406     motion_bx0= (-motion_px*time_bp)/time_pp;
1407     motion_by0= (-motion_py*time_bp)/time_pp;
1408     motion_dx= motion_dy=0;
1409     dmin2= check_bidir_mv(s, mb_x, mb_y, 
1410                           motion_fx, motion_fy,
1411                           motion_bx0, motion_by0,
1412                           motion_fx, motion_fy,
1413                           motion_bx0, motion_by0) - s->qscale;
1414
1415     motion_bx= motion_fx - motion_px;
1416     motion_by= motion_fy - motion_py;
1417     for(by=-1; by<2; by++){
1418         for(bx=-1; bx<2; bx++){
1419             uint8_t *dest_y = s->me_scratchpad + (by+1)*s->linesize*16 + (bx+1)*16;
1420             uint8_t *ptr;
1421             int dxy;
1422             int src_x, src_y;
1423             const int width= s->width;
1424             const int height= s->height;
1425
1426             dxy = ((motion_fy & 1) << 1) | (motion_fx & 1);
1427             src_x = (mb_x + bx) * 16 + (motion_fx >> 1);
1428             src_y = (mb_y + by) * 16 + (motion_fy >> 1);
1429             src_x = clip(src_x, -16, width);
1430             if (src_x == width) dxy &= ~1;
1431             src_y = clip(src_y, -16, height);
1432             if (src_y == height) dxy &= ~2;
1433
1434             ptr = s->last_picture[0] + (src_y * s->linesize) + src_x;
1435             put_pixels_tab[0][dxy](dest_y    , ptr    , s->linesize, 16);
1436
1437             dxy = ((motion_by & 1) << 1) | (motion_bx & 1);
1438             src_x = (mb_x + bx) * 16 + (motion_bx >> 1);
1439             src_y = (mb_y + by) * 16 + (motion_by >> 1);
1440             src_x = clip(src_x, -16, width);
1441             if (src_x == width) dxy &= ~1;
1442             src_y = clip(src_y, -16, height);
1443             if (src_y == height) dxy &= ~2;
1444
1445             avg_pixels_tab[0][dxy](dest_y    , ptr    , s->linesize, 16);
1446         }
1447     }
1448
1449     P_LAST[0]        = mv_table[mot_xy    ][0];
1450     P_LAST[1]        = mv_table[mot_xy    ][1];
1451     P_LEFT[0]        = mv_table[mot_xy - 1][0];
1452     P_LEFT[1]        = mv_table[mot_xy - 1][1];
1453     P_LAST_RIGHT[0]  = mv_table[mot_xy + 1][0];
1454     P_LAST_RIGHT[1]  = mv_table[mot_xy + 1][1];
1455     P_LAST_BOTTOM[0] = mv_table[mot_xy + mot_stride][0];
1456     P_LAST_BOTTOM[1] = mv_table[mot_xy + mot_stride][1];
1457 /*
1458     if(P_LEFT[0]       > (rel_xmax<<shift)) P_LEFT[0]       = (rel_xmax<<shift);
1459     if(P_LAST_RIGHT[0] < (rel_xmin<<shift)) P_LAST_RIGHT[0] = (rel_xmin<<shift);
1460     if(P_LAST_BOTTOM[1]< (rel_ymin<<shift)) P_LAST_BOTTOM[1]= (rel_ymin<<shift);
1461 */
1462     /* special case for first line */
1463     if ((mb_y == 0 || s->first_slice_line)) {
1464     } else {
1465         P_TOP[0] = mv_table[mot_xy - mot_stride             ][0];
1466         P_TOP[1] = mv_table[mot_xy - mot_stride             ][1];
1467         P_TOPRIGHT[0] = mv_table[mot_xy - mot_stride + 1         ][0];
1468         P_TOPRIGHT[1] = mv_table[mot_xy - mot_stride + 1         ][1];
1469     
1470         P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
1471         P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
1472     }
1473     dmin = epzs_motion_search(s, &mx, &my, P, 0, 0, -16, -16, 15, 15, ref_picture);
1474     if(mx==0 && my==0) dmin=99999999; // not representable, due to rounding stuff
1475     if(dmin2<dmin){ 
1476         dmin= dmin2;
1477         mx=0;
1478         my=0;
1479     }
1480 #if 1
1481     mx2= mx= mx*2; 
1482     my2= my= my*2;
1483     for(by=-1; by<2; by++){
1484         if(my2+by < -32) continue;
1485         for(bx=-1; bx<2; bx++){
1486             if(bx==0 && by==0) continue;
1487             if(mx2+bx < -32) continue;
1488             dmin2= check_bidir_mv(s, mb_x, mb_y, 
1489                           mx2+bx+motion_fx, my2+by+motion_fy,
1490                           mx2+bx+motion_bx, my2+by+motion_by,
1491                           mx2+bx+motion_fx, my2+by+motion_fy,
1492                           motion_bx, motion_by) - s->qscale;
1493             
1494             if(dmin2<dmin){
1495                 dmin=dmin2;
1496                 mx= mx2 + bx;
1497                 my= my2 + by;
1498             }
1499         }
1500     }
1501 #else
1502     mx*=2; my*=2;
1503 #endif
1504     if(mx==0 && my==0){
1505         motion_bx= motion_bx0;
1506         motion_by= motion_by0;
1507     }
1508
1509     s->b_direct_mv_table[mot_xy][0]= mx;
1510     s->b_direct_mv_table[mot_xy][1]= my;
1511     s->b_direct_forw_mv_table[mot_xy][0]= motion_fx + mx;
1512     s->b_direct_forw_mv_table[mot_xy][1]= motion_fy + my;
1513     s->b_direct_back_mv_table[mot_xy][0]= motion_bx + mx;
1514     s->b_direct_back_mv_table[mot_xy][1]= motion_by + my;
1515     return dmin;
1516 }
1517
1518 void ff_estimate_b_frame_motion(MpegEncContext * s,
1519                              int mb_x, int mb_y)
1520 {
1521     const int quant= s->qscale;
1522     int fmin, bmin, dmin, fbmin;
1523     int type=0;
1524     
1525     dmin= direct_search(s, mb_x, mb_y);
1526
1527     fmin= ff_estimate_motion_b(s, mb_x, mb_y, s->b_forw_mv_table, s->last_picture[0], s->f_code);
1528     bmin= ff_estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, s->next_picture[0], s->b_code) - quant;
1529 //printf(" %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]);
1530
1531     fbmin= bidir_refine(s, mb_x, mb_y);
1532
1533     {
1534         int score= dmin;
1535         type=MB_TYPE_DIRECT;
1536         
1537         if(fmin<score){
1538             score=fmin;
1539             type= MB_TYPE_FORWARD; 
1540         }
1541         if(bmin<score){
1542             score=bmin;
1543             type= MB_TYPE_BACKWARD; 
1544         }
1545         if(fbmin<score){
1546             score=fbmin;
1547             type= MB_TYPE_BIDIR;
1548         }
1549         score= (score*score)>>8;
1550         s->mc_mb_var_sum += score;
1551         s->mc_mb_var[mb_y*s->mb_width + mb_x] = score; //FIXME use SSD
1552     }
1553
1554     if(s->flags&CODEC_FLAG_HQ){
1555         type= MB_TYPE_FORWARD | MB_TYPE_BACKWARD | MB_TYPE_BIDIR | MB_TYPE_DIRECT; //FIXME something smarter
1556     }
1557
1558 /*
1559 {
1560 static int count=0;
1561 static int sum=0;
1562 if(type==MB_TYPE_DIRECT){
1563   int diff= ABS(s->b_forw_mv_table)
1564 }
1565 }*/
1566
1567     s->mb_type[mb_y*s->mb_width + mb_x]= type;
1568 /*    if(mb_y==0 && mb_x==0) printf("\n");
1569     if(mb_x==0) printf("\n");
1570     printf("%d", av_log2(type));
1571 */
1572 }
1573
1574 /* find best f_code for ME which do unlimited searches */
1575 int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type)
1576 {
1577     if(s->me_method>=ME_EPZS){
1578         int score[8];
1579         int i, y;
1580         UINT8 * fcode_tab= s->fcode_tab;
1581         int best_fcode=-1;
1582         int best_score=-10000000;
1583
1584         for(i=0; i<8; i++) score[i]= s->mb_num*(8-i); //FIXME *2 and all other too so its the same but nicer
1585
1586         for(y=0; y<s->mb_height; y++){
1587             int x;
1588             int xy= (y+1)* (s->mb_width+2) + 1;
1589             i= y*s->mb_width;
1590             for(x=0; x<s->mb_width; x++){
1591                 if(s->mb_type[i] & type){
1592                     int fcode= MAX(fcode_tab[mv_table[xy][0] + MAX_MV],
1593                                    fcode_tab[mv_table[xy][1] + MAX_MV]);
1594                     int j;
1595                     
1596                     for(j=0; j<fcode && j<8; j++){
1597                         if(s->pict_type==B_TYPE || s->mc_mb_var[i] < s->mb_var[i])
1598                             score[j]-= 170;
1599                     }
1600                 }
1601                 i++;
1602                 xy++;
1603             }
1604         }
1605         
1606         for(i=1; i<8; i++){
1607             if(score[i] > best_score){
1608                 best_score= score[i];
1609                 best_fcode= i;
1610             }
1611 //            printf("%d %d\n", i, score[i]);
1612         }
1613
1614 //    printf("fcode: %d type: %d\n", i, s->pict_type);
1615         return best_fcode;
1616 /*        for(i=0; i<=MAX_FCODE; i++){
1617             printf("%d ", mv_num[i]);
1618         }
1619         printf("\n");*/
1620     }else{
1621         return 1;
1622     }
1623 }
1624
1625 void ff_fix_long_p_mvs(MpegEncContext * s)
1626 {
1627     const int f_code= s->f_code;
1628     int y;
1629     UINT8 * fcode_tab= s->fcode_tab;
1630 //int clip=0;
1631 //int noclip=0;
1632     /* clip / convert to intra 16x16 type MVs */
1633     for(y=0; y<s->mb_height; y++){
1634         int x;
1635         int xy= (y+1)* (s->mb_width+2)+1;
1636         int i= y*s->mb_width;
1637         for(x=0; x<s->mb_width; x++){
1638             if(s->mb_type[i]&MB_TYPE_INTER){
1639                 if(   fcode_tab[s->p_mv_table[xy][0] + MAX_MV] > f_code
1640                    || fcode_tab[s->p_mv_table[xy][0] + MAX_MV] == 0
1641                    || fcode_tab[s->p_mv_table[xy][1] + MAX_MV] > f_code
1642                    || fcode_tab[s->p_mv_table[xy][1] + MAX_MV] == 0 ){
1643                     s->mb_type[i] &= ~MB_TYPE_INTER;
1644                     s->mb_type[i] |= MB_TYPE_INTRA;
1645                     s->p_mv_table[xy][0] = 0;
1646                     s->p_mv_table[xy][1] = 0;
1647 //clip++;
1648                 }
1649 //else
1650 //  noclip++;
1651             }
1652             xy++;
1653             i++;
1654         }
1655     }
1656 //printf("%d no:%d %d//\n", clip, noclip, f_code);
1657     if(s->flags&CODEC_FLAG_4MV){
1658         const int wrap= 2+ s->mb_width*2;
1659
1660         /* clip / convert to intra 8x8 type MVs */
1661         for(y=0; y<s->mb_height; y++){
1662             int xy= (y*2 + 1)*wrap + 1;
1663             int i= y*s->mb_width;
1664             int x;
1665
1666             for(x=0; x<s->mb_width; x++){
1667                 if(s->mb_type[i]&MB_TYPE_INTER4V){
1668                     int block;
1669                     for(block=0; block<4; block++){
1670                         int off= (block& 1) + (block>>1)*wrap;
1671                         int mx= s->motion_val[ xy + off ][0];
1672                         int my= s->motion_val[ xy + off ][1];
1673
1674                         if(   fcode_tab[mx + MAX_MV] > f_code
1675                            || fcode_tab[mx + MAX_MV] == 0
1676                            || fcode_tab[my + MAX_MV] > f_code
1677                            || fcode_tab[my + MAX_MV] == 0 ){
1678                             s->mb_type[i] &= ~MB_TYPE_INTER4V;
1679                             s->mb_type[i] |= MB_TYPE_INTRA;
1680                         }
1681                     }
1682                 }
1683                 xy+=2;
1684                 i++;
1685             }
1686         }
1687     }
1688 }
1689
1690 void ff_fix_long_b_mvs(MpegEncContext * s, int16_t (*mv_table)[2], int f_code, int type)
1691 {
1692     int y;
1693     UINT8 * fcode_tab= s->fcode_tab;
1694
1695     /* clip / convert to intra 16x16 type MVs */
1696     for(y=0; y<s->mb_height; y++){
1697         int x;
1698         int xy= (y+1)* (s->mb_width+2)+1;
1699         int i= y*s->mb_width;
1700         for(x=0; x<s->mb_width; x++){
1701             if(s->mb_type[i]&type){
1702                 if(   fcode_tab[mv_table[xy][0] + MAX_MV] > f_code
1703                    || fcode_tab[mv_table[xy][0] + MAX_MV] == 0
1704                    || fcode_tab[mv_table[xy][1] + MAX_MV] > f_code
1705                    || fcode_tab[mv_table[xy][1] + MAX_MV] == 0 ){
1706                     if(s->mb_type[i]&(~type)) s->mb_type[i] &= ~type;
1707                     else{
1708                         mv_table[xy][0] = 0;
1709                         mv_table[xy][1] = 0;
1710                         //this is certainly bad FIXME            
1711                     }
1712                 }
1713             }
1714             xy++;
1715             i++;
1716         }
1717     }
1718 }