]> git.sesse.net Git - x264/blobdiff - encoder/analyse.c
early termination for intra4x4 analysis
[x264] / encoder / analyse.c
index 41b4bb2c5d5252ef977bbf6e83a470f5982e3aa1..991a41564875919c331792868d28b0e9c11f9cf8 100644 (file)
@@ -27,8 +27,8 @@
 #include <math.h>
 #include <limits.h>
 
-#include "../common/common.h"
-#include "../common/macroblock.h"
+#include "common/common.h"
+#include "common/macroblock.h"
 #include "macroblock.h"
 #include "me.h"
 #include "ratecontrol.h"
@@ -70,9 +70,13 @@ typedef struct
     /* conduct the analysis using this lamda and QP */
     int i_lambda;
     int i_qp;
+    int16_t *p_cost_mv;
 
 
     /* I: Intra part */
+    /* Take some shortcuts in intra search if intra is deemed unlikely */
+    int b_fast_intra;
+
     /* Luma part 16x16 and 4x4 modes stats */
     int i_sad_i16x16;
     int i_predict16x16;
@@ -85,8 +89,6 @@ typedef struct
     int i_predict8x8;
 
     /* II: Inter part P/B frame */
-    int i_mv_range;
-
     x264_mb_analysis_list_t l0;
     x264_mb_analysis_list_t l1;
 
@@ -133,6 +135,31 @@ static const int i_mb_b16x8_cost_table[16] = {
 static const int i_sub_mb_b_cost_table[13] = {
     7, 5, 5, 3, 7, 5, 7, 3, 7, 7, 7, 5, 1
 };
+static const int i_sub_mb_p_cost_table[4] = {
+    5, 3, 3, 1
+};
+
+/* initialize an array of lambda*nbits for all possible mvs */
+static void x264_mb_analyse_load_costs( x264_t *h, x264_mb_analysis_t *a )
+{
+    static int16_t *p_cost_mv[52];
+
+    if( !p_cost_mv[a->i_qp] )
+    {
+        /* could be faster, but isn't called many times */
+        /* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */
+        int i;
+        p_cost_mv[a->i_qp] = x264_malloc( (4*4*h->param.analyse.i_mv_range + 1) * sizeof(int16_t) );
+        p_cost_mv[a->i_qp] += 2*4*h->param.analyse.i_mv_range;
+        for( i = 0; i <= 2*4*h->param.analyse.i_mv_range; i++ )
+        {
+            p_cost_mv[a->i_qp][-i] =
+            p_cost_mv[a->i_qp][i]  = a->i_lambda * bs_size_se( i );
+        }
+    }
+
+    a->p_cost_mv = p_cost_mv[a->i_qp];
+}
 
 static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
 {
@@ -142,61 +169,87 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
     a->i_qp = i_qp;
     a->i_lambda = i_qp0_cost_table[i_qp];
 
+    h->mb.i_subpel_refine = h->param.analyse.i_subpel_refine;
+    h->mb.b_chroma_me = h->param.analyse.b_chroma_me && h->sh.i_type == SLICE_TYPE_P
+                        && h->mb.i_subpel_refine >= 5;
+    a->b_fast_intra = 0;
+
     /* I: Intra part */
-    a->i_sad_i16x16 = -1;
-    a->i_sad_i4x4   = -1;
-    a->i_sad_i8x8   = -1;
+    a->i_sad_i16x16 =
+    a->i_sad_i4x4   =
+    a->i_sad_i8x8   = COST_MAX;
 
     /* II: Inter part P/B frame */
     if( h->sh.i_type != SLICE_TYPE_I )
     {
-        int dmb;
         int i;
+        int i_fmv_range = h->param.analyse.i_mv_range - 16;
+
+        /* Calculate max allowed MV range */
+#define CLIP_FMV(mv) x264_clip3( mv, -i_fmv_range, i_fmv_range )
+        h->mb.mv_min_fpel[0] = CLIP_FMV( -16*h->mb.i_mb_x - 8 );
+        h->mb.mv_max_fpel[0] = CLIP_FMV( 16*( h->sps->i_mb_width - h->mb.i_mb_x ) - 8 );
+        h->mb.mv_min[0] = 4*( h->mb.mv_min_fpel[0] - 16 );
+        h->mb.mv_max[0] = 4*( h->mb.mv_max_fpel[0] + 16 );
+        if( h->mb.i_mb_x == 0)
+        {
+            h->mb.mv_min_fpel[1] = CLIP_FMV( -16*h->mb.i_mb_y - 8 );
+            h->mb.mv_max_fpel[1] = CLIP_FMV( 16*( h->sps->i_mb_height - h->mb.i_mb_y ) - 8 );
+            h->mb.mv_min[1] = 4*( h->mb.mv_min_fpel[1] - 16 );
+            h->mb.mv_max[1] = 4*( h->mb.mv_max_fpel[1] + 16 );
+        }
+#undef CLIP_FMV
 
-        /* Calculate max start MV range */
-        dmb = h->mb.i_mb_x;
-        if( h->mb.i_mb_y < dmb )
-            dmb = h->mb.i_mb_y;
-        if( h->sps->i_mb_width - h->mb.i_mb_x < dmb )
-            dmb = h->sps->i_mb_width - h->mb.i_mb_x;
-        if( h->sps->i_mb_height - h->mb.i_mb_y < dmb )
-            dmb = h->sps->i_mb_height - h->mb.i_mb_y;
-
-        a->i_mv_range = 16*dmb + 8;
-
-        a->l0.me16x16.cost = -1;
-        a->l0.i_cost8x8    = -1;
+        a->l0.me16x16.cost =
+        a->l0.i_cost8x8    = COST_MAX;
 
         for( i = 0; i < 4; i++ )
         {
-            a->l0.i_cost4x4[i] = -1;
-            a->l0.i_cost8x4[i] = -1;
-            a->l0.i_cost4x8[i] = -1;
+            a->l0.i_cost4x4[i] =
+            a->l0.i_cost8x4[i] =
+            a->l0.i_cost4x8[i] = COST_MAX;
         }
 
-        a->l0.i_cost16x8   = -1;
-        a->l0.i_cost8x16   = -1;
+        a->l0.i_cost16x8   =
+        a->l0.i_cost8x16   = COST_MAX;
         if( h->sh.i_type == SLICE_TYPE_B )
         {
-            a->l1.me16x16.cost = -1;
-            a->l1.i_cost8x8    = -1;
+            a->l1.me16x16.cost =
+            a->l1.i_cost8x8    = COST_MAX;
 
             for( i = 0; i < 4; i++ )
             {
-                a->l1.i_cost4x4[i] = -1;
-                a->l1.i_cost8x4[i] = -1;
-                a->l1.i_cost4x8[i] = -1;
-                a->i_cost8x8direct[i] = -1;
+                a->l1.i_cost4x4[i] =
+                a->l1.i_cost8x4[i] =
+                a->l1.i_cost4x8[i] =
+                a->i_cost8x8direct[i] = COST_MAX;
             }
 
-            a->l1.i_cost16x8   = -1;
-            a->l1.i_cost8x16   = -1;
+            a->l1.i_cost16x8   =
+            a->l1.i_cost8x16   =
 
-            a->i_cost16x16bi   = -1;
-            a->i_cost16x16direct = -1;
-            a->i_cost8x8bi     = -1;
-            a->i_cost16x8bi    = -1;
-            a->i_cost8x16bi    = -1;
+            a->i_cost16x16bi   =
+            a->i_cost16x16direct =
+            a->i_cost8x8bi     =
+            a->i_cost16x8bi    =
+            a->i_cost8x16bi    = COST_MAX;
+        }
+
+        /* Fast intra decision */
+        if( h->mb.i_mb_xy > 4 )
+        {
+            const unsigned int i_neighbour = h->mb.i_neighbour;
+            if(   ((i_neighbour&MB_LEFT) && IS_INTRA( h->mb.type[h->mb.i_mb_xy - 1] ))
+               || ((i_neighbour&MB_TOP) && IS_INTRA( h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride] ))
+               || (((i_neighbour&(MB_TOP|MB_LEFT)) == (MB_TOP|MB_LEFT)) && IS_INTRA( h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride-1 ] ))
+               || ((i_neighbour&MB_TOPRIGHT) && IS_INTRA( h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride+1 ] ))
+               || (h->sh.i_type == SLICE_TYPE_P && IS_INTRA( h->fref0[0]->mb_type[h->mb.i_mb_xy] ))
+               || (h->mb.i_mb_xy < 3*(h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_16x16])) )
+            { /* intra is likely */ }
+            else
+            {
+                a->b_fast_intra = 1;
+            }
         }
     }
 }
