]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/motion_est.c
fix %8 != 0 w/h
[ffmpeg] / libavcodec / motion_est.c
index 878c73cfdc84fcf52051aa9f5193a33676d78515..82b5f766eca913c7b9b86b57ccfdabfb83a9d695 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  *
  * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
  */
@@ -45,7 +45,7 @@
 #define P_MV1 P[9]
 
 static inline int sad_hpel_motion_search(MpegEncContext * s,
-                                 int *mx_ptr, int *my_ptr, int dmin,
+                                  int *mx_ptr, int *my_ptr, int dmin,
                                   int src_index, int ref_index,
                                   int size, int h);
 
@@ -293,25 +293,25 @@ static int pix_dev(uint8_t * pix, int line_size, int mean)
 
     s = 0;
     for (i = 0; i < 16; i++) {
-       for (j = 0; j < 16; j += 8) {
-           s += ABS(pix[0]-mean);
-           s += ABS(pix[1]-mean);
-           s += ABS(pix[2]-mean);
-           s += ABS(pix[3]-mean);
-           s += ABS(pix[4]-mean);
-           s += ABS(pix[5]-mean);
-           s += ABS(pix[6]-mean);
-           s += ABS(pix[7]-mean);
-           pix += 8;
-       }
-       pix += line_size - 16;
+        for (j = 0; j < 16; j += 8) {
+            s += ABS(pix[0]-mean);
+            s += ABS(pix[1]-mean);
+            s += ABS(pix[2]-mean);
+            s += ABS(pix[3]-mean);
+            s += ABS(pix[4]-mean);
+            s += ABS(pix[5]-mean);
+            s += ABS(pix[6]-mean);
+            s += ABS(pix[7]-mean);
+            pix += 8;
+        }
+        pix += line_size - 16;
     }
     return s;
 }
 #endif
 
 static inline void no_motion_search(MpegEncContext * s,
-                                   int *mx_ptr, int *my_ptr)
+                                    int *mx_ptr, int *my_ptr)
 {
     *mx_ptr = 16 * s->mb_x;
     *my_ptr = 16 * s->mb_y;
@@ -328,35 +328,35 @@ static int full_motion_search(MpegEncContext * s,
 
     xx = 16 * s->mb_x;
     yy = 16 * s->mb_y;
-    x1 = xx - range + 1;       /* we loose one pixel to avoid boundary pb with half pixel pred */
+    x1 = xx - range + 1;        /* we loose one pixel to avoid boundary pb with half pixel pred */
     if (x1 < xmin)
-       x1 = xmin;
+        x1 = xmin;
     x2 = xx + range - 1;
     if (x2 > xmax)
-       x2 = xmax;
+        x2 = xmax;
     y1 = yy - range + 1;
     if (y1 < ymin)
-       y1 = ymin;
+        y1 = ymin;
     y2 = yy + range - 1;
     if (y2 > ymax)
-       y2 = ymax;
+        y2 = ymax;
     pix = s->new_picture.data[0] + (yy * s->linesize) + xx;
     dmin = 0x7fffffff;
     mx = 0;
     my = 0;
     for (y = y1; y <= y2; y++) {
-       for (x = x1; x <= x2; x++) {
-           d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x,
-                            s->linesize, 16);
-           if (d < dmin ||
-               (d == dmin &&
-                (abs(x - xx) + abs(y - yy)) <
-                (abs(mx - xx) + abs(my - yy)))) {
-               dmin = d;
-               mx = x;
-               my = y;
-           }
-       }
+        for (x = x1; x <= x2; x++) {
+            d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x,
+                             s->linesize, 16);
+            if (d < dmin ||
+                (d == dmin &&
+                 (abs(x - xx) + abs(y - yy)) <
+                 (abs(mx - xx) + abs(my - yy)))) {
+                dmin = d;
+                mx = x;
+                my = y;
+            }
+        }
     }
 
     *mx_ptr = mx;
@@ -364,8 +364,8 @@ static int full_motion_search(MpegEncContext * s,
 
 #if 0
     if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
-       *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
-       fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
+        *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
+        av_log(NULL, AV_LOG_ERROR, "error %d %d\n", *mx_ptr, *my_ptr);
     }
 #endif
     return dmin;