@@ -336,7 +389,7 @@ static void predict_4x4_mode_available( unsigned int i_neighbour, int idx, int *
     }
 }
 
-static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res )
+static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res, int i_cost_inter )
 {
     const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra : h->param.analyse.inter;
     const int i_stride = h->mb.pic.i_stride[0];
@@ -366,12 +419,21 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res )
         i_sad = h->pixf.satd[PIXEL_16x16]( p_dst, i_stride, p_src, i_stride ) +
                 res->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
         /* if i_score is lower it is better */
-        if( res->i_sad_i16x16 == -1 || res->i_sad_i16x16 > i_sad )
+        if( res->i_sad_i16x16 > i_sad )
         {
             res->i_predict16x16 = i_mode;
             res->i_sad_i16x16     = i_sad;
         }
     }
+    /* cavlc mb type prefix */
+    if( h->sh.i_type == SLICE_TYPE_B )
+        res->i_sad_i16x16 += res->i_lambda * i_mb_b_cost_table[I_16x16];
+
+    if( res->b_fast_intra )
+    {
+        if( res->i_sad_i16x16 > 2*i_cost_inter )
+            return;
+    }
 
     /* 4x4 prediction selection */
     if( flags & X264_ANALYSE_I4x4 )
@@ -392,7 +454,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res )
             p_src_by = p_src + 4 * x + 4 * y * i_stride;
             p_dst_by = p_dst + 4 * x + 4 * y * i_stride;
 
-            i_best = -1;
+            i_best = COST_MAX;
             predict_4x4_mode_available( h->mb.i_neighbour, idx, predict_mode, &i_max );
             for( i = 0; i < i_max; i++ )
             {
@@ -411,7 +473,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res )
                 i_sad += res->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix[i_mode] ? 1 : 4);
 
                 /* if i_score is lower it is better */
-                if( i_best == -1 || i_best > i_sad )
+                if( i_best > i_sad )
                 {
                     res->i_predict4x4[x][y] = i_mode;
                     i_best = i_sad;
@@ -428,6 +490,8 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res )
                 x264_mb_pred_mode4x4_fix[res->i_predict4x4[x][y]];
         }
         res->i_sad_i4x4 += res->i_lambda * 24;    /* from JVT (SATD0) */
+        if( h->sh.i_type == SLICE_TYPE_B )
+            res->i_sad_i4x4 += res->i_lambda * i_mb_b_cost_table[I_4x4];
     }
 }
 
@@ -441,6 +505,9 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *res )
     uint8_t *p_dstc[2], *p_srcc[2];
     int      i_stride[2];
 
+    if( res->i_sad_i8x8 < COST_MAX )
+        return;
+
     /* 8x8 prediction selection for chroma */
     p_dstc[0] = h->mb.pic.p_fdec[1];
     p_dstc[1] = h->mb.pic.p_fdec[2];
@@ -451,7 +518,7 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *res )
     i_stride[1] = h->mb.pic.i_stride[2];
 
     predict_8x8_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
-    res->i_sad_i8x8 = -1;
+    res->i_sad_i8x8 = COST_MAX;
     for( i = 0; i < i_max; i++ )
     {
         int i_sad;
@@ -471,7 +538,7 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *res )
                 res->i_lambda * bs_size_ue( x264_mb_pred_mode8x8_fix[i_mode] );
 
         /* if i_score is lower it is better */
-        if( res->i_sad_i8x8 == -1 || res->i_sad_i8x8 > i_sad )
+        if( res->i_sad_i8x8 > i_sad )
         {
             res->i_predict8x8 = i_mode;
             res->i_sad_i8x8     = i_sad;
@@ -479,30 +546,47 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *res )
     }
 }
 
+#define LOAD_FENC( m, src, xoff, yoff) \
+    (m)->i_stride[0] = h->mb.pic.i_stride[0]; \
+    (m)->i_stride[1] = h->mb.pic.i_stride[1]; \
+    (m)->p_fenc[0] = &(src)[0][(xoff)+(yoff)*(m)->i_stride[0]]; \
+    (m)->p_fenc[1] = &(src)[1][((xoff)>>1)+((yoff)>>1)*(m)->i_stride[1]]; \
+    (m)->p_fenc[2] = &(src)[2][((xoff)>>1)+((yoff)>>1)*(m)->i_stride[1]];
+#define LOAD_HPELS(m, src, xoff, yoff) \
+    (m)->p_fref[0] = &(src)[0][(xoff)+(yoff)*(m)->i_stride[0]]; \
+    (m)->p_fref[1] = &(src)[1][(xoff)+(yoff)*(m)->i_stride[0]]; \
+    (m)->p_fref[2] = &(src)[2][(xoff)+(yoff)*(m)->i_stride[0]]; \
+    (m)->p_fref[3] = &(src)[3][(xoff)+(yoff)*(m)->i_stride[0]]; \
+    (m)->p_fref[4] = &(src)[4][((xoff)>>1)+((yoff)>>1)*(m)->i_stride[1]]; \
+    (m)->p_fref[5] = &(src)[5][((xoff)>>1)+((yoff)>>1)*(m)->i_stride[1]];
+
 static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
 {
     x264_me_t m;
     int i_ref;
     int mvc[4][2], i_mvc;
+    int i_fullpel_thresh = INT_MAX;
+    int *p_fullpel_thresh = h->i_ref0>1 ? &i_fullpel_thresh : NULL;
 
     /* 16x16 Search on all ref frame */
     m.i_pixel = PIXEL_16x16;
-    m.lm      = a->i_lambda;
-    m.p_fenc  = h->mb.pic.p_fenc[0];
-    m.i_stride= h->mb.pic.i_stride[0];
-    m.i_mv_range = a->i_mv_range;
+    m.p_cost_mv = a->p_cost_mv;
+    LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 );
 
     a->l0.me16x16.cost = INT_MAX;
     for( i_ref = 0; i_ref < h->i_ref0; i_ref++ )
     {
+        const int i_ref_cost = a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, i_ref );
+        i_fullpel_thresh -= i_ref_cost;
+
         /* search with ref */
-        m.p_fref = h->mb.pic.p_fref[0][i_ref][0];
+        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, 0 );
         x264_mb_predict_mv_16x16( h, 0, i_ref, m.mvp );
         x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );
-        x264_me_search( h, &m, mvc, i_mvc );
+        x264_me_search_ref( h, &m, mvc, i_mvc, p_fullpel_thresh );
 
-        /* add ref cost */
-        m.cost += m.lm * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, i_ref );
+        m.cost += i_ref_cost;
+        i_fullpel_thresh += i_ref_cost;
 
         if( m.cost < a->l0.me16x16.cost )
         {
@@ -516,7 +600,7 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
     }
 
     /* subtract ref cost, so we don't have to add it for the other P types */
-    a->l0.me16x16.cost -= m.lm * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref );
+    a->l0.me16x16.cost -= a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref );
 
     /* Set global ref, needed for all others modes */
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.i_ref );
@@ -524,8 +608,8 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
 
 static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
     int mvc[5][2], i_mvc;
     int i;
 
@@ -543,12 +627,10 @@ static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
         const int y8 = i/2;
 
         m->i_pixel = PIXEL_8x8;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc = &p_fenc[8*(y8*h->mb.pic.i_stride[0]+x8)];
-        m->p_fref = &p_fref[8*(y8*h->mb.pic.i_stride[0]+x8)];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 8*x8, 8*y8 );
+        LOAD_HPELS( m, p_fref, 8*x8, 8*y8 );
 
         x264_mb_predict_mv( h, 0, 4*i, 2, m->mvp );
         x264_me_search( h, m, mvc, i_mvc );
@@ -558,6 +640,9 @@ static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
         mvc[i_mvc][0] = m->mv[0];
         mvc[i_mvc][1] = m->mv[1];
         i_mvc++;
+
+        /* mb type cost */
+        m->cost += a->i_lambda * i_sub_mb_p_cost_table[D_L0_8x8];
     }
 
     a->l0.i_cost8x8 = a->l0.me8x8[0].cost + a->l0.me8x8[1].cost +
@@ -566,8 +651,8 @@ static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
 
 static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
     int mvc[2][2];
     int i;
 
@@ -579,12 +664,10 @@ static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
         x264_me_t *m = &a->l0.me16x8[i];
 
         m->i_pixel = PIXEL_16x8;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc = &p_fenc[8*i*h->mb.pic.i_stride[0]];
-        m->p_fref = &p_fref[8*i*h->mb.pic.i_stride[0]];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 0, 8*i );
+        LOAD_HPELS( m, p_fref, 0, 8*i );
 
         mvc[0][0] = a->l0.me8x8[2*i].mv[0];
         mvc[0][1] = a->l0.me8x8[2*i].mv[1];
@@ -602,8 +685,8 @@ static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
 
 static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
     int mvc[2][2];
     int i;
 
@@ -615,12 +698,10 @@ static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a )
         x264_me_t *m = &a->l0.me8x16[i];
 
         m->i_pixel = PIXEL_8x16;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc  = &p_fenc[8*i];
-        m->p_fref  = &p_fref[8*i];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 8*i, 0 );
+        LOAD_HPELS( m, p_fref, 8*i, 0 );
 
         mvc[0][0] = a->l0.me8x8[i].mv[0];
         mvc[0][1] = a->l0.me8x8[i].mv[1];
@@ -636,10 +717,42 @@ static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a )
     a->l0.i_cost8x16 = a->l0.me8x16[0].cost + a->l0.me8x16[1].cost;
 }
 
+static int x264_mb_analyse_inter_p4x4_chroma( x264_t *h, x264_mb_analysis_t *a, uint8_t **p_fref, int i8x8, int pixel )
+{
+    uint8_t pix1[8*8], pix2[8*8];
+    const int i_stride = h->mb.pic.i_stride[1];
+    const int off = 4*(i8x8&1) + 2*(i8x8&2)*i_stride;
+
+#define CHROMA4x4MC( width, height, me, x, y ) \
+    h->mc.mc_chroma( &p_fref[4][off+x+y*i_stride], i_stride, &pix1[x+y*8], 8, (me).mv[0], (me).mv[1], width, height ); \
+    h->mc.mc_chroma( &p_fref[5][off+x+y*i_stride], i_stride, &pix2[x+y*8], 8, (me).mv[0], (me).mv[1], width, height );
+
+    if( pixel == PIXEL_4x4 )
+    {
+        CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][0], 0,0 );
+        CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][1], 0,2 );
+        CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][2], 2,0 );
+        CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][3], 2,2 );
+    }
+    else if( pixel == PIXEL_8x4 )
+    {
+        CHROMA4x4MC( 4,2, a->l0.me8x4[i8x8][0], 0,0 );
+        CHROMA4x4MC( 4,2, a->l0.me8x4[i8x8][1], 0,2 );
+    }
+    else
+    {
+        CHROMA4x4MC( 2,4, a->l0.me4x8[i8x8][0], 0,0 );
+        CHROMA4x4MC( 2,4, a->l0.me4x8[i8x8][1], 2,0 );
+    }
+
+    return h->pixf.satd[PIXEL_4x4]( &h->mb.pic.p_fenc[1][off], i_stride, pix1, 8 )
+         + h->pixf.satd[PIXEL_4x4]( &h->mb.pic.p_fenc[2][off], i_stride, pix2, 8 );
+}
+
 static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8x8 )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
 
     int i4x4;
 