@@ -386,22 +386,22 @@ static int log_motion_search(MpegEncContext * s,
     /* Left limit */
     x1 = xx - range;
     if (x1 < xmin)
-       x1 = xmin;
+        x1 = xmin;
 
     /* Right limit */
     x2 = xx + range;
     if (x2 > xmax)
-       x2 = xmax;
+        x2 = xmax;
 
     /* Upper limit */
     y1 = yy - range;
     if (y1 < ymin)
-       y1 = ymin;
+        y1 = ymin;
 
     /* Lower limit */
     y2 = yy + range;
     if (y2 > ymax)
-       y2 = ymax;
+        y2 = ymax;
 
     pix = s->new_picture.data[0] + (yy * s->linesize) + xx;
     dmin = 0x7fffffff;
@@ -409,34 +409,34 @@ static int log_motion_search(MpegEncContext * s,
     my = 0;
 
     do {
-       for (y = y1; y <= y2; y += range) {
-           for (x = x1; x <= x2; x += range) {
-               d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
-               if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
-                   dmin = d;
-                   mx = x;
-                   my = y;
-               }
-           }
-       }
-
-       range = range >> 1;
-
-       x1 = mx - range;
-       if (x1 < xmin)
-           x1 = xmin;
-
-       x2 = mx + range;
-       if (x2 > xmax)
-           x2 = xmax;
-
-       y1 = my - range;
-       if (y1 < ymin)
-           y1 = ymin;
-
-       y2 = my + range;
-       if (y2 > ymax)
-           y2 = ymax;
+        for (y = y1; y <= y2; y += range) {
+            for (x = x1; x <= x2; x += range) {
+                d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
+                if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
+                    dmin = d;
+                    mx = x;
+                    my = y;
+                }
+            }
+        }
+
+        range = range >> 1;
+
+        x1 = mx - range;
+        if (x1 < xmin)
+            x1 = xmin;
+
+        x2 = mx + range;
+        if (x2 > xmax)
+            x2 = xmax;
+
+        y1 = my - range;
+        if (y1 < ymin)
+            y1 = ymin;
+
+        y2 = my + range;
+        if (y2 > ymax)
+            y2 = ymax;
 
     } while (range >= 1);
 
@@ -462,22 +462,22 @@ static int phods_motion_search(MpegEncContext * s,
     /* Left limit */
     x1 = xx - range;
     if (x1 < xmin)
-       x1 = xmin;
+        x1 = xmin;
 
     /* Right limit */
     x2 = xx + range;
     if (x2 > xmax)
-       x2 = xmax;
+        x2 = xmax;
 
     /* Upper limit */
     y1 = yy - range;
     if (y1 < ymin)
-       y1 = ymin;
+        y1 = ymin;
 
     /* Lower limit */
     y2 = yy + range;
     if (y2 > ymax)
-       y2 = ymax;
+        y2 = ymax;
 
     pix = s->new_picture.data[0] + (yy * s->linesize) + xx;
     mx = 0;
@@ -489,43 +489,43 @@ static int phods_motion_search(MpegEncContext * s,
         dminx = 0x7fffffff;
         dminy = 0x7fffffff;
 
-       lastx = x;
-       for (x = x1; x <= x2; x += range) {
-           d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
-           if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
-               dminx = d;
-               mx = x;
-           }
-       }
-
-       x = lastx;
-       for (y = y1; y <= y2; y += range) {
-           d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
-           if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
-               dminy = d;
-               my = y;
-           }
-       }
-
-       range = range >> 1;
-
-       x = mx;
-       y = my;
-       x1 = mx - range;
-       if (x1 < xmin)
-           x1 = xmin;
-
-       x2 = mx + range;
-       if (x2 > xmax)
-           x2 = xmax;
-
-       y1 = my - range;
-       if (y1 < ymin)
-           y1 = ymin;
-
-       y2 = my + range;
-       if (y2 > ymax)
-           y2 = ymax;
+        lastx = x;
+        for (x = x1; x <= x2; x += range) {
+            d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
+            if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
+                dminx = d;
+                mx = x;
+            }
+        }
+
+        x = lastx;
+        for (y = y1; y <= y2; y += range) {
+            d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16);
+            if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
+                dminy = d;
+                my = y;
+            }
+        }
+
+        range = range >> 1;
+
+        x = mx;
+        y = my;
+        x1 = mx - range;
+        if (x1 < xmin)
+            x1 = xmin;
+
+        x2 = mx + range;
+        if (x2 > xmax)
+            x2 = xmax;
+
+        y1 = my - range;
+        if (y1 < ymin)
+            y1 = ymin;
+
+        y2 = my + range;
+        if (y2 > ymax)
+            y2 = ymax;
 
     } while (range >= 1);
 