@@ -656,12 +769,10 @@ static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8
         x264_me_t *m = &a->l0.me4x4[i8x8][i4x4];
 
         m->i_pixel = PIXEL_4x4;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc  = &p_fenc[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->p_fref  = &p_fref[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
 
         x264_mb_predict_mv( h, 0, idx, 1, m->mvp );
         x264_me_search( h, m, &a->l0.me8x8[i8x8].mv, i_mvc );
@@ -672,13 +783,16 @@ static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8
     a->l0.i_cost4x4[i8x8] = a->l0.me4x4[i8x8][0].cost +
                          a->l0.me4x4[i8x8][1].cost +
                          a->l0.me4x4[i8x8][2].cost +
-                         a->l0.me4x4[i8x8][3].cost;
+                         a->l0.me4x4[i8x8][3].cost +
+                         a->i_lambda * i_sub_mb_p_cost_table[D_L0_4x4];
+    if( h->mb.b_chroma_me )
+        a->l0.i_cost4x4[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_4x4 );
 }
 
 static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8x8 )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
 
     int i8x4;
 
@@ -695,12 +809,10 @@ static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8
         x264_me_t *m = &a->l0.me8x4[i8x8][i8x4];
 
         m->i_pixel = PIXEL_8x4;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc  = &p_fenc[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->p_fref  = &p_fref[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
 
         x264_mb_predict_mv( h, 0, idx, 2, m->mvp );
         x264_me_search( h, m, &a->l0.me4x4[i8x8][0].mv, i_mvc );
@@ -708,13 +820,16 @@ static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8
         x264_macroblock_cache_mv( h, x4, y4, 2, 1, 0, m->mv[0], m->mv[1] );
     }
 
-    a->l0.i_cost8x4[i8x8] = a->l0.me8x4[i8x8][0].cost + a->l0.me8x4[i8x8][1].cost;
+    a->l0.i_cost8x4[i8x8] = a->l0.me8x4[i8x8][0].cost + a->l0.me8x4[i8x8][1].cost +
+                            a->i_lambda * i_sub_mb_p_cost_table[D_L0_8x4];
+    if( h->mb.b_chroma_me )
+        a->l0.i_cost8x4[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_8x4 );
 }
 
 static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8x8 )
 {
-    uint8_t  *p_fref = h->mb.pic.p_fref[0][a->l0.i_ref][0];
-    uint8_t  *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.i_ref];
+    uint8_t  **p_fenc = h->mb.pic.p_fenc;
 
     int i4x8;
 
@@ -731,12 +846,10 @@ static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8
         x264_me_t *m = &a->l0.me4x8[i8x8][i4x8];
 
         m->i_pixel = PIXEL_4x8;
-        m->lm      = a->i_lambda;
+        m->p_cost_mv = a->p_cost_mv;
 
-        m->p_fenc  = &p_fenc[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->p_fref  = &p_fref[4*(y4*h->mb.pic.i_stride[0]+x4)];
-        m->i_stride= h->mb.pic.i_stride[0];
-        m->i_mv_range = a->i_mv_range;
+        LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
 
         x264_mb_predict_mv( h, 0, idx, 1, m->mvp );
         x264_me_search( h, m, &a->l0.me4x4[i8x8][0].mv, i_mvc );
@@ -744,7 +857,10 @@ static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8
         x264_macroblock_cache_mv( h, x4, y4, 1, 2, 0, m->mv[0], m->mv[1] );
     }
 
-    a->l0.i_cost4x8[i8x8] = a->l0.me4x8[i8x8][0].cost + a->l0.me4x8[i8x8][1].cost;
+    a->l0.i_cost4x8[i8x8] = a->l0.me4x8[i8x8][0].cost + a->l0.me4x8[i8x8][1].cost +
+                            a->i_lambda * i_sub_mb_p_cost_table[D_L0_4x8];
+    if( h->mb.b_chroma_me )
+        a->l0.i_cost4x8[i8x8] += x264_mb_analyse_inter_p4x4_chroma( h, a, p_fref, i8x8, PIXEL_4x8 );
 }
 
 static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
@@ -752,8 +868,8 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
     /* Assumes that fdec still contains the results of
      * x264_mb_predict_mv_direct16x16 and x264_mb_mc */
 
-    uint8_t *p_fenc = h->mb.pic.p_fenc[0];
-    uint8_t *p_fdec = h->mb.pic.p_fdec[0];
+    uint8_t **p_fenc = h->mb.pic.p_fenc;
+    uint8_t **p_fdec = h->mb.pic.p_fdec;
     int i_stride= h->mb.pic.i_stride[0];
     int i;
 
@@ -765,7 +881,7 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
         const int off = 8 * x8 + 8 * i_stride * y8;
         a->i_cost16x16direct +=
         a->i_cost8x8direct[i] =
-            h->pixf.satd[PIXEL_8x8]( &p_fenc[off], i_stride, &p_fdec[off], i_stride );
+            h->pixf.satd[PIXEL_8x8]( &p_fenc[0][off], i_stride, &p_fdec[0][off], i_stride );
 
         /* mb type cost */
         a->i_cost8x8direct[i] += a->i_lambda * i_sub_mb_b_cost_table[D_DIRECT_8x8];
@@ -774,84 +890,132 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
     a->i_cost16x16direct += a->i_lambda * i_mb_b_cost_table[B_DIRECT];
 }
 
+#define WEIGHTED_AVG( size, pix1, stride1, src2, stride2 ) \
+    { \
+        if( h->param.analyse.b_weighted_bipred ) \
+            h->pixf.avg_weight[size]( pix1, stride1, src2, stride2, \
+                    h->mb.bipred_weight[a->l0.i_ref][a->l1.i_ref] ); \
+        else \
+            h->pixf.avg[size]( pix1, stride1, src2, stride2 ); \
+    }
+
 static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
 {
     uint8_t pix1[16*16], pix2[16*16];
+    uint8_t *src2;
+    int stride2 = 16;
+    int src2_ref, pix1_ref;
 
     x264_me_t m;
     int i_ref;
+    int mvc[5][2], i_mvc;
+    int i_fullpel_thresh = INT_MAX;
+    int *p_fullpel_thresh = h->i_ref0>1 ? &i_fullpel_thresh : NULL;
 
     /* 16x16 Search on all ref frame */
     m.i_pixel = PIXEL_16x16;
-    m.lm      = a->i_lambda;
-    m.p_fenc  = h->mb.pic.p_fenc[0];
-    m.i_stride= h->mb.pic.i_stride[0];
-    m.i_mv_range = a->i_mv_range;
+    m.p_cost_mv = a->p_cost_mv;
+    LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 );
 
     /* ME for List 0 */
     a->l0.me16x16.cost = INT_MAX;
     for( i_ref = 0; i_ref < h->i_ref0; i_ref++ )
     {
         /* search with ref */
-        m.p_fref = h->mb.pic.p_fref[0][i_ref][0];
+        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, 0 );
         x264_mb_predict_mv_16x16( h, 0, i_ref, m.mvp );
-        x264_me_search( h, &m, NULL, 0 );
+        x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );
+        x264_me_search_ref( h, &m, mvc, i_mvc, p_fullpel_thresh );
 
         /* add ref cost */
-        m.cost += m.lm * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, i_ref );
+        m.cost += a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, i_ref );
 
         if( m.cost < a->l0.me16x16.cost )
         {
             a->l0.i_ref = i_ref;
             a->l0.me16x16 = m;
         }
+
+        /* save mv for predicting neighbors */
+        h->mb.mvr[0][i_ref][h->mb.i_mb_xy][0] = m.mv[0];
+        h->mb.mvr[0][i_ref][h->mb.i_mb_xy][1] = m.mv[1];
     }
     /* subtract ref cost, so we don't have to add it for the other MB types */
-    a->l0.me16x16.cost -= m.lm * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref );
+    a->l0.me16x16.cost -= a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref );
 
     /* ME for list 1 */
+    i_fullpel_thresh = INT_MAX;
+    p_fullpel_thresh = h->i_ref1>1 ? &i_fullpel_thresh : NULL;
     a->l1.me16x16.cost = INT_MAX;
     for( i_ref = 0; i_ref < h->i_ref1; i_ref++ )
     {
         /* search with ref */
-        m.p_fref = h->mb.pic.p_fref[1][i_ref][0];
+        LOAD_HPELS( &m, h->mb.pic.p_fref[1][i_ref], 0, 0 );
         x264_mb_predict_mv_16x16( h, 1, i_ref, m.mvp );
-        x264_me_search( h, &m, NULL, 0 );
+        x264_mb_predict_mv_ref16x16( h, 1, i_ref, mvc, &i_mvc );
+        x264_me_search_ref( h, &m, mvc, i_mvc, p_fullpel_thresh );
 
         /* add ref cost */
-        m.cost += m.lm * bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, i_ref );
+        m.cost += a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, i_ref );
 
         if( m.cost < a->l1.me16x16.cost )
         {
             a->l1.i_ref = i_ref;
             a->l1.me16x16 = m;
         }
+
+        /* save mv for predicting neighbors */
+        h->mb.mvr[1][i_ref][h->mb.i_mb_xy][0] = m.mv[0];
+        h->mb.mvr[1][i_ref][h->mb.i_mb_xy][1] = m.mv[1];
     }
     /* subtract ref cost, so we don't have to add it for the other MB types */
-    a->l1.me16x16.cost -= m.lm * bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, a->l1.i_ref );
+    a->l1.me16x16.cost -= a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, a->l1.i_ref );
 
     /* Set global ref, needed for other modes? */
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.i_ref );
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, a->l1.i_ref );
 
     /* get cost of BI mode */
-    h->mc[MC_LUMA]( h->mb.pic.p_fref[0][a->l0.i_ref][0], h->mb.pic.i_stride[0],
-                    pix1, 16,
-                    a->l0.me16x16.mv[0], a->l0.me16x16.mv[1],
-                    16, 16 );
-    h->mc[MC_LUMA]( h->mb.pic.p_fref[1][a->l1.i_ref][0], h->mb.pic.i_stride[0],
-                    pix2, 16,
-                    a->l1.me16x16.mv[0], a->l1.me16x16.mv[1],
-                    16, 16 );
-    h->pixf.avg[PIXEL_16x16]( pix1, 16, pix2, 16 );
-
-    a->i_cost16x16bi = h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0], pix1, 16 ) +
-                       a->i_lambda * ( bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref ) +
-                                       bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, a->l1.i_ref ) +
-                                       bs_size_se( a->l0.me16x16.mv[0] - a->l0.me16x16.mvp[0] ) +
-                                       bs_size_se( a->l0.me16x16.mv[1] - a->l0.me16x16.mvp[1] ) +
-                                       bs_size_se( a->l1.me16x16.mv[0] - a->l1.me16x16.mvp[0] ) +
-                                       bs_size_se( a->l1.me16x16.mv[1] - a->l1.me16x16.mvp[1] ) );
+    if ( ((a->l0.me16x16.mv[0] | a->l0.me16x16.mv[1]) & 1) == 0 )
+    {
+        /* l0 reference is halfpel, so get_ref on it will make it faster */
+        src2 = h->mc.get_ref( h->mb.pic.p_fref[0][a->l0.i_ref], h->mb.pic.i_stride[0],
+                        pix2, &stride2,
+                        a->l0.me16x16.mv[0], a->l0.me16x16.mv[1],
+                        16, 16 );
+        h->mc.mc_luma( h->mb.pic.p_fref[1][a->l1.i_ref], h->mb.pic.i_stride[0],
+                        pix1, 16,
+                        a->l1.me16x16.mv[0], a->l1.me16x16.mv[1],
+                        16, 16 );
+        src2_ref = a->l0.i_ref;
+        pix1_ref = a->l1.i_ref;
+    } 
+    else
+    {
+        /* if l0 was qpel, we'll use get_ref on l1 instead */
+        h->mc.mc_luma( h->mb.pic.p_fref[0][a->l0.i_ref], h->mb.pic.i_stride[0],
+                        pix1, 16,
+                        a->l0.me16x16.mv[0], a->l0.me16x16.mv[1],
+                        16, 16 );
+        src2 = h->mc.get_ref( h->mb.pic.p_fref[1][a->l1.i_ref], h->mb.pic.i_stride[0],
+                        pix2, &stride2,
+                        a->l1.me16x16.mv[0], a->l1.me16x16.mv[1],
+                        16, 16 );
+        src2_ref = a->l1.i_ref;
+        pix1_ref = a->l0.i_ref;
+    }
+
+    if( h->param.analyse.b_weighted_bipred )
+        h->pixf.avg_weight[PIXEL_16x16]( pix1, 16, src2, stride2,
+                h->mb.bipred_weight[pix1_ref][src2_ref] );
+    else
+        h->pixf.avg[PIXEL_16x16]( pix1, 16, src2, stride2 );
+
+    a->i_cost16x16bi = h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0], pix1, 16 )
+                     + a->i_lambda * ( bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref )
+                                     + bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, a->l1.i_ref ) )
+                     + a->l0.me16x16.cost_mv
+                     + a->l1.me16x16.cost_mv;
 
     /* mb type cost */
     a->i_cost16x16bi   += a->i_lambda * i_mb_b_cost_table[B_BI_BI];