@@ -550,7 +550,7 @@ static int phods_motion_search(MpegEncContext * s,
 }
 
 static inline int sad_hpel_motion_search(MpegEncContext * s,
-                                 int *mx_ptr, int *my_ptr, int dmin,
+                                  int *mx_ptr, int *my_ptr, int dmin,
                                   int src_index, int ref_index,
                                   int size, int h)
 {
@@ -901,6 +901,8 @@ static int interlaced_search(MpegEncContext *s, int ref_index,
             int16_t (*mv_table)[2]= mv_tables[block][field_select];
 
             if(user_field_select){
+                assert(field_select==0 || field_select==1);
+                assert(field_select_tables[block][xy]==0 || field_select_tables[block][xy]==1);
                 if(field_select_tables[block][xy] != field_select)
                     continue;
             }
@@ -1164,50 +1166,50 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
     /* intra / predictive decision */
     pix = c->src[0][0];
     sum = s->dsp.pix_sum(pix, s->linesize);
-    varc = (s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500 + 128)>>8;
+    varc = s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500;
 
     pic->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8;
-    pic->mb_var [s->mb_stride * mb_y + mb_x] = varc;
-    c->mb_var_sum_temp += varc;
+    pic->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8;
+    c->mb_var_sum_temp += (varc+128)>>8;
 
     if(c->avctx->me_threshold){
-        vard= (check_input_motion(s, mb_x, mb_y, 1)+128)>>8;
+        vard= check_input_motion(s, mb_x, mb_y, 1);
 
-        if(vard<c->avctx->me_threshold){
-            pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = vard;
-            c->mc_mb_var_sum_temp += vard;
-            if (vard <= 64 || vard < varc) { //FIXME
+        if((vard+128)>>8 < c->avctx->me_threshold){
+            pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8;
+            c->mc_mb_var_sum_temp += (vard+128)>>8;
+            if (vard <= 64<<8 || vard < varc) { //FIXME
                 c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
             }else{
-                c->scene_change_score+= s->qscale;
+                c->scene_change_score+= s->qscale * s->avctx->scenechange_factor;
             }
             return;
         }
-        if(vard<c->avctx->mb_threshold)
+        if((vard+128)>>8 < c->avctx->mb_threshold)
             mb_type= s->mb_type[mb_x + mb_y*s->mb_stride];
     }
 
     switch(s->me_method) {
     case ME_ZERO:
     default:
-       no_motion_search(s, &mx, &my);
+        no_motion_search(s, &mx, &my);
         mx-= mb_x*16;
         my-= mb_y*16;
         dmin = 0;
         break;
 #if 0
     case ME_FULL:
-       dmin = full_motion_search(s, &mx, &my, range, ref_picture);
+        dmin = full_motion_search(s, &mx, &my, range, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
     case ME_LOG:
-       dmin = log_motion_search(s, &mx, &my, range / 2, ref_picture);
+        dmin = log_motion_search(s, &mx, &my, range / 2, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
     case ME_PHODS:
-       dmin = phods_motion_search(s, &mx, &my, range / 2, ref_picture);
+        dmin = phods_motion_search(s, &mx, &my, range / 2, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
@@ -1256,21 +1258,21 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
     /* At this point (mx,my) are full-pell and the relative displacement */
     ppix = c->ref[0][0] + (my * s->linesize) + mx;
 
-    vard = (s->dsp.sse[0](NULL, pix, ppix, s->linesize, 16)+128)>>8;
+    vard = s->dsp.sse[0](NULL, pix, ppix, s->linesize, 16);
 
-    pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = vard;
+    pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8;
 //    pic->mb_cmp_score[s->mb_stride * mb_y + mb_x] = dmin;
-    c->mc_mb_var_sum_temp += vard;
+    c->mc_mb_var_sum_temp += (vard+128)>>8;
 
 #if 0
     printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n",
-          varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
+           varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
 #endif
     if(mb_type){
-        if (vard <= 64 || vard < varc)
+        if (vard <= 64<<8 || vard < varc)
             c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
         else
-            c->scene_change_score+= s->qscale;
+            c->scene_change_score+= s->qscale * s->avctx->scenechange_factor;
 
         if(mb_type == CANDIDATE_MB_TYPE_INTER){
             c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16);
@@ -1288,14 +1290,14 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
             interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 1);
         }
     }else if(c->avctx->mb_decision > FF_MB_DECISION_SIMPLE){
-        if (vard <= 64 || vard < varc)
+        if (vard <= 64<<8 || vard < varc)
             c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
         else
-            c->scene_change_score+= s->qscale;
+            c->scene_change_score+= s->qscale * s->avctx->scenechange_factor;
 
-        if (vard*2 + 200 > varc)
+        if (vard*2 + 200*256 > varc)
             mb_type|= CANDIDATE_MB_TYPE_INTRA;
-        if (varc*2 + 200 > vard){
+        if (varc*2 + 200*256 > vard){
             mb_type|= CANDIDATE_MB_TYPE_INTER;
             c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16);
             if(s->flags&CODEC_FLAG_MV0)
@@ -1306,7 +1308,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
             my <<=shift;
         }
         if((s->flags&CODEC_FLAG_4MV)
-           && !c->skip && varc>50 && vard>10){
+           && !c->skip && varc>50<<8 && vard>10<<8){
             if(h263_mv4_search(s, mx, my, shift) < INT_MAX)
                 mb_type|=CANDIDATE_MB_TYPE_INTER4V;
 
@@ -1327,7 +1329,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
             dmin= ff_get_mb_score(s, mx, my, 0, 0, 0, 16, 1);
 
         if((s->flags&CODEC_FLAG_4MV)
-           && !c->skip && varc>50 && vard>10){
+           && !c->skip && varc>50<<8 && vard>10<<8){
             int dmin4= h263_mv4_search(s, mx, my, shift);
             if(dmin4 < dmin){
                 mb_type= CANDIDATE_MB_TYPE_INTER4V;
@@ -1348,7 +1350,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
 
         /* get intra luma score */
         if((c->avctx->mb_cmp&0xFF)==FF_CMP_SSE){
-            intra_score= (varc<<8) - 500; //FIXME dont scale it down so we dont have to fix it
+            intra_score= varc - 500;
         }else{
             int mean= (sum+128)>>8;
             mean*= 0x01010101;
@@ -1394,10 +1396,10 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
         }else
             s->current_picture.mb_type[mb_y*s->mb_stride + mb_x]= 0;
 
-        if (vard <= 64 || vard < varc) { //FIXME
+        if (vard <= 64<<8 || vard < varc) { //FIXME
             c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
         }else{
-            c->scene_change_score+= s->qscale;
+            c->scene_change_score+= s->qscale * s->avctx->scenechange_factor;
         }
     }
 
@@ -1479,24 +1481,24 @@ static int ff_estimate_motion_b(MpegEncContext * s,
     switch(s->me_method) {
     case ME_ZERO:
     default:
-       no_motion_search(s, &mx, &my);
+        no_motion_search(s, &mx, &my);
         dmin = 0;
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
 #if 0
     case ME_FULL:
-       dmin = full_motion_search(s, &mx, &my, range, ref_picture);
+        dmin = full_motion_search(s, &mx, &my, range, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
     case ME_LOG:
-       dmin = log_motion_search(s, &mx, &my, range / 2, ref_picture);
+        dmin = log_motion_search(s, &mx, &my, range / 2, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
     case ME_PHODS:
-       dmin = phods_motion_search(s, &mx, &my, range / 2, ref_picture);
+        dmin = phods_motion_search(s, &mx, &my, range / 2, ref_picture);
         mx-= mb_x*16;
         my-= mb_y*16;
         break;
@@ -1561,7 +1563,8 @@ static inline int check_bidir_mv(MpegEncContext * s,
     //FIXME better f_code prediction (max mv & distance)
     //FIXME pointers
     MotionEstContext * const c= &s->me;
-    uint8_t * const mv_penalty= c->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+    uint8_t * const mv_penalty_f= c->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+    uint8_t * const mv_penalty_b= c->mv_penalty[s->b_code] + MAX_MV; // f_code of the prev frame
     int stride= c->stride;
     uint8_t *dest_y = c->scratchpad;
     uint8_t *ptr;
@@ -1602,8 +1605,8 @@ static inline int check_bidir_mv(MpegEncContext * s,
         s->dsp.avg_pixels_tab[size][dxy](dest_y    , ptr    , stride, h);
     }
 
-    fbmin = (mv_penalty[motion_fx-pred_fx] + mv_penalty[motion_fy-pred_fy])*c->mb_penalty_factor
-           +(mv_penalty[motion_bx-pred_bx] + mv_penalty[motion_by-pred_by])*c->mb_penalty_factor
+    fbmin = (mv_penalty_f[motion_fx-pred_fx] + mv_penalty_f[motion_fy-pred_fy])*c->mb_penalty_factor
+           +(mv_penalty_b[motion_bx-pred_bx] + mv_penalty_b[motion_by-pred_by])*c->mb_penalty_factor
            + s->dsp.mb_cmp[size](s, src_data[0], dest_y, stride, h); //FIXME new_pic
 
     if(c->avctx->mb_cmp&FF_CMP_CHROMA){
@@ -1616,6 +1619,7 @@ static inline int check_bidir_mv(MpegEncContext * s,
 /* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/
 static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y)
 {
+    MotionEstContext * const c= &s->me;
     const int mot_stride = s->mb_stride;
     const int xy = mb_y *mot_stride + mb_x;
     int fbmin;
@@ -1627,8 +1631,19 @@ static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y)
     int motion_fy= s->b_bidir_forw_mv_table[xy][1]= s->b_forw_mv_table[xy][1];
     int motion_bx= s->b_bidir_back_mv_table[xy][0]= s->b_back_mv_table[xy][0];
     int motion_by= s->b_bidir_back_mv_table[xy][1]= s->b_back_mv_table[xy][1];
-
-    //FIXME do refinement and add flag
+    const int flags= c->sub_flags;
+    const int qpel= flags&FLAG_QPEL;
+    const int shift= 1+qpel;
+    const int xmin= c->xmin<<shift;
+    const int ymin= c->ymin<<shift;
+    const int xmax= c->xmax<<shift;
+    const int ymax= c->ymax<<shift;
+    uint8_t map[8][8][8][8];
+
+    memset(map,0,sizeof(map));
+#define BIDIR_MAP(fx,fy,bx,by) \
+    map[(motion_fx+fx)&7][(motion_fy+fy)&7][(motion_bx+bx)&7][(motion_by+by)&7]
+    BIDIR_MAP(0,0,0,0) = 1;
 
     fbmin= check_bidir_mv(s, motion_fx, motion_fy,
                           motion_bx, motion_by,
@@ -1636,7 +1651,67 @@ static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y)
                           pred_bx, pred_by,
                           0, 16);
 
-   return fbmin;
+    if(s->avctx->bidir_refine){
+        int score, end;
+#define CHECK_BIDIR(fx,fy,bx,by)\
+    if( !BIDIR_MAP(fx,fy,bx,by)\
+       &&(fx<=0 || motion_fx+fx<=xmax) && (fy<=0 || motion_fy+fy<=ymax) && (bx<=0 || motion_bx+bx<=xmax) && (by<=0 || motion_by+by<=ymax)\
+       &&(fx>=0 || motion_fx+fx>=xmin) && (fy>=0 || motion_fy+fy>=ymin) && (bx>=0 || motion_bx+bx>=xmin) && (by>=0 || motion_by+by>=ymin)){\
+        BIDIR_MAP(fx,fy,bx,by) = 1;\
+        score= check_bidir_mv(s, motion_fx+fx, motion_fy+fy, motion_bx+bx, motion_by+by, pred_fx, pred_fy, pred_bx, pred_by, 0, 16);\
+        if(score < fbmin){\
+            fbmin= score;\
+            motion_fx+=fx;\
+            motion_fy+=fy;\
+            motion_bx+=bx;\
+            motion_by+=by;\
+            end=0;\
+        }\
+    }
+#define CHECK_BIDIR2(a,b,c,d)\
+CHECK_BIDIR(a,b,c,d)\
+CHECK_BIDIR(-a,-b,-c,-d)
+
+#define CHECK_BIDIRR(a,b,c,d)\
+CHECK_BIDIR2(a,b,c,d)\
+CHECK_BIDIR2(b,c,d,a)\
+CHECK_BIDIR2(c,d,a,b)\
+CHECK_BIDIR2(d,a,b,c)
+
+        do{
+            end=1;
+
+            CHECK_BIDIRR( 0, 0, 0, 1)
+            if(s->avctx->bidir_refine > 1){
+                CHECK_BIDIRR( 0, 0, 1, 1)
+                CHECK_BIDIR2( 0, 1, 0, 1)
+                CHECK_BIDIR2( 1, 0, 1, 0)
+                CHECK_BIDIRR( 0, 0,-1, 1)
+                CHECK_BIDIR2( 0,-1, 0, 1)
+                CHECK_BIDIR2(-1, 0, 1, 0)
+                if(s->avctx->bidir_refine > 2){
+                    CHECK_BIDIRR( 0, 1, 1, 1)
+                    CHECK_BIDIRR( 0,-1, 1, 1)
+                    CHECK_BIDIRR( 0, 1,-1, 1)
+                    CHECK_BIDIRR( 0, 1, 1,-1)
+                    if(s->avctx->bidir_refine > 3){
+                        CHECK_BIDIR2( 1, 1, 1, 1)
+                        CHECK_BIDIRR( 1, 1, 1,-1)
+                        CHECK_BIDIR2( 1, 1,-1,-1)
+                        CHECK_BIDIR2( 1,-1,-1, 1)
+                        CHECK_BIDIR2( 1,-1, 1,-1)
+                    }
+                }
+            }
+        }while(!end);
+    }
+
+    s->b_bidir_forw_mv_table[xy][0]= motion_fx;
+    s->b_bidir_forw_mv_table[xy][1]= motion_fy;
+    s->b_bidir_back_mv_table[xy][0]= motion_bx;
+    s->b_bidir_back_mv_table[xy][1]= motion_by;
+
+    return fbmin;
 }
 
 static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y)
@@ -1755,26 +1830,26 @@ void ff_estimate_b_frame_motion(MpegEncContext * s,
 
     c->skip=0;
     if(c->avctx->me_threshold){
-        int vard= (check_input_motion(s, mb_x, mb_y, 0)+128)>>8;
+        int vard= check_input_motion(s, mb_x, mb_y, 0);
 
-        if(vard<c->avctx->me_threshold){
+        if((vard+128)>>8 < c->avctx->me_threshold){
 //            pix = c->src[0][0];
 //            sum = s->dsp.pix_sum(pix, s->linesize);
-//            varc = (s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500 + 128)>>8;
+//            varc = s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500;
 
-//            pic->mb_var   [s->mb_stride * mb_y + mb_x] = varc;
-             s->current_picture.mc_mb_var[s->mb_stride * mb_y + mb_x] = vard;
+//            pic->mb_var   [s->mb_stride * mb_y + mb_x] = (varc+128)>>8;
+             s->current_picture.mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8;
 /*            pic->mb_mean  [s->mb_stride * mb_y + mb_x] = (sum+128)>>8;
-            c->mb_var_sum_temp    += varc;*/
-            c->mc_mb_var_sum_temp += vard;
-/*            if (vard <= 64 || vard < varc) {
+            c->mb_var_sum_temp    += (varc+128)>>8;*/
+            c->mc_mb_var_sum_temp += (vard+128)>>8;
+/*            if (vard <= 64<<8 || vard < varc) {
                 c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
             }else{
-                c->scene_change_score+= s->qscale;
+                c->scene_change_score+= s->qscale * s->avctx->scenechange_factor;
             }*/
             return;
         }
-        if(vard<c->avctx->mb_threshold){
+        if((vard+128)>>8 < c->avctx->mb_threshold){
             type= s->mb_type[mb_y*s->mb_stride + mb_x];
             if(type == CANDIDATE_MB_TYPE_DIRECT){
                 direct_search(s, mb_x, mb_y);