@@ -916,9 +1080,9 @@ static inline void x264_mb_cache_mv_b8x16( x264_t *h, x264_mb_analysis_t *a, int
 
 static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t *p_fref[2] = { h->mb.pic.p_fref[0][a->l0.i_ref][0],
-                           h->mb.pic.p_fref[1][a->l1.i_ref][0] };
-    uint8_t *p_fenc = h->mb.pic.p_fenc[0];
+    uint8_t **p_fref[2] =
+        { h->mb.pic.p_fref[0][a->l0.i_ref],
+          h->mb.pic.p_fref[1][a->l1.i_ref] };
     uint8_t pix[2][8*8];
     int i, l;
 
@@ -931,7 +1095,6 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
     {
         const int x8 = i%2;
         const int y8 = i/2;
-        uint8_t *p_fenc_i = &p_fenc[8*(y8*h->mb.pic.i_stride[0]+x8)];
         int i_part_cost;
         int i_part_cost_bi = 0;
 
@@ -941,31 +1104,28 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
             x264_me_t *m = &lX->me8x8[i];
 
             m->i_pixel = PIXEL_8x8;
-            m->lm      = a->i_lambda;
+            m->p_cost_mv = a->p_cost_mv;
 
-            m->p_fenc = p_fenc_i;
-            m->p_fref = &p_fref[l][8*(y8*h->mb.pic.i_stride[0]+x8)];
-            m->i_stride = h->mb.pic.i_stride[0];
-            m->i_mv_range = a->i_mv_range;
+            LOAD_FENC( m, h->mb.pic.p_fenc, 8*x8, 8*y8 );
+            LOAD_HPELS( m, p_fref[l], 8*x8, 8*y8 );
 
             x264_mb_predict_mv( h, l, 4*i, 2, m->mvp );
             x264_me_search( h, m, &lX->me16x16.mv, 1 );
 
             x264_macroblock_cache_mv( h, 2*x8, 2*y8, 2, 2, l, m->mv[0], m->mv[1] );
-            lX->i_cost8x8 += m->cost;
 
             /* BI mode */
-            h->mc[MC_LUMA]( m->p_fref, m->i_stride, pix[l], 8,
+            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 8,
                             m->mv[0], m->mv[1], 8, 8 );
+            i_part_cost_bi += m->cost_mv;
             /* FIXME: ref cost */
-            i_part_cost_bi += a->i_lambda * ( bs_size_se( m->mv[0] - m->mvp[0] ) +
-                                              bs_size_se( m->mv[1] - m->mvp[1] ) +
-                                              i_sub_mb_b_cost_table[D_L0_8x8] );
         }
 
-        h->pixf.avg[PIXEL_8x8]( pix[0], 8, pix[1], 8 );
-        i_part_cost_bi += h->pixf.satd[PIXEL_8x8]( p_fenc_i, h->mb.pic.i_stride[0], pix[0], 8 )
+        WEIGHTED_AVG( PIXEL_8x8, pix[0], 8, pix[1], 8 );
+        i_part_cost_bi += h->pixf.satd[PIXEL_8x8]( a->l0.me8x8[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 8 )
                         + a->i_lambda * i_sub_mb_b_cost_table[D_BI_8x8];
+        a->l0.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L0_8x8];
+        a->l1.me8x8[i].cost += a->i_lambda * i_sub_mb_b_cost_table[D_L1_8x8];
 
         i_part_cost = a->l0.me8x8[i].cost;
         h->mb.i_sub_partition[i] = D_L0_8x8;
@@ -979,7 +1139,7 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
             i_part_cost = i_part_cost_bi;
             h->mb.i_sub_partition[i] = D_BI_8x8;
         }
-        if( a->i_cost8x8direct[i] < i_part_cost && a->i_cost8x8direct[i] >= 0)
+        if( a->i_cost8x8direct[i] < i_part_cost )
         {
             i_part_cost = a->i_cost8x8direct[i];
             h->mb.i_sub_partition[i] = D_DIRECT_8x8;
@@ -996,11 +1156,10 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
 
 static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t *p_fref[2] = { h->mb.pic.p_fref[0][a->l0.i_ref][0],
-                           h->mb.pic.p_fref[1][a->l1.i_ref][0] };
-    uint8_t *p_fenc = h->mb.pic.p_fenc[0];
-    uint8_t pix[2][8*8];
-    int i_ref_stride = h->mb.pic.i_stride[0];
+    uint8_t **p_fref[2] =
+        { h->mb.pic.p_fref[0][a->l0.i_ref],
+          h->mb.pic.p_fref[1][a->l1.i_ref] };
+    uint8_t pix[2][16*8];
     int mvc[2][2];
     int i, l;
 
@@ -1009,7 +1168,6 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
 
     for( i = 0; i < 2; i++ )
     {
-        uint8_t *p_fenc_i = &p_fenc[8*i*i_ref_stride];
         int i_part_cost;
         int i_part_cost_bi = 0;
 
@@ -1020,12 +1178,10 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
             x264_me_t *m = &lX->me16x8[i];
 
             m->i_pixel = PIXEL_16x8;
-            m->lm      = a->i_lambda;
+            m->p_cost_mv = a->p_cost_mv;
 
-            m->p_fenc  = p_fenc_i;
-            m->i_stride= i_ref_stride;
-            m->p_fref  = &p_fref[l][8*i*i_ref_stride];
-            m->i_mv_range = a->i_mv_range;
+            LOAD_FENC( m, h->mb.pic.p_fenc, 0, 8*i );
+            LOAD_HPELS( m, p_fref[l], 0, 8*i );
 
             mvc[0][0] = lX->me8x8[2*i].mv[0];
             mvc[0][1] = lX->me8x8[2*i].mv[1];
@@ -1036,15 +1192,14 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
             x264_me_search( h, m, mvc, 2 );
 
             /* BI mode */
-            h->mc[MC_LUMA]( m->p_fref, m->i_stride, pix[l], 8,
-                            m->mv[0], m->mv[1], 8, 8 );
+            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 16,
+                            m->mv[0], m->mv[1], 16, 8 );
             /* FIXME: ref cost */
-            i_part_cost_bi += a->i_lambda * ( bs_size_se( m->mv[0] - m->mvp[0] ) +
-                                              bs_size_se( m->mv[1] - m->mvp[1] ) );
+            i_part_cost_bi += m->cost_mv;
         }
 
-        h->pixf.avg[PIXEL_16x8]( pix[0], 8, pix[1], 8 );
-        i_part_cost_bi += h->pixf.satd[PIXEL_16x8]( p_fenc_i, h->mb.pic.i_stride[0], pix[0], 8 );
+        WEIGHTED_AVG( PIXEL_16x8, pix[0], 16, pix[1], 16 );
+        i_part_cost_bi += h->pixf.satd[PIXEL_16x8]( a->l0.me16x8[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 16 );
 
         i_part_cost = a->l0.me16x8[i].cost;
         a->i_mb_partition16x8[i] = D_L0_8x8; /* not actually 8x8, only the L0 matters */
@@ -1072,11 +1227,10 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
 }
 static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t *p_fref[2] = { h->mb.pic.p_fref[0][a->l0.i_ref][0],
-                           h->mb.pic.p_fref[1][a->l1.i_ref][0] };
-    uint8_t *p_fenc = h->mb.pic.p_fenc[0];
-    uint8_t pix[2][8*8];
-    int i_ref_stride = h->mb.pic.i_stride[0];
+    uint8_t **p_fref[2] =
+        { h->mb.pic.p_fref[0][a->l0.i_ref],
+          h->mb.pic.p_fref[1][a->l1.i_ref] };
+    uint8_t pix[2][8*16];
     int mvc[2][2];
     int i, l;
 
@@ -1085,7 +1239,6 @@ static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
 
     for( i = 0; i < 2; i++ )
     {
-        uint8_t *p_fenc_i = &p_fenc[8*i];
         int i_part_cost;
         int i_part_cost_bi = 0;
 
@@ -1095,12 +1248,10 @@ static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
             x264_me_t *m = &lX->me8x16[i];
 
             m->i_pixel = PIXEL_8x16;
-            m->lm      = a->i_lambda;
+            m->p_cost_mv = a->p_cost_mv;
 
-            m->p_fenc  = p_fenc_i;
-            m->p_fref  = &p_fref[l][8*i];
-            m->i_stride= i_ref_stride;
-            m->i_mv_range = a->i_mv_range;
+            LOAD_FENC( m, h->mb.pic.p_fenc, 8*i, 0 );
+            LOAD_HPELS( m, p_fref[l], 8*i, 0 );
 
             mvc[0][0] = lX->me8x8[i].mv[0];
             mvc[0][1] = lX->me8x8[i].mv[1];
@@ -1111,15 +1262,14 @@ static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
             x264_me_search( h, m, mvc, 2 );
 
             /* BI mode */
-            h->mc[MC_LUMA]( m->p_fref, m->i_stride, pix[l], 8,
-                            m->mv[0], m->mv[1], 8, 8 );
+            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 8,
+                            m->mv[0], m->mv[1], 8, 16 );
             /* FIXME: ref cost */
-            i_part_cost_bi += a->i_lambda * ( bs_size_se( m->mv[0] - m->mvp[0] ) +
-                                              bs_size_se( m->mv[1] - m->mvp[1] ) );
+            i_part_cost_bi += m->cost_mv;
         }
 
-        h->pixf.avg[PIXEL_8x16]( pix[0], 8, pix[1], 8 );
-        i_part_cost_bi += h->pixf.satd[PIXEL_8x16]( p_fenc_i, h->mb.pic.i_stride[0], pix[0], 8 );
+        WEIGHTED_AVG( PIXEL_8x16, pix[0], 8, pix[1], 8 );
+        i_part_cost_bi += h->pixf.satd[PIXEL_8x16]( a->l0.me8x16[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 8 );
 
         i_part_cost = a->l0.me8x16[i].cost;
         a->i_mb_partition8x16[i] = D_L0_8x8;
@@ -1156,11 +1306,9 @@ void x264_macroblock_analyse( x264_t *h )
 
     h->mb.qp[h->mb.i_mb_xy] = x264_ratecontrol_qp(h);
 
-    /* FIXME check if it's 12 */
-    if( h->mb.qp[h->mb.i_mb_xy] - h->mb.i_last_qp < -12 )
-        h->mb.qp[h->mb.i_mb_xy] = h->mb.i_last_qp - 12;
-    else if( h->mb.qp[h->mb.i_mb_xy] - h->mb.i_last_qp > 12 )
-        h->mb.qp[h->mb.i_mb_xy] = h->mb.i_last_qp + 12;
+    /* prevent QP from varying too fast. FIXME what's a sane limit? */
+    h->mb.qp[h->mb.i_mb_xy] = x264_clip3( h->mb.qp[h->mb.i_mb_xy],
+                                          h->mb.i_last_qp - 12, h->mb.i_last_qp + 12 );
 
     /* init analysis */
     x264_mb_analyse_init( h, &analysis, h->mb.qp[h->mb.i_mb_xy] );
@@ -1168,9 +1316,9 @@ void x264_macroblock_analyse( x264_t *h )
     /*--------------------------- Do the analysis ---------------------------*/
     if( h->sh.i_type == SLICE_TYPE_I )
     {
-        x264_mb_analyse_intra( h, &analysis );
+        x264_mb_analyse_intra( h, &analysis, COST_MAX );
 
-        if( analysis.i_sad_i4x4 >= 0 &&  analysis.i_sad_i4x4 < analysis.i_sad_i16x16 )
+        if( analysis.i_sad_i4x4 < analysis.i_sad_i16x16 )
             h->mb.i_type = I_4x4;
         else
             h->mb.i_type = I_16x16;
@@ -1203,6 +1351,8 @@ void x264_macroblock_analyse( x264_t *h )
             int i_type;
             int i_partition;
 
+            x264_mb_analyse_load_costs( h, &analysis );
+
             x264_mb_analyse_inter_p16x16( h, &analysis );
             if( flags & X264_ANALYSE_PSUB16x16 )
                 x264_mb_analyse_inter_p8x8( h, &analysis );
@@ -1333,23 +1483,32 @@ void x264_macroblock_analyse( x264_t *h )
                                       analysis.l0.me4x4[i8x8][3].cost;
                             break;
                         default:
-                            fprintf( stderr, "internal error (!8x8 && !4x4)" );
+                            x264_log( h, X264_LOG_ERROR, "internal error (!8x8 && !4x4)\n" );
                             break;
                     }
                 }
             }
 
-            x264_mb_analyse_intra( h, &analysis );
+            x264_mb_analyse_intra( h, &analysis, i_cost );
+            if( h->mb.b_chroma_me &&
+                ( analysis.i_sad_i16x16 < i_cost
+             || ( analysis.i_sad_i4x4 < i_cost )))
+            {
+                x264_mb_analyse_intra_chroma( h, &analysis );
+                analysis.i_sad_i16x16 += analysis.i_sad_i8x8;
+                analysis.i_sad_i4x4 += analysis.i_sad_i8x8;
+            }
+
             i_intra_type = I_16x16;
             i_intra_cost = analysis.i_sad_i16x16;
 
-            if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_intra_cost )
+            if( analysis.i_sad_i4x4 < i_intra_cost )
             {
                 i_intra_type = I_4x4;
                 i_intra_cost = analysis.i_sad_i4x4;
             }
 
-            if( i_intra_cost >= 0 && i_intra_cost < i_cost )
+            if( i_intra_cost < i_cost )
             {
                 h->mb.i_type = i_intra_type;
                 i_cost = i_intra_cost;
@@ -1380,6 +1539,8 @@ void x264_macroblock_analyse( x264_t *h )
             int i_partition;
             int i_cost;
 
+            x264_mb_analyse_load_costs( h, &analysis );
+
             /* select best inter mode */
             /* direct must be first */
             if( analysis.b_direct_available )
@@ -1400,7 +1561,7 @@ void x264_macroblock_analyse( x264_t *h )
                 h->mb.i_type = B_BI_BI;
                 i_cost = analysis.i_cost16x16bi;
             }
-            if( analysis.i_cost16x16direct < i_cost && analysis.i_cost16x16direct >= 0 )
+            if( analysis.i_cost16x16direct < i_cost )
             {
                 h->mb.i_type = B_DIRECT;
                 i_cost = analysis.i_cost16x16direct;
@@ -1445,35 +1606,91 @@ void x264_macroblock_analyse( x264_t *h )
             /* refine qpel */
             if( i_partition == D_16x16 )
             {
+                analysis.l0.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
+                analysis.l1.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
                 if( h->mb.i_type == B_L0_L0 )
                 {
-                    analysis.l0.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
                     x264_me_refine_qpel( h, &analysis.l0.me16x16 );
-                    analysis.l0.me16x16.cost += analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
-                    i_cost = analysis.l0.me16x16.cost;
+                    i_cost = analysis.l0.me16x16.cost
+                           + analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
                 }
                 else if( h->mb.i_type == B_L1_L1 )
                 {
-                    analysis.l1.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
                     x264_me_refine_qpel( h, &analysis.l1.me16x16 );
-                    analysis.l1.me16x16.cost += analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
-                    i_cost = analysis.l1.me16x16.cost;
+                    i_cost = analysis.l1.me16x16.cost
+                           + analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
+                }
+                else if( h->mb.i_type == B_BI_BI )
+                {
+                    x264_me_refine_qpel( h, &analysis.l0.me16x16 );
+                    x264_me_refine_qpel( h, &analysis.l1.me16x16 );
+                }
+            }
+            else if( i_partition == D_16x8 )
+            {
+                for( i=0; i<2; i++ )
+                {
+                    if( analysis.i_mb_partition16x8[i] != D_L1_8x8 )
+                        x264_me_refine_qpel( h, &analysis.l0.me16x8[i] );
+                    if( analysis.i_mb_partition16x8[i] != D_L0_8x8 )
+                        x264_me_refine_qpel( h, &analysis.l1.me16x8[i] );
+                }
+            }
+            else if( i_partition == D_8x16 )
+            {
+                for( i=0; i<2; i++ )
+                {
+                    if( analysis.i_mb_partition8x16[i] != D_L1_8x8 )
+                        x264_me_refine_qpel( h, &analysis.l0.me8x16[i] );
+                    if( analysis.i_mb_partition8x16[i] != D_L0_8x8 )
+                        x264_me_refine_qpel( h, &analysis.l1.me8x16[i] );
+                }
+            }
+            else if( i_partition == D_8x8 )
+            {
+                for( i=0; i<4; i++ )
+                {
+                    x264_me_t *m;
+                    int i_part_cost_old;
+                    int i_type_cost;
+                    int i_part_type = h->mb.i_sub_partition[i];
+                    int b_bidir = (i_part_type == D_BI_8x8);
+
+                    if( i_part_type == D_DIRECT_8x8 )
+                        continue;
+                    if( x264_mb_partition_listX_table[0][i_part_type] )
+                    {
+                        m = &analysis.l0.me8x8[i];
+                        i_part_cost_old = m->cost;
+                        i_type_cost = analysis.i_lambda * i_sub_mb_b_cost_table[D_L0_8x8];
+                        m->cost -= i_type_cost;
+                        x264_me_refine_qpel( h, m );
+                        if( !b_bidir )
+                            analysis.i_cost8x8bi += m->cost + i_type_cost - i_part_cost_old;
+                    }
+                    if( x264_mb_partition_listX_table[1][i_part_type] )
+                    {
+                        m = &analysis.l1.me8x8[i];
+                        i_part_cost_old = m->cost;
+                        i_type_cost = analysis.i_lambda * i_sub_mb_b_cost_table[D_L1_8x8];
+                        m->cost -= i_type_cost;
+                        x264_me_refine_qpel( h, m );
+                        if( !b_bidir )
+                            analysis.i_cost8x8bi += m->cost + i_type_cost - i_part_cost_old;
+                    }
+                    /* TODO: update mvp? */
                 }
             }
-            /* TODO: refine bidir, 8x8 */
 
             /* best intra mode */
-            x264_mb_analyse_intra( h, &analysis );
-            /* mb type cost */
-            analysis.i_sad_i16x16 += analysis.i_lambda * i_mb_b_cost_table[I_16x16];
-            analysis.i_sad_i4x4   += analysis.i_lambda * i_mb_b_cost_table[I_4x4];
+            x264_mb_analyse_intra( h, &analysis, i_cost );
 
-            if( analysis.i_sad_i16x16 >= 0 && analysis.i_sad_i16x16 < i_cost )
+            if( analysis.i_sad_i16x16 < i_cost )
             {
                 h->mb.i_type = I_16x16;
                 i_cost = analysis.i_sad_i16x16;
             }
-            if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_cost )
+            if( analysis.i_sad_i4x4 < i_cost )
             {
                 h->mb.i_type = I_4x4;
                 i_cost = analysis.i_sad_i4x4;
@@ -1521,7 +1738,7 @@ void x264_macroblock_analyse( x264_t *h )
                     break;
 
                 default:
-                    fprintf( stderr, "internal error P_L0 and partition=%d\n", h->mb.i_partition );
+                    x264_log( h, X264_LOG_ERROR, "internal error P_L0 and partition=%d\n", h->mb.i_partition );
                     break;
             }
             break;
@@ -1553,7 +1770,7 @@ void x264_macroblock_analyse( x264_t *h )
                         x264_macroblock_cache_mv( h, x+1, y+1, 1, 1, 0, analysis.l0.me4x4[i][3].mv[0], analysis.l0.me4x4[i][3].mv[1] );
                         break;
                     default:
-                        fprintf( stderr, "internal error\n" );
+                        x264_log( h, X264_LOG_ERROR, "internal error\n" );
                         break;
                 }
             }
@@ -1626,9 +1843,11 @@ void x264_macroblock_analyse( x264_t *h )
                 x264_mb_cache_mv_b8x16( h, &analysis, 1, 1 );
                 break;
             default:
-                fprintf( stderr, "internal error (invalid MB type)\n" );
+                x264_log( h, X264_LOG_ERROR, "internal error (invalid MB type)\n" );
                 break;
             }
     }
 }
 
+#include "slicetype_decision.c"
+