]> git.sesse.net Git - x264/blobdiff - encoder/analyse.c
fix shared libs on MacOSX
[x264] / encoder / analyse.c
index 334220dcf7292b62365b474f1ed91c76e78d6e50..de3cf57234e3e21d0fdee267d77e115f59db7990 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
 #include <math.h>
 #include <limits.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
 
 #include "common/common.h"
 #include "macroblock.h"
@@ -39,12 +39,13 @@ typedef struct
 {
     /* 16x16 */
     int i_ref;
+    int       i_rd16x16;
     x264_me_t me16x16;
 
     /* 8x8 */
     int       i_cost8x8;
-    int       mvc[16][5][2]; /* [ref][0] is 16x16 mv,
-                                [ref][1..4] are 8x8 mv from partition [0..3] */
+    /* [ref][0] is 16x16 mv, [ref][1..4] are 8x8 mv from partition [0..3] */
+    DECLARE_ALIGNED_8( int mvc[32][5][2] );
     x264_me_t me8x8[4];
 
     /* Sub 4x4 */
@@ -57,7 +58,7 @@ typedef struct
 
     /* Sub 4x8 */
     int       i_cost4x8[4]; /* cost per 8x8 partition */
-    x264_me_t me4x8[4][4];
+    x264_me_t me4x8[4][2];
 
     /* 16x8 */
     int       i_cost16x8;
@@ -82,20 +83,23 @@ typedef struct
     /* I: Intra part */
     /* Take some shortcuts in intra search if intra is deemed unlikely */
     int b_fast_intra;
-    int i_best_satd;
+    int b_try_pskip;
 
     /* Luma part */
-    int i_sad_i16x16;
+    int i_satd_i16x16;
+    int i_satd_i16x16_dir[7];
     int i_predict16x16;
 
-    int i_sad_i8x8;
-    int i_predict8x8[2][2];
+    int i_satd_i8x8;
+    int i_satd_i8x8_dir[12][4];
+    int i_predict8x8[4];
 
-    int i_sad_i4x4;
-    int i_predict4x4[4][4];
+    int i_satd_i4x4;
+    int i_predict4x4[16];
 
     /* Chroma part */
-    int i_sad_i8x8chroma;
+    int i_satd_i8x8chroma;
+    int i_satd_i8x8chroma_dir[4];
     int i_predict8x8chroma;
 
     /* II: Inter part P/B frame */
@@ -108,6 +112,11 @@ typedef struct
     int i_cost8x8direct[4];
     int i_cost16x8bi;
     int i_cost8x16bi;
+    int i_rd16x16bi;
+    int i_rd16x16direct;
+    int i_rd16x8bi;
+    int i_rd8x16bi;
+    int i_rd8x8bi;
 
     int i_mb_partition16x8[2]; /* mb_partition_e */
     int i_mb_partition8x16[2];
@@ -129,21 +138,19 @@ static const int i_qp0_cost_table[52] = {
   40,45,51,57,64,72,81,91   /* 44-51 */
 };
 
-/* pow(lambda,2) * .9 */
+/* lambda2 = pow(lambda,2) * .9 * 256 */
 static const int i_qp0_cost2_table[52] = {
-   1,   1,   1,   1,   1,   1, /*  0-5  */
-   1,   1,   1,   1,   1,   1, /*  6-11 */
-   1,   1,   1,   2,   2,   3, /* 12-17 */
-   4,   5,   6,   7,   9,  11, /* 18-23 */
-  14,  18,  23,  29,  36,  46, /* 24-29 */
-  58,  73,  91, 115, 145, 183, /* 30-35 */
- 230, 290, 366, 461, 581, 731, /* 36-41 */
- 922,1161,1463,1843,2322,2926, /* 42-47 */
-3686,4645,5852,7373
+    14,      18,      22,      28,     36,     45,     57,     72, /*  0 -  7 */
+    91,     115,     145,     182,    230,    290,    365,    460, /*  8 - 15 */
+   580,     731,     921,    1161,   1462,   1843,   2322,   2925, /* 16 - 23 */
+  3686,    4644,    5851,    7372,   9289,  11703,  14745,  18578, /* 24 - 31 */
+ 23407,   29491,   37156,   46814,  58982,  74313,  93628, 117964, /* 32 - 39 */
+148626,  187257,  235929,  297252, 374514, 471859, 594505, 749029, /* 40 - 47 */
+943718, 1189010, 1498059, 1887436                                  /* 48 - 51 */
 };
 
 /* TODO: calculate CABAC costs */
-static const int i_mb_b_cost_table[19] = {
+static const int i_mb_b_cost_table[X264_MBTYPE_MAX] = {
     9, 9, 9, 9, 0, 0, 0, 1, 3, 7, 7, 7, 3, 7, 7, 7, 5, 9, 0
 };
 static const int i_mb_b16x8_cost_table[17] = {
@@ -158,34 +165,46 @@ static const int i_sub_mb_p_cost_table[4] = {
 
 static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a );
 
+uint16_t *x264_cost_mv_fpel[52][4];
+
 /* 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];
+    int i, j;
 
     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] = x264_malloc( (4*4*2048 + 1) * sizeof(int16_t) );
+        p_cost_mv[a->i_qp] += 2*4*2048;
+        for( i = 0; i <= 2*4*2048; 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];
+
+    /* FIXME is this useful for all me methods? */
+    if( h->param.analyse.i_me_method >= X264_ME_ESA && !x264_cost_mv_fpel[a->i_qp][0] )
+    {
+        for( j=0; j<4; j++ )
+        {
+            x264_cost_mv_fpel[a->i_qp][j] = x264_malloc( (4*2048 + 1) * sizeof(int16_t) );
+            x264_cost_mv_fpel[a->i_qp][j] += 2*2048;
+            for( i = -2*2048; i < 2*2048; i++ )
+                x264_cost_mv_fpel[a->i_qp][j][i] = p_cost_mv[a->i_qp][i*4+j];
+        }
+    }
 }
 
 static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
 {
-    memset( a, 0, sizeof( x264_mb_analysis_t ) );
-
     /* conduct the analysis using this lamda and QP */
     a->i_qp = h->mb.i_qp = i_qp;
+    h->mb.i_chroma_qp = i_chroma_qp_table[x264_clip3( i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )];
     a->i_lambda = i_qp0_cost_table[i_qp];
     a->i_lambda2 = i_qp0_cost2_table[i_qp];
     a->b_mbrd = h->param.analyse.i_subpel_refine >= 6 &&
@@ -195,40 +214,78 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int 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;
-    h->mb.b_trellis = h->param.analyse.i_trellis > 1;
+    h->mb.b_trellis = h->param.analyse.i_trellis > 1 && a->b_mbrd;
     h->mb.b_transform_8x8 = 0;
+    h->mb.b_noise_reduction = 0;
 
     /* I: Intra part */
-    a->i_sad_i16x16 =
-    a->i_sad_i8x8   =
-    a->i_sad_i4x4   =
-    a->i_sad_i8x8chroma = COST_MAX;
+    a->i_satd_i16x16 =
+    a->i_satd_i8x8   =
+    a->i_satd_i4x4   =
+    a->i_satd_i8x8chroma = COST_MAX;
 
     a->b_fast_intra = 0;
-    a->i_best_satd = COST_MAX;
+    h->mb.i_skip_intra =
+        h->mb.b_lossless ? 0 :
+        a->b_mbrd ? 2 :
+        !h->param.analyse.i_trellis && !h->param.analyse.i_noise_reduction;
 
     /* II: Inter part P/B frame */
     if( h->sh.i_type != SLICE_TYPE_I )
     {
-        int i;
-        int i_fmv_range = h->param.analyse.i_mv_range - 16;
+        int i, j;
+        int i_fmv_range = 4 * h->param.analyse.i_mv_range;
+        // limit motion search to a slightly smaller range than the theoretical limit,
+        // since the search may go a few iterations past its given range
+        int i_fpel_border = 5; // umh unconditional radius
+        int i_spel_border = 8; // 1.5 for subpel_satd, 1.5 for subpel_rd, 2 for bime, round up
 
         /* 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 );
+#define CLIP_FMV(mv) x264_clip3( mv, -i_fmv_range, i_fmv_range-1 )
+        h->mb.mv_min[0] = 4*( -16*h->mb.i_mb_x - 24 );
+        h->mb.mv_max[0] = 4*( 16*( h->sps->i_mb_width - h->mb.i_mb_x - 1 ) + 24 );
+        h->mb.mv_min_spel[0] = CLIP_FMV( h->mb.mv_min[0] );
+        h->mb.mv_max_spel[0] = CLIP_FMV( h->mb.mv_max[0] );
+        h->mb.mv_min_fpel[0] = (h->mb.mv_min_spel[0]>>2) + i_fpel_border;
+        h->mb.mv_max_fpel[0] = (h->mb.mv_max_spel[0]>>2) - i_fpel_border;
         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 );
+            int mb_y = h->mb.i_mb_y >> h->sh.b_mbaff;
+            int mb_height = h->sps->i_mb_height >> h->sh.b_mbaff;
+            int thread_mvy_range = i_fmv_range;
+
+            if( h->param.i_threads > 1 )
+            {
+                int pix_y = (h->mb.i_mb_y | h->mb.b_interlaced) * 16;
+                int thresh = pix_y + h->param.analyse.i_mv_range_thread;
+                for( i = (h->sh.i_type == SLICE_TYPE_B); i >= 0; i-- )
+                {
+                    x264_frame_t **fref = i ? h->fref1 : h->fref0;
+                    int i_ref = i ? h->i_ref1 : h->i_ref0;
+                    for( j=0; j<i_ref; j++ )
+                    {
+                        x264_frame_cond_wait( fref[j], thresh );
+                        thread_mvy_range = X264_MIN( thread_mvy_range, fref[j]->i_lines_completed - pix_y );
+                    }
+                }
+                if( h->param.b_deterministic )
+                    thread_mvy_range = h->param.analyse.i_mv_range_thread;
+                if( h->mb.b_interlaced )
+                    thread_mvy_range >>= 1;
+            }
+
+            h->mb.mv_min[1] = 4*( -16*mb_y - 24 );
+            h->mb.mv_max[1] = 4*( 16*( mb_height - mb_y - 1 ) + 24 );
+            h->mb.mv_min_spel[1] = x264_clip3( h->mb.mv_min[1], X264_MAX(4*(-512+i_spel_border), -i_fmv_range), i_fmv_range );
+            h->mb.mv_max_spel[1] = CLIP_FMV( h->mb.mv_max[1] );
+            h->mb.mv_max_spel[1] = X264_MIN( h->mb.mv_max_spel[1], thread_mvy_range*4 );
+            h->mb.mv_min_fpel[1] = (h->mb.mv_min_spel[1]>>2) + i_fpel_border;
+            h->mb.mv_max_fpel[1] = (h->mb.mv_max_spel[1]>>2) - i_fpel_border;
         }
 #undef CLIP_FMV
 
         a->l0.me16x16.cost =
+        a->l0.i_rd16x16    =
         a->l0.i_cost8x8    = COST_MAX;
 
         for( i = 0; i < 4; i++ )
@@ -243,6 +300,7 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
         if( h->sh.i_type == SLICE_TYPE_B )
         {
             a->l1.me16x16.cost =
+            a->l1.i_rd16x16    =
             a->l1.i_cost8x8    = COST_MAX;
 
             for( i = 0; i < 4; i++ )
@@ -255,7 +313,11 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
 
             a->l1.i_cost16x8   =
             a->l1.i_cost8x16   =
-
+            a->i_rd16x16bi     =
+            a->i_rd16x16direct =
+            a->i_rd8x8bi       =
+            a->i_rd16x8bi      =
+            a->i_rd8x16bi      =
             a->i_cost16x16bi   =
             a->i_cost16x16direct =
             a->i_cost8x8bi     =
@@ -266,8 +328,7 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
         /* Fast intra decision */
         if( h->mb.i_mb_xy - h->sh.i_first_mb > 4 )
         {
-            if( a->b_mbrd
-               || IS_INTRA( h->mb.i_mb_type_left )
+            if(   IS_INTRA( h->mb.i_mb_type_left )
                || IS_INTRA( h->mb.i_mb_type_top )
                || IS_INTRA( h->mb.i_mb_type_topleft )
                || IS_INTRA( h->mb.i_mb_type_topright )
@@ -292,7 +353,7 @@ static void predict_16x16_mode_available( unsigned int i_neighbour, int *mode, i
 {
     if( i_neighbour & MB_TOPLEFT )
     {
-        /* top and left avaible */
+        /* top and left available */
         *mode++ = I_PRED_16x16_V;
         *mode++ = I_PRED_16x16_H;
         *mode++ = I_PRED_16x16_DC;
@@ -315,7 +376,7 @@ static void predict_16x16_mode_available( unsigned int i_neighbour, int *mode, i
     }
     else
     {
-        /* none avaible */
+        /* none available */
         *mode = I_PRED_16x16_DC_128;
         *pi_count = 1;
     }
@@ -326,7 +387,7 @@ static void predict_8x8chroma_mode_available( unsigned int i_neighbour, int *mod
 {
     if( i_neighbour & MB_TOPLEFT )
     {
-        /* top and left avaible */
+        /* top and left available */
         *mode++ = I_PRED_CHROMA_V;
         *mode++ = I_PRED_CHROMA_H;
         *mode++ = I_PRED_CHROMA_DC;
@@ -349,7 +410,7 @@ static void predict_8x8chroma_mode_available( unsigned int i_neighbour, int *mod
     }
     else
     {
-        /* none avaible */
+        /* none available */
         *mode = I_PRED_CHROMA_DC_128;
         *pi_count = 1;
     }
@@ -364,16 +425,20 @@ static void predict_4x4_mode_available( unsigned int i_neighbour,
 
     if( b_l && b_t )
     {
+        *pi_count = 6;
         *mode++ = I_PRED_4x4_DC;
         *mode++ = I_PRED_4x4_H;
         *mode++ = I_PRED_4x4_V;
         *mode++ = I_PRED_4x4_DDL;
-        *mode++ = I_PRED_4x4_DDR;
-        *mode++ = I_PRED_4x4_VR;
-        *mode++ = I_PRED_4x4_HD;
+        if( i_neighbour & MB_TOPLEFT )
+        {
+            *mode++ = I_PRED_4x4_DDR;
+            *mode++ = I_PRED_4x4_VR;
+            *mode++ = I_PRED_4x4_HD;
+            *pi_count += 3;
+        }
         *mode++ = I_PRED_4x4_VL;
         *mode++ = I_PRED_4x4_HU;
-        *pi_count = 9;
     }
     else if( b_l )
     {
@@ -402,12 +467,11 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a )
     int i;
 
     int i_max;
-    int predict_mode[9];
+    int predict_mode[4];
 
     uint8_t *p_dstc[2], *p_srcc[2];
-    int      i_stride[2];
 
-    if( a->i_sad_i8x8chroma < COST_MAX )
+    if( a->i_satd_i8x8chroma < COST_MAX )
         return;
 
     /* 8x8 prediction selection for chroma */
@@ -416,242 +480,466 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a )
     p_srcc[0] = h->mb.pic.p_fenc[1];
     p_srcc[1] = h->mb.pic.p_fenc[2];
 
-    i_stride[0] = h->mb.pic.i_stride[1];
-    i_stride[1] = h->mb.pic.i_stride[2];
-
     predict_8x8chroma_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
-    a->i_sad_i8x8chroma = COST_MAX;
-    for( i = 0; i < i_max; i++ )
+    a->i_satd_i8x8chroma = COST_MAX;
+    if( i_max == 4 && h->pixf.intra_satd_x3_8x8c && h->pixf.mbcmp[0] == h->pixf.satd[0] )
     {
-        int i_sad;
-        int i_mode;
-
-        i_mode = predict_mode[i];
-
-        /* we do the prediction */
-        h->predict_8x8c[i_mode]( p_dstc[0], i_stride[0] );
-        h->predict_8x8c[i_mode]( p_dstc[1], i_stride[1] );
-
-        /* we calculate the cost */
-        i_sad = h->pixf.mbcmp[PIXEL_8x8]( p_dstc[0], i_stride[0],
-                                          p_srcc[0], i_stride[0] ) +
-                h->pixf.mbcmp[PIXEL_8x8]( p_dstc[1], i_stride[1],
-                                          p_srcc[1], i_stride[1] ) +
-                a->i_lambda * bs_size_ue( x264_mb_pred_mode8x8c_fix[i_mode] );
+        int satdu[4], satdv[4];
+        h->pixf.intra_satd_x3_8x8c( p_srcc[0], p_dstc[0], satdu );
+        h->pixf.intra_satd_x3_8x8c( p_srcc[1], p_dstc[1], satdv );
+        h->predict_8x8c[I_PRED_CHROMA_P]( p_dstc[0] );
+        h->predict_8x8c[I_PRED_CHROMA_P]( p_dstc[1] );
+        satdu[I_PRED_CHROMA_P] =
+            h->pixf.mbcmp[PIXEL_8x8]( p_dstc[0], FDEC_STRIDE, p_srcc[0], FENC_STRIDE );
+        satdv[I_PRED_CHROMA_P] =
+            h->pixf.mbcmp[PIXEL_8x8]( p_dstc[1], FDEC_STRIDE, p_srcc[1], FENC_STRIDE );
+        
+        for( i=0; i<i_max; i++ )
+        {
+            int i_mode = predict_mode[i];
+            int i_satd = satdu[i_mode] + satdv[i_mode]
+                       + a->i_lambda * bs_size_ue(i_mode);
 
-        /* if i_score is lower it is better */
-        if( a->i_sad_i8x8chroma > i_sad )
+            a->i_satd_i8x8chroma_dir[i] = i_satd;
+            COPY2_IF_LT( a->i_satd_i8x8chroma, i_satd, a->i_predict8x8chroma, i_mode );
+        }
+    }
+    else
+    {
+        for( i=0; i<i_max; i++ )
         {
-            a->i_predict8x8chroma = i_mode;
-            a->i_sad_i8x8chroma   = i_sad;
+            int i_satd;
+            int i_mode = predict_mode[i];
+
+            /* we do the prediction */
+            h->predict_8x8c[i_mode]( p_dstc[0] );
+            h->predict_8x8c[i_mode]( p_dstc[1] );
+
+            /* we calculate the cost */
+            i_satd = h->pixf.mbcmp[PIXEL_8x8]( p_dstc[0], FDEC_STRIDE,
+                                               p_srcc[0], FENC_STRIDE ) +
+                     h->pixf.mbcmp[PIXEL_8x8]( p_dstc[1], FDEC_STRIDE,
+                                               p_srcc[1], FENC_STRIDE ) +
+                     a->i_lambda * bs_size_ue( x264_mb_pred_mode8x8c_fix[i_mode] );
+
+            a->i_satd_i8x8chroma_dir[i] = i_satd;
+            COPY2_IF_LT( a->i_satd_i8x8chroma, i_satd, a->i_predict8x8chroma, i_mode );
         }
     }
 
     h->mb.i_chroma_pred_mode = a->i_predict8x8chroma;
 }
 
-static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_cost_inter )
+static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_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];
     uint8_t  *p_src = h->mb.pic.p_fenc[0];
     uint8_t  *p_dst = h->mb.pic.p_fdec[0];
-    int      f8_satd_rd_ratio = 0;
 
     int i, idx;
     int i_max;
     int predict_mode[9];
-    int i_satd_thresh;
-
-    if( h->sh.i_type == SLICE_TYPE_B )
-        i_satd_thresh = a->i_best_satd * 9/8;
-    else
-        i_satd_thresh = a->i_best_satd * 5/4 + a->i_lambda * 10;
+    int b_merged_satd = h->pixf.intra_satd_x3_16x16 && h->pixf.mbcmp[0] == h->pixf.satd[0];
 
     /*---------------- Try all mode and calculate their score ---------------*/
 
     /* 16x16 prediction selection */
     predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
-    for( i = 0; i < i_max; i++ )
-    {
-        int i_sad;
-        int i_mode;
 
-        i_mode = predict_mode[i];
-        h->predict_16x16[i_mode]( p_dst, i_stride );
-
-        i_sad = h->pixf.mbcmp[PIXEL_16x16]( p_dst, i_stride, p_src, i_stride ) +
-                a->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
-        if( a->i_sad_i16x16 > i_sad )
+    if( b_merged_satd && i_max == 4 )
+    {
+        h->pixf.intra_satd_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir );
+        h->predict_16x16[I_PRED_16x16_P]( p_dst );
+        a->i_satd_i16x16_dir[I_PRED_16x16_P] =
+            h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE );
+        for( i=0; i<4; i++ )
         {
-            a->i_predict16x16 = i_mode;
-            a->i_sad_i16x16   = i_sad;
+            int cost = a->i_satd_i16x16_dir[i] += a->i_lambda * bs_size_ue(i);
+            COPY2_IF_LT( a->i_satd_i16x16, cost, a->i_predict16x16, i );
         }
     }
-
-    if( a->b_mbrd )
+    else
     {
-        f8_satd_rd_ratio = ((unsigned)i_cost_inter << 8) / a->i_best_satd + 1;
-        x264_mb_analyse_intra_chroma( h, a );
-        if( h->mb.b_chroma_me )
-            a->i_sad_i16x16 += a->i_sad_i8x8chroma;
-        if( a->i_sad_i16x16 < i_satd_thresh )
+        for( i = 0; i < i_max; i++ )
         {
-            h->mb.i_type = I_16x16;
-            h->mb.i_intra16x16_pred_mode = a->i_predict16x16;
-            a->i_sad_i16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+            int i_satd;
+            int i_mode = predict_mode[i];
+            h->predict_16x16[i_mode]( p_dst );
+
+            i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) +
+                    a->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
+            COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode );
+            a->i_satd_i16x16_dir[i_mode] = i_satd;
         }
-        else
-            a->i_sad_i16x16 = a->i_sad_i16x16 * f8_satd_rd_ratio >> 8;
     }
-    else
+
+    if( h->sh.i_type == SLICE_TYPE_B )
+        /* cavlc mb type prefix */
+        a->i_satd_i16x16 += a->i_lambda * i_mb_b_cost_table[I_16x16];
+    if( a->b_fast_intra && a->i_satd_i16x16 > 2*i_satd_inter )
+        return;
+
+    /* 8x8 prediction selection */
+    if( flags & X264_ANALYSE_I8x8 )
     {
+        DECLARE_ALIGNED_16( uint8_t edge[33] );
+        x264_pixel_cmp_t sa8d = (*h->pixf.mbcmp == *h->pixf.sad) ? h->pixf.sad[PIXEL_8x8] : h->pixf.sa8d[PIXEL_8x8];
+        int i_satd_thresh = a->b_mbrd ? COST_MAX : X264_MIN( i_satd_inter, a->i_satd_i16x16 );
+        int i_cost = 0;
+        b_merged_satd = h->pixf.intra_sa8d_x3_8x8 && h->pixf.mbcmp[0] == h->pixf.satd[0];
+
+        // FIXME some bias like in i4x4?
         if( h->sh.i_type == SLICE_TYPE_B )
-            /* cavlc mb type prefix */
-            a->i_sad_i16x16 += a->i_lambda * i_mb_b_cost_table[I_16x16];
-        if( a->b_fast_intra && a->i_sad_i16x16 > 2*i_cost_inter )
+            i_cost += a->i_lambda * i_mb_b_cost_table[I_8x8];
+
+        for( idx = 0;; idx++ )
+        {
+            int x = idx&1;
+            int y = idx>>1;
+            uint8_t *p_src_by = p_src + 8*x + 8*y*FENC_STRIDE;
+            uint8_t *p_dst_by = p_dst + 8*x + 8*y*FDEC_STRIDE;
+            int i_best = COST_MAX;
+            int i_pred_mode = x264_mb_predict_intra4x4_mode( h, 4*idx );
+
+            predict_4x4_mode_available( h->mb.i_neighbour8[idx], predict_mode, &i_max );
+            x264_predict_8x8_filter( p_dst_by, edge, h->mb.i_neighbour8[idx], ALL_NEIGHBORS );
+
+            if( b_merged_satd && i_max == 9 )
+            {
+                int satd[3];
+                h->pixf.intra_sa8d_x3_8x8( p_src_by, edge, satd );
+                if( i_pred_mode < 3 )
+                    satd[i_pred_mode] -= 3 * a->i_lambda;
+                for( i=2; i>=0; i-- )
+                {
+                    int cost = a->i_satd_i8x8_dir[i][idx] = satd[i] + 4 * a->i_lambda;
+                    COPY2_IF_LT( i_best, cost, a->i_predict8x8[idx], i );
+                }
+                i = 3;
+            }
+            else
+                i = 0;
+
+            for( ; i<i_max; i++ )
+            {
+                int i_satd;
+                int i_mode = predict_mode[i];
+
+                h->predict_8x8[i_mode]( p_dst_by, edge );
+
+                i_satd = sa8d( p_dst_by, FDEC_STRIDE, p_src_by, FENC_STRIDE )
+                       + a->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
+
+                COPY2_IF_LT( i_best, i_satd, a->i_predict8x8[idx], i_mode );
+                a->i_satd_i8x8_dir[i_mode][idx] = i_satd;
+            }
+            i_cost += i_best;
+
+            if( idx == 3 || i_cost > i_satd_thresh )
+                break;
+
+            /* we need to encode this block now (for next ones) */
+            h->predict_8x8[a->i_predict8x8[idx]]( p_dst_by, edge );
+            x264_mb_encode_i8x8( h, idx, a->i_qp );
+
+            x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[idx] );
+        }
+
+        if( idx == 3 )
+        {
+            a->i_satd_i8x8 = i_cost;
+            if( h->mb.i_skip_intra )
+            {
+                h->mc.copy[PIXEL_16x16]( h->mb.pic.i8x8_fdec_buf, 16, p_dst, FDEC_STRIDE, 16 );
+                if( h->mb.i_skip_intra == 2 )
+                    h->mc.memcpy_aligned( h->mb.pic.i8x8_dct_buf, h->dct.luma8x8, sizeof(h->mb.pic.i8x8_dct_buf) );
+            }
+        }
+        else
+        {
+            a->i_satd_i8x8 = COST_MAX;
+            i_cost = i_cost * 4/(idx+1);
+        }
+        if( X264_MIN(i_cost, a->i_satd_i16x16) > i_satd_inter*(5+a->b_mbrd)/4 )
             return;
     }
 
     /* 4x4 prediction selection */
     if( flags & X264_ANALYSE_I4x4 )
     {
-        a->i_sad_i4x4 = 0;
-        for( idx = 0; idx < 16; idx++ )
-        {
-            uint8_t *p_src_by;
-            uint8_t *p_dst_by;
-            int     i_best;
-            int x, y;
-            int i_pred_mode;
+        int i_cost;
+        int i_satd_thresh = X264_MIN3( i_satd_inter, a->i_satd_i16x16, a->i_satd_i8x8 );
+        b_merged_satd = h->pixf.intra_satd_x3_4x4 && h->pixf.mbcmp[0] == h->pixf.satd[0];
+        if( a->b_mbrd )
+            i_satd_thresh = i_satd_thresh * (10-a->b_fast_intra)/8;
 
-            i_pred_mode= x264_mb_predict_intra4x4_mode( h, idx );
-            x = block_idx_x[idx];
-            y = block_idx_y[idx];
+        i_cost = a->i_lambda * 24;    /* from JVT (SATD0) */
+        if( h->sh.i_type == SLICE_TYPE_B )
+            i_cost += a->i_lambda * i_mb_b_cost_table[I_4x4];
 
-            p_src_by = p_src + 4 * x + 4 * y * i_stride;
-            p_dst_by = p_dst + 4 * x + 4 * y * i_stride;
+        for( idx = 0;; idx++ )
+        {
+            int x = block_idx_x[idx];
+            int y = block_idx_y[idx];
+            uint8_t *p_src_by = p_src + 4*x + 4*y*FENC_STRIDE;
+            uint8_t *p_dst_by = p_dst + 4*x + 4*y*FDEC_STRIDE;
+            int i_best = COST_MAX;
+            int i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx );
 
-            i_best = COST_MAX;
             predict_4x4_mode_available( h->mb.i_neighbour4[idx], predict_mode, &i_max );
 
             if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP )
                 /* emulate missing topright samples */
-                *(uint32_t*) &p_dst_by[4 - i_stride] = p_dst_by[3 - i_stride] * 0x01010101U;
+                *(uint32_t*) &p_dst_by[4 - FDEC_STRIDE] = p_dst_by[3 - FDEC_STRIDE] * 0x01010101U;
 
-            for( i = 0; i < i_max; i++ )
+            if( b_merged_satd && i_max >= 6 )
             {
-                int i_sad;
-                int i_mode;
+                int satd[3];
+                h->pixf.intra_satd_x3_4x4( p_src_by, p_dst_by, satd );
+                if( i_pred_mode < 3 )
+                    satd[i_pred_mode] -= 3 * a->i_lambda;
+                for( i=2; i>=0; i-- )
+                    COPY2_IF_LT( i_best, satd[i] + 4 * a->i_lambda,
+                                 a->i_predict4x4[idx], i );
+                i = 3;
+            }
+            else
+                i = 0;
 
-                i_mode = predict_mode[i];
-                h->predict_4x4[i_mode]( p_dst_by, i_stride );
+            for( ; i<i_max; i++ )
+            {
+                int i_satd;
+                int i_mode = predict_mode[i];
 
-                i_sad = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, i_stride,
-                                                  p_src_by, i_stride )
-                      + a->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
+                h->predict_4x4[i_mode]( p_dst_by );
 
-                if( i_best > i_sad )
-                {
-                    a->i_predict4x4[x][y] = i_mode;
-                    i_best = i_sad;
-                }
+                i_satd = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, FDEC_STRIDE,
+                                                   p_src_by, FENC_STRIDE )
+                       + a->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
+
+                COPY2_IF_LT( i_best, i_satd, a->i_predict4x4[idx], i_mode );
             }
-            a->i_sad_i4x4 += i_best;
+            i_cost += i_best;
+
+            if( i_cost > i_satd_thresh || idx == 15 )
+                break;
 
             /* we need to encode this block now (for next ones) */
-            h->predict_4x4[a->i_predict4x4[x][y]]( p_dst_by, i_stride );
+            h->predict_4x4[a->i_predict4x4[idx]]( p_dst_by );
             x264_mb_encode_i4x4( h, idx, a->i_qp );
 
-            h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[x][y];
+            h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[idx];
         }
-
-        a->i_sad_i4x4 += a->i_lambda * 24;    /* from JVT (SATD0) */
-        if( a->b_mbrd )
+        if( idx == 15 )
         {
-            if( h->mb.b_chroma_me )
-                a->i_sad_i4x4 += a->i_sad_i8x8chroma;
-            if( a->i_sad_i4x4 < i_satd_thresh )
+            a->i_satd_i4x4 = i_cost;
+            if( h->mb.i_skip_intra )
             {
-                h->mb.i_type = I_4x4;
-                a->i_sad_i4x4 = x264_rd_cost_mb( h, a->i_lambda2 );
+                h->mc.copy[PIXEL_16x16]( h->mb.pic.i4x4_fdec_buf, 16, p_dst, FDEC_STRIDE, 16 );
+                if( h->mb.i_skip_intra == 2 )
+                    h->mc.memcpy_aligned( h->mb.pic.i4x4_dct_buf, h->dct.luma4x4, sizeof(h->mb.pic.i4x4_dct_buf) );
             }
-            else
-                a->i_sad_i4x4 = a->i_sad_i4x4 * f8_satd_rd_ratio >> 8;
         }
         else
+            a->i_satd_i4x4 = COST_MAX;
+    }
+}
+
+static void x264_intra_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_thresh )
+{
+    if( a->i_satd_i16x16 <= i_satd_thresh )
+    {
+        h->mb.i_type = I_16x16;
+        x264_analyse_update_cache( h, a );
+        a->i_satd_i16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    else
+        a->i_satd_i16x16 = COST_MAX;
+
+    if( a->i_satd_i4x4 <= i_satd_thresh && a->i_satd_i4x4 < COST_MAX )
+    {
+        h->mb.i_type = I_4x4;
+        x264_analyse_update_cache( h, a );
+        a->i_satd_i4x4 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    else
+        a->i_satd_i4x4 = COST_MAX;
+
+    if( a->i_satd_i8x8 <= i_satd_thresh && a->i_satd_i8x8 < COST_MAX )
+    {
+        h->mb.i_type = I_8x8;
+        x264_analyse_update_cache( h, a );
+        a->i_satd_i8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    else
+        a->i_satd_i8x8 = COST_MAX;
+}
+
+static void x264_intra_rd_refine( x264_t *h, x264_mb_analysis_t *a )
+{
+    uint8_t  *p_src = h->mb.pic.p_fenc[0];
+    uint8_t  *p_dst = h->mb.pic.p_fdec[0];
+
+    int i, j, idx, x, y;
+    int i_max, i_satd, i_best, i_mode, i_thresh;
+    int i_pred_mode;
+    int predict_mode[9];
+    h->mb.i_skip_intra = 0;
+
+    if( h->mb.i_type == I_16x16 )
+    {
+        int old_pred_mode = a->i_predict16x16;
+        i_thresh = a->i_satd_i16x16_dir[old_pred_mode] * 9/8;
+        i_best = a->i_satd_i16x16;
+        predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
+        for( i = 0; i < i_max; i++ )
         {
-            if( h->sh.i_type == SLICE_TYPE_B )
-                a->i_sad_i4x4 += a->i_lambda * i_mb_b_cost_table[I_4x4];
+            int i_mode = predict_mode[i];
+            if( i_mode == old_pred_mode || a->i_satd_i16x16_dir[i_mode] > i_thresh )
+                continue;
+            h->mb.i_intra16x16_pred_mode = i_mode;
+            i_satd = x264_rd_cost_mb( h, a->i_lambda2 );
+            COPY2_IF_LT( i_best, i_satd, a->i_predict16x16, i_mode );
         }
     }
+    else if( h->mb.i_type == I_4x4 )
+    {
+        uint32_t pels[4] = {0}; // doesn't need initting, just shuts up a gcc warning
+        int i_nnz = 0;
+        for( idx = 0; idx < 16; idx++ )
+        {
+            uint8_t *p_src_by;
+            uint8_t *p_dst_by;
+            i_best = COST_MAX;
 
-    /* 8x8 prediction selection */
-    if( flags & X264_ANALYSE_I8x8 )
+            i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx );
+            x = block_idx_x[idx];
+            y = block_idx_y[idx];
+
+            p_src_by = p_src + 4*x + 4*y*FENC_STRIDE;
+            p_dst_by = p_dst + 4*x + 4*y*FDEC_STRIDE;
+            predict_4x4_mode_available( h->mb.i_neighbour4[idx], predict_mode, &i_max );
+
+            if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP )
+                /* emulate missing topright samples */
+                *(uint32_t*) &p_dst_by[4 - FDEC_STRIDE] = p_dst_by[3 - FDEC_STRIDE] * 0x01010101U;
+
+            for( i = 0; i < i_max; i++ )
+            {
+                i_mode = predict_mode[i];
+                h->predict_4x4[i_mode]( p_dst_by );
+                i_satd = x264_rd_cost_i4x4( h, a->i_lambda2, idx, i_mode );
+
+                if( i_best > i_satd )
+                {
+                    a->i_predict4x4[idx] = i_mode;
+                    i_best = i_satd;
+                    pels[0] = *(uint32_t*)(p_dst_by+0*FDEC_STRIDE);
+                    pels[1] = *(uint32_t*)(p_dst_by+1*FDEC_STRIDE);
+                    pels[2] = *(uint32_t*)(p_dst_by+2*FDEC_STRIDE);
+                    pels[3] = *(uint32_t*)(p_dst_by+3*FDEC_STRIDE);
+                    i_nnz = h->mb.cache.non_zero_count[x264_scan8[idx]];
+                }
+            }
+
+            *(uint32_t*)(p_dst_by+0*FDEC_STRIDE) = pels[0];
+            *(uint32_t*)(p_dst_by+1*FDEC_STRIDE) = pels[1];
+            *(uint32_t*)(p_dst_by+2*FDEC_STRIDE) = pels[2];
+            *(uint32_t*)(p_dst_by+3*FDEC_STRIDE) = pels[3];
+            h->mb.cache.non_zero_count[x264_scan8[idx]] = i_nnz;
+
+            h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[idx];
+        }
+    }
+    else if( h->mb.i_type == I_8x8 )
     {
-        a->i_sad_i8x8 = 0;
+        DECLARE_ALIGNED_16( uint8_t edge[33] );
         for( idx = 0; idx < 4; idx++ )
         {
+            uint64_t pels_h = 0;
+            uint8_t pels_v[7];
+            int i_nnz[3];
             uint8_t *p_src_by;
             uint8_t *p_dst_by;
-            int     i_best;
-            int x, y;
-            int i_pred_mode;
+            int j;
+            i_thresh = a->i_satd_i8x8_dir[a->i_predict8x8[idx]][idx] * 11/8;
 
-            i_pred_mode= x264_mb_predict_intra4x4_mode( h, 4*idx );
+            i_best = COST_MAX;
+            i_pred_mode = x264_mb_predict_intra4x4_mode( h, 4*idx );
             x = idx&1;
             y = idx>>1;
 
-            p_src_by = p_src + 8 * x + 8 * y * i_stride;
-            p_dst_by = p_dst + 8 * x + 8 * y * i_stride;
-
-            i_best = COST_MAX;
+            p_src_by = p_src + 8*x + 8*y*FENC_STRIDE;
+            p_dst_by = p_dst + 8*x + 8*y*FDEC_STRIDE;
             predict_4x4_mode_available( h->mb.i_neighbour8[idx], predict_mode, &i_max );
+            x264_predict_8x8_filter( p_dst_by, edge, h->mb.i_neighbour8[idx], ALL_NEIGHBORS );
+
             for( i = 0; i < i_max; i++ )
             {
-                int i_sad;
-                int i_mode;
-
                 i_mode = predict_mode[i];
-                h->predict_8x8[i_mode]( p_dst_by, i_stride, h->mb.i_neighbour8[idx] );
+                if( a->i_satd_i8x8_dir[i_mode][idx] > i_thresh )
+                    continue;
+                h->predict_8x8[i_mode]( p_dst_by, edge );
+                i_satd = x264_rd_cost_i8x8( h, a->i_lambda2, idx, i_mode );
 
-                /* could use sa8d, but it doesn't seem worth the speed cost (without mmx at least) */
-                i_sad = h->pixf.mbcmp[PIXEL_8x8]( p_dst_by, i_stride,
-                                                  p_src_by, i_stride )
-                      + a->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
-
-                if( i_best > i_sad )
+                if( i_best > i_satd )
                 {
-                    a->i_predict8x8[x][y] = i_mode;
-                    i_best = i_sad;
+                    a->i_predict8x8[idx] = i_mode;
+                    i_best = i_satd;
+
+                    pels_h = *(uint64_t*)(p_dst_by+7*FDEC_STRIDE);
+                    if( !(idx&1) )
+                        for( j=0; j<7; j++ )
+                            pels_v[j] = p_dst_by[7+j*FDEC_STRIDE];
+                    for( j=0; j<3; j++ )
+                        i_nnz[j] = h->mb.cache.non_zero_count[x264_scan8[4*idx+j+1]];
                 }
             }
-            a->i_sad_i8x8 += i_best;
 
-            /* we need to encode this block now (for next ones) */
-            h->predict_8x8[a->i_predict8x8[x][y]]( p_dst_by, i_stride, h->mb.i_neighbour );
-            x264_mb_encode_i8x8( h, idx, a->i_qp );
+            *(uint64_t*)(p_dst_by+7*FDEC_STRIDE) = pels_h;
+            if( !(idx&1) )
+                for( j=0; j<7; j++ )
+                    p_dst_by[7+j*FDEC_STRIDE] = pels_v[j];
+            for( j=0; j<3; j++ )
+                h->mb.cache.non_zero_count[x264_scan8[4*idx+j+1]] = i_nnz[j];
 
-            x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[x][y] );
+            x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[idx] );
         }
+    }
 
-        if( a->b_mbrd )
-        {
-            if( h->mb.b_chroma_me )
-                a->i_sad_i8x8 += a->i_sad_i8x8chroma;
-            if( a->i_sad_i8x8 < i_satd_thresh )
+    /* RD selection for chroma prediction */
+    predict_8x8chroma_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
+    if( i_max > 1 )
+    {
+        i_thresh = a->i_satd_i8x8chroma * 5/4;
+
+        for( i = j = 0; i < i_max; i++ )
+            if( a->i_satd_i8x8chroma_dir[i] < i_thresh &&
+                predict_mode[i] != a->i_predict8x8chroma )
             {
-                h->mb.i_type = I_8x8;
-                a->i_sad_i8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
+                predict_mode[j++] = predict_mode[i];
             }
-            else
-                a->i_sad_i8x8 = a->i_sad_i8x8 * f8_satd_rd_ratio >> 8;
-        }
-        else
+        i_max = j;
+
+        if( i_max > 0 )
         {
-            // FIXME some bias like in i4x4?
-            if( h->sh.i_type == SLICE_TYPE_B )
-                a->i_sad_i8x8 += a->i_lambda * i_mb_b_cost_table[I_8x8];
+            int i_chroma_lambda = i_qp0_cost2_table[h->mb.i_chroma_qp];
+            /* the previous thing encoded was x264_intra_rd(), so the pixels and
+             * coefs for the current chroma mode are still around, so we only
+             * have to recount the bits. */
+            i_best = x264_rd_cost_i8x8_chroma( h, i_chroma_lambda, a->i_predict8x8chroma, 0 );
+            for( i = 0; i < i_max; i++ )
+            {
+                i_mode = predict_mode[i];
+                h->predict_8x8c[i_mode]( h->mb.pic.p_fdec[1] );
+                h->predict_8x8c[i_mode]( h->mb.pic.p_fdec[2] );
+                /* if we've already found a mode that needs no residual, then
+                 * probably any mode with a residual will be worse.
+                 * so avoid dct on the remaining modes to improve speed. */
+                i_satd = x264_rd_cost_i8x8_chroma( h, i_chroma_lambda, i_mode, h->mb.i_cbp_chroma != 0x00 );
+                COPY2_IF_LT( i_best, i_satd, a->i_predict8x8chroma, i_mode );
+            }
+            h->mb.i_chroma_pred_mode = a->i_predict8x8chroma;
         }
     }
 }
@@ -659,17 +947,18 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_cost_
 #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]];
+    (m)->p_fenc[0] = &(src)[0][(xoff)+(yoff)*FENC_STRIDE]; \
+    (m)->p_fenc[1] = &(src)[1][((xoff)>>1)+((yoff)>>1)*FENC_STRIDE]; \
+    (m)->p_fenc[2] = &(src)[2][((xoff)>>1)+((yoff)>>1)*FENC_STRIDE];
 
-#define LOAD_HPELS(m, src, xoff, yoff) \
+#define LOAD_HPELS(m, src, list, ref, 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]];
+    (m)->p_fref[5] = &(src)[5][((xoff)>>1)+((yoff)>>1)*(m)->i_stride[1]]; \
+    (m)->integral = &h->mb.pic.p_integral[list][ref][(xoff)+(yoff)*(m)->i_stride[0]];
 
 #define REF_COST(list, ref) \
     (a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l##list##_active - 1, ref ))
@@ -680,7 +969,7 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
     int i_ref;
     int mvc[7][2], i_mvc;
     int i_halfpel_thresh = INT_MAX;
-    int *p_halfpel_thresh = h->i_ref0>1 ? &i_halfpel_thresh : NULL;
+    int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL;
 
     /* 16x16 Search on all ref frame */
     m.i_pixel = PIXEL_16x16;
@@ -688,7 +977,7 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
     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++ )
+    for( i_ref = 0; i_ref < h->mb.pic.i_fref[0]; i_ref++ )
     {
         const int i_ref_cost = REF_COST( 0, i_ref );
         i_halfpel_thresh -= i_ref_cost;
@@ -696,11 +985,26 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
         m.i_ref = i_ref;
 
         /* search with ref */
-        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, 0 );
+        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 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_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );
 
+        /* early termination
+         * SSD threshold would probably be better than SATD */
+        if( i_ref == 0
+            && a->b_try_pskip
+            && m.cost-m.cost_mv < 300*a->i_lambda
+            &&  abs(m.mv[0]-h->mb.cache.pskip_mv[0])
+              + abs(m.mv[1]-h->mb.cache.pskip_mv[1]) <= 1
+            && x264_macroblock_probe_pskip( h ) )
+        {
+            h->mb.i_type = P_SKIP;
+            x264_analyse_update_cache( h, a );
+            assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
+            return;
+        }
+
         m.cost += i_ref_cost;
         i_halfpel_thresh += i_ref_cost;
 
@@ -715,14 +1019,16 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
     }
 
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref );
+    assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
 
-    if( a->b_mbrd )
+    h->mb.i_type = P_L0;
+    if( a->b_mbrd && a->l0.me16x16.i_ref == 0
+        && a->l0.me16x16.mv[0] == h->mb.cache.pskip_mv[0]
+        && a->l0.me16x16.mv[1] == h->mb.cache.pskip_mv[1] )
     {
-        a->i_best_satd = a->l0.me16x16.cost;
-        h->mb.i_type = P_L0;
         h->mb.i_partition = D_16x16;
-        x264_macroblock_cache_mv ( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv[0], a->l0.me16x16.mv[1] );
-        a->l0.me16x16.cost = x264_rd_cost_mb( h, a->i_lambda2 );
+        x264_macroblock_cache_mv( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv[0], a->l0.me16x16.mv[1] );
+        a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
     }
 }
 
@@ -732,9 +1038,9 @@ static void x264_mb_analyse_inter_p8x8_mixed_ref( x264_t *h, x264_mb_analysis_t
     int i_ref;
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
     int i_halfpel_thresh = INT_MAX;
-    int *p_halfpel_thresh = /*h->i_ref0>1 ? &i_halfpel_thresh : */NULL;
+    int *p_halfpel_thresh = /*h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : */NULL;
     int i;
-    int i_maxref = h->i_ref0-1;
+    int i_maxref = h->mb.pic.i_fref[0]-1;
 
     h->mb.i_partition = D_8x8;
 
@@ -776,7 +1082,7 @@ static void x264_mb_analyse_inter_p8x8_mixed_ref( x264_t *h, x264_mb_analysis_t
              m.i_ref_cost = i_ref_cost;
              m.i_ref = i_ref;
 
-             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 8*x8, 8*y8 );
+             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 8*x8, 8*y8 );
              x264_macroblock_cache_ref( h, 2*x8, 2*y8, 2, 2, 0, i_ref );
              x264_mb_predict_mv( h, 0, 4*i, 2, m.mvp );
              x264_me_search_ref( h, &m, a->l0.mvc[i_ref], i+1, p_halfpel_thresh );
@@ -797,15 +1103,8 @@ static void x264_mb_analyse_inter_p8x8_mixed_ref( x264_t *h, x264_mb_analysis_t
 
     a->l0.i_cost8x8 = a->l0.me8x8[0].cost + a->l0.me8x8[1].cost +
                       a->l0.me8x8[2].cost + a->l0.me8x8[3].cost;
-    if( a->b_mbrd )
-    {
-        if( a->i_best_satd > a->l0.i_cost8x8 )
-            a->i_best_satd = a->l0.i_cost8x8;
-        h->mb.i_type = P_8x8;
-        h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
-        h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
-        a->l0.i_cost8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
-    }
+    h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
+    h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
 }
 
 static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
@@ -836,7 +1135,7 @@ static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
         m->i_ref = i_ref;
 
         LOAD_FENC( m, p_fenc, 8*x8, 8*y8 );
-        LOAD_HPELS( m, p_fref, 8*x8, 8*y8 );
+        LOAD_HPELS( m, p_fref, 0, i_ref, 8*x8, 8*y8 );
         x264_mb_predict_mv( h, 0, 4*i, 2, m->mvp );
         x264_me_search( h, m, mvc, i_mvc );
 
@@ -855,22 +1154,15 @@ static void x264_mb_analyse_inter_p8x8( x264_t *h, x264_mb_analysis_t *a )
     a->l0.i_cost8x8 = a->l0.me8x8[0].cost + a->l0.me8x8[1].cost +
                       a->l0.me8x8[2].cost + a->l0.me8x8[3].cost -
                       REF_COST( 0, a->l0.me16x16.i_ref );
-    if( a->b_mbrd )
-    {
-        if( a->i_best_satd > a->l0.i_cost8x8 )
-            a->i_best_satd = a->l0.i_cost8x8;
-        h->mb.i_type = P_8x8;
-        h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
-        h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
-        a->l0.i_cost8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
-    }
+    h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
+    h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
 }
 
 static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
 {
     x264_me_t m;
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
-    int mvc[3][2];
+    DECLARE_ALIGNED_8( int mvc[3][2] );
     int i, j;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -899,7 +1191,7 @@ static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
              *(uint64_t*)mvc[1] = *(uint64_t*)a->l0.mvc[i_ref][2*i+1];
              *(uint64_t*)mvc[2] = *(uint64_t*)a->l0.mvc[i_ref][2*i+2];
 
-             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, 8*i );
+             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 0, 8*i );
              x264_macroblock_cache_ref( h, 0, 2*i, 4, 2, 0, i_ref );
              x264_mb_predict_mv( h, 0, 8*i, 4, m.mvp );
              x264_me_search( h, &m, mvc, 3 );
@@ -914,20 +1206,13 @@ static void x264_mb_analyse_inter_p16x8( x264_t *h, x264_mb_analysis_t *a )
     }
 
     a->l0.i_cost16x8 = a->l0.me16x8[0].cost + a->l0.me16x8[1].cost;
-    if( a->b_mbrd )
-    {
-        if( a->i_best_satd > a->l0.i_cost16x8 )
-            a->i_best_satd = a->l0.i_cost16x8;
-        h->mb.i_type = P_L0;
-        a->l0.i_cost16x8 = x264_rd_cost_mb( h, a->i_lambda2 );
-    }
 }
 
 static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a )
 {
     x264_me_t m;
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
-    int mvc[3][2];
+    DECLARE_ALIGNED_8( int mvc[3][2] );
     int i, j;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -955,7 +1240,7 @@ static void x264_mb_analyse_inter_p8x16( x264_t *h, x264_mb_analysis_t *a )
              *(uint64_t*)mvc[1] = *(uint64_t*)a->l0.mvc[i_ref][i+1];
              *(uint64_t*)mvc[2] = *(uint64_t*)a->l0.mvc[i_ref][i+3];
 
-             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 8*i, 0 );
+             LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 8*i, 0 );
              x264_macroblock_cache_ref( h, 2*i, 0, 2, 4, 0, i_ref );
              x264_mb_predict_mv( h, 0, 4*i, 2, m.mvp );
              x264_me_search( h, &m, mvc, 3 );
@@ -970,30 +1255,25 @@ 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;
-    if( a->b_mbrd )
-    {
-        if( a->i_best_satd > a->l0.i_cost8x16 )
-            a->i_best_satd = a->l0.i_cost8x16;
-        h->mb.i_type = P_L0;
-        a->l0.i_cost8x16 = x264_rd_cost_mb( h, a->i_lambda2 );
-    }
 }
 
 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];
+    DECLARE_ALIGNED_8( uint8_t pix1[16*8] );
+    uint8_t *pix2 = pix1+8;
     const int i_stride = h->mb.pic.i_stride[1];
-    const int off = 4*(i8x8&1) + 2*(i8x8&2)*i_stride;
+    const int or = 4*(i8x8&1) + 2*(i8x8&2)*i_stride;
+    const int oe = 4*(i8x8&1) + 2*(i8x8&2)*FENC_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 );
+    h->mc.mc_chroma( &pix1[x+y*16], 16, &p_fref[4][or+x+y*i_stride], i_stride, (me).mv[0], (me).mv[1], width, height ); \
+    h->mc.mc_chroma( &pix2[x+y*16], 16, &p_fref[5][or+x+y*i_stride], i_stride, (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][1], 2,0 );
+        CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][2], 0,2 );
         CHROMA4x4MC( 2,2, a->l0.me4x4[i8x8][3], 2,2 );
     }
     else if( pixel == PIXEL_8x4 )
@@ -1007,15 +1287,15 @@ static int x264_mb_analyse_inter_p4x4_chroma( x264_t *h, x264_mb_analysis_t *a,
         CHROMA4x4MC( 2,4, a->l0.me4x8[i8x8][1], 2,0 );
     }
 
-    return h->pixf.mbcmp[PIXEL_4x4]( &h->mb.pic.p_fenc[1][off], i_stride, pix1, 8 )
-         + h->pixf.mbcmp[PIXEL_4x4]( &h->mb.pic.p_fenc[2][off], i_stride, pix2, 8 );
+    return h->pixf.mbcmp[PIXEL_4x4]( &h->mb.pic.p_fenc[1][oe], FENC_STRIDE, pix1, 16 )
+         + h->pixf.mbcmp[PIXEL_4x4]( &h->mb.pic.p_fenc[2][oe], FENC_STRIDE, pix2, 16 );
 }
 
 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.me8x8[i8x8].i_ref];
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
-
+    const int i_ref = a->l0.me8x8[i8x8].i_ref;
     int i4x4;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -1034,7 +1314,7 @@ static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8
         m->p_cost_mv = a->p_cost_mv;
 
         LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
-        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 0, i_ref, 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 );
@@ -1045,7 +1325,7 @@ static void x264_mb_analyse_inter_p4x4( x264_t *h, x264_mb_analysis_t *a, int i8
                             a->l0.me4x4[i8x8][1].cost +
                             a->l0.me4x4[i8x8][2].cost +
                             a->l0.me4x4[i8x8][3].cost +
-                            REF_COST( 0, a->l0.me8x8[i8x8].i_ref ) +
+                            REF_COST( 0, i_ref ) +
                             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 );
@@ -1055,7 +1335,7 @@ static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8
 {
     uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.me8x8[i8x8].i_ref];
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
-
+    const int i_ref = a->l0.me8x8[i8x8].i_ref;
     int i8x4;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -1074,7 +1354,7 @@ static void x264_mb_analyse_inter_p8x4( x264_t *h, x264_mb_analysis_t *a, int i8
         m->p_cost_mv = a->p_cost_mv;
 
         LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
-        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 0, i_ref, 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 );
@@ -1082,7 +1362,7 @@ 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 +
-                            REF_COST( 0, a->l0.me8x8[i8x8].i_ref ) +
+                            REF_COST( 0, i_ref ) +
                             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 );
@@ -1092,7 +1372,7 @@ static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8
 {
     uint8_t  **p_fref = h->mb.pic.p_fref[0][a->l0.me8x8[i8x8].i_ref];
     uint8_t  **p_fenc = h->mb.pic.p_fenc;
-
+    const int i_ref = a->l0.me8x8[i8x8].i_ref;
     int i4x8;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -1111,7 +1391,7 @@ static void x264_mb_analyse_inter_p4x8( x264_t *h, x264_mb_analysis_t *a, int i8
         m->p_cost_mv = a->p_cost_mv;
 
         LOAD_FENC( m, p_fenc, 4*x4, 4*y4 );
-        LOAD_HPELS( m, p_fref, 4*x4, 4*y4 );
+        LOAD_HPELS( m, p_fref, 0, i_ref, 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 );
@@ -1119,7 +1399,7 @@ 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 +
-                            REF_COST( 0, a->l0.me8x8[i8x8].i_ref ) +
+                            REF_COST( 0, i_ref ) +
                             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 );
@@ -1132,32 +1412,20 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
 
     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;
 
-    a->i_cost16x16direct = 0;
+    a->i_cost16x16direct = a->i_lambda * i_mb_b_cost_table[B_DIRECT];
     for( i = 0; i < 4; i++ )
     {
-        const int x8 = i%2;
-        const int y8 = i/2;
-        const int off = 8 * x8 + 8 * i_stride * y8;
+        const int x = (i&1)*8;
+        const int y = (i>>1)*8;
         a->i_cost16x16direct +=
         a->i_cost8x8direct[i] =
-            h->pixf.mbcmp[PIXEL_8x8]( &p_fenc[0][off], i_stride, &p_fdec[0][off], i_stride );
+            h->pixf.mbcmp[PIXEL_8x8]( &p_fenc[0][x+y*FENC_STRIDE], FENC_STRIDE, &p_fdec[0][x+y*FDEC_STRIDE], FDEC_STRIDE );
 
         /* mb type cost */
         a->i_cost8x8direct[i] += a->i_lambda * i_sub_mb_b_cost_table[D_DIRECT_8x8];
     }
-    a->i_cost16x16direct += a->i_lambda * i_mb_b_cost_table[B_DIRECT];
-
-    if( a->b_mbrd )
-    {
-        if( a->i_cost16x16direct < a->i_best_satd )
-            a->i_best_satd = a->i_cost16x16direct;
-
-        h->mb.i_type = B_DIRECT;
-        a->i_cost16x16direct = x264_rd_cost_mb( h, a->i_lambda2 );
-    }
 }
 
 #define WEIGHTED_AVG( size, pix1, stride1, src2, stride2 ) \
@@ -1171,16 +1439,17 @@ static void x264_mb_analyse_inter_direct( x264_t *h, x264_mb_analysis_t *a )
 
 static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
 {
-    uint8_t pix1[16*16], pix2[16*16];
+    DECLARE_ALIGNED_16( uint8_t pix1[16*16] );
+    DECLARE_ALIGNED_16( uint8_t pix2[16*16] );
     uint8_t *src2;
     int stride2 = 16;
-    int src2_ref, pix1_ref;
+    int weight;
 
     x264_me_t m;
     int i_ref;
     int mvc[8][2], i_mvc;
     int i_halfpel_thresh = INT_MAX;
-    int *p_halfpel_thresh = h->i_ref0>1 ? &i_halfpel_thresh : NULL;
+    int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL;
 
     /* 16x16 Search on all ref frame */
     m.i_pixel = PIXEL_16x16;
@@ -1189,10 +1458,10 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
 
     /* ME for List 0 */
     a->l0.me16x16.cost = INT_MAX;
-    for( i_ref = 0; i_ref < h->i_ref0; i_ref++ )
+    for( i_ref = 0; i_ref < h->mb.pic.i_fref[0]; i_ref++ )
     {
         /* search with ref */
-        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, 0 );
+        LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 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_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );
@@ -1215,12 +1484,12 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
 
     /* ME for list 1 */
     i_halfpel_thresh = INT_MAX;
-    p_halfpel_thresh = h->i_ref1>1 ? &i_halfpel_thresh : NULL;
+    p_halfpel_thresh = h->mb.pic.i_fref[1]>1 ? &i_halfpel_thresh : NULL;
     a->l1.me16x16.cost = INT_MAX;
-    for( i_ref = 0; i_ref < h->i_ref1; i_ref++ )
+    for( i_ref = 0; i_ref < h->mb.pic.i_fref[1]; i_ref++ )
     {
         /* search with ref */
-        LOAD_HPELS( &m, h->mb.pic.p_fref[1][i_ref], 0, 0 );
+        LOAD_HPELS( &m, h->mb.pic.p_fref[1][i_ref], 1, i_ref, 0, 0 );
         x264_mb_predict_mv_16x16( h, 1, i_ref, m.mvp );
         x264_mb_predict_mv_ref16x16( h, 1, i_ref, mvc, &i_mvc );
         x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );
@@ -1246,42 +1515,41 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, a->l1.i_ref );
 
     /* get cost of BI mode */
+    weight = h->mb.bipred_weight[a->l0.i_ref][a->l1.i_ref];
     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;
+        src2 = 
+        h->mc.get_ref( pix2, &stride2,
+                       h->mb.pic.p_fref[0][a->l0.i_ref], h->mb.pic.i_stride[0],
+                       a->l0.me16x16.mv[0], a->l0.me16x16.mv[1],
+                       16, 16 );
+        h->mc.mc_luma( pix1, 16,
+                       h->mb.pic.p_fref[1][a->l1.i_ref], h->mb.pic.i_stride[0],
+                       a->l1.me16x16.mv[0], a->l1.me16x16.mv[1],
+                       16, 16 );
+        weight = 64 - weight;
     } 
     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;
+        h->mc.mc_luma( pix1, 16,
+                       h->mb.pic.p_fref[0][a->l0.i_ref], h->mb.pic.i_stride[0],
+                       a->l0.me16x16.mv[0], a->l0.me16x16.mv[1],
+                       16, 16 );
+        src2 =
+        h->mc.get_ref( pix2, &stride2,
+                       h->mb.pic.p_fref[1][a->l1.i_ref], h->mb.pic.i_stride[0],
+                       a->l1.me16x16.mv[0], a->l1.me16x16.mv[1],
+                       16, 16 );
     }
 
     if( h->param.analyse.b_weighted_bipred )
-        h->mc.avg_weight[PIXEL_16x16]( pix1, 16, src2, stride2,
-                h->mb.bipred_weight[pix1_ref][src2_ref] );
+        h->mc.avg_weight[PIXEL_16x16]( pix1, 16, src2, stride2, weight );
     else
         h->mc.avg[PIXEL_16x16]( pix1, 16, src2, stride2 );
 
-    a->i_cost16x16bi = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0], pix1, 16 )
+    a->i_cost16x16bi = h->pixf.mbcmp[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE, pix1, 16 )
                      + REF_COST( 0, a->l0.i_ref )
                      + REF_COST( 1, a->l1.i_ref )
                      + a->l0.me16x16.cost_mv
@@ -1291,50 +1559,6 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
     a->i_cost16x16bi   += a->i_lambda * i_mb_b_cost_table[B_BI_BI];
     a->l0.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L0_L0];
     a->l1.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L1_L1];
-
-    if( a->b_mbrd )
-    {
-        int i_satd_thresh;
-
-        if( a->l0.me16x16.cost < a->i_best_satd )
-            a->i_best_satd = a->l0.me16x16.cost;
-        if( a->l1.me16x16.cost < a->i_best_satd )
-            a->i_best_satd = a->l1.me16x16.cost;
-        if( a->i_cost16x16bi < a->i_best_satd )
-            a->i_best_satd = a->i_cost16x16bi;
-
-        i_satd_thresh = a->i_best_satd * 3/2;
-
-        h->mb.i_partition = D_16x16;
-        /* L0 */
-        if( a->l0.me16x16.cost < i_satd_thresh )
-        {
-            h->mb.i_type = B_L0_L0;
-            x264_macroblock_cache_mv( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv[0], a->l0.me16x16.mv[1] );
-            a->l0.me16x16.cost = x264_rd_cost_mb( h, a->i_lambda2 );
-        }
-        else
-            a->l0.me16x16.cost = COST_MAX;
-
-        /* L1 */
-        if( a->l1.me16x16.cost < i_satd_thresh )
-        {
-            h->mb.i_type = B_L1_L1;
-            x264_macroblock_cache_mv( h, 0, 0, 4, 4, 1, a->l1.me16x16.mv[0], a->l1.me16x16.mv[1] );
-            a->l1.me16x16.cost = x264_rd_cost_mb( h, a->i_lambda2 );
-        }
-        else
-            a->l1.me16x16.cost = COST_MAX;
-
-        /* BI */
-        if( a->i_cost16x16bi < i_satd_thresh )
-        {
-            h->mb.i_type = B_BI_BI;
-            a->i_cost16x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
-        }
-        else
-            a->i_cost16x16bi = COST_MAX;
-    }
 }
 
 static inline void x264_mb_cache_mv_p8x8( x264_t *h, x264_mb_analysis_t *a, int i )
@@ -1427,7 +1651,7 @@ 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],
           h->mb.pic.p_fref[1][a->l1.i_ref] };
-    uint8_t pix[2][8*8];
+    DECLARE_ALIGNED_8( uint8_t pix[2][8*8] );
     int i, l;
 
     /* XXX Needed for x264_mb_predict_mv */
@@ -1451,7 +1675,7 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
             m->p_cost_mv = a->p_cost_mv;
 
             LOAD_FENC( m, h->mb.pic.p_fenc, 8*x8, 8*y8 );
-            LOAD_HPELS( m, p_fref[l], 8*x8, 8*y8 );
+            LOAD_HPELS( m, p_fref[l], l, lX->i_ref, 8*x8, 8*y8 );
 
             x264_mb_predict_mv( h, l, 4*i, 2, m->mvp );
             x264_me_search( h, m, &lX->me16x16.mv, 1 );
@@ -1459,35 +1683,23 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
             x264_macroblock_cache_mv( h, 2*x8, 2*y8, 2, 2, l, m->mv[0], m->mv[1] );
 
             /* BI mode */
-            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 8,
-                            m->mv[0], m->mv[1], 8, 8 );
+            h->mc.mc_luma( pix[l], 8, m->p_fref, m->i_stride[0],
+                           m->mv[0], m->mv[1], 8, 8 );
             i_part_cost_bi += m->cost_mv;
             /* FIXME: ref cost */
         }
 
         WEIGHTED_AVG( PIXEL_8x8, pix[0], 8, pix[1], 8 );
-        i_part_cost_bi += h->pixf.mbcmp[PIXEL_8x8]( a->l0.me8x8[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 8 )
+        i_part_cost_bi += h->pixf.mbcmp[PIXEL_8x8]( a->l0.me8x8[i].p_fenc[0], FENC_STRIDE, 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;
-        if( a->l1.me8x8[i].cost < i_part_cost )
-        {
-            i_part_cost = a->l1.me8x8[i].cost;
-            h->mb.i_sub_partition[i] = D_L1_8x8;
-        }
-        if( i_part_cost_bi < i_part_cost )
-        {
-            i_part_cost = i_part_cost_bi;
-            h->mb.i_sub_partition[i] = D_BI_8x8;
-        }
-        if( a->i_cost8x8direct[i] < i_part_cost )
-        {
-            i_part_cost = a->i_cost8x8direct[i];
-            h->mb.i_sub_partition[i] = D_DIRECT_8x8;
-        }
+        COPY2_IF_LT( i_part_cost, a->l1.me8x8[i].cost, h->mb.i_sub_partition[i], D_L1_8x8 );
+        COPY2_IF_LT( i_part_cost, i_part_cost_bi, h->mb.i_sub_partition[i], D_BI_8x8 );
+        COPY2_IF_LT( i_part_cost, a->i_cost8x8direct[i], h->mb.i_sub_partition[i], D_DIRECT_8x8 );
         a->i_cost8x8bi += i_part_cost;
 
         /* XXX Needed for x264_mb_predict_mv */
@@ -1496,21 +1708,6 @@ static void x264_mb_analyse_inter_b8x8( x264_t *h, x264_mb_analysis_t *a )
 
     /* mb type cost */
     a->i_cost8x8bi += a->i_lambda * i_mb_b_cost_table[B_8x8];
-
-    if( a->b_mbrd )
-    {
-        if( a->i_cost8x8bi < a->i_best_satd )
-            a->i_best_satd = a->i_cost8x8bi;
-
-        if( a->i_cost8x8bi < a->i_best_satd * 3/2 )
-        {
-            h->mb.i_type = B_8x8;
-            h->mb.i_partition = D_8x8;
-            a->i_cost8x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
-        }
-        else
-            a->i_cost8x8bi = COST_MAX;
-    }
 }
 
 static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
@@ -1518,8 +1715,8 @@ 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],
           h->mb.pic.p_fref[1][a->l1.i_ref] };
-    uint8_t pix[2][16*8];
-    int mvc[2][2];
+    DECLARE_ALIGNED_16( uint8_t  pix[2][16*8] );
+    DECLARE_ALIGNED_8( int mvc[2][2] );
     int i, l;
 
     h->mb.i_partition = D_16x8;
@@ -1540,25 +1737,23 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
             m->p_cost_mv = a->p_cost_mv;
 
             LOAD_FENC( m, h->mb.pic.p_fenc, 0, 8*i );
-            LOAD_HPELS( m, p_fref[l], 0, 8*i );
+            LOAD_HPELS( m, p_fref[l], l, lX->i_ref, 0, 8*i );
 
-            mvc[0][0] = lX->me8x8[2*i].mv[0];
-            mvc[0][1] = lX->me8x8[2*i].mv[1];
-            mvc[1][0] = lX->me8x8[2*i+1].mv[0];
-            mvc[1][1] = lX->me8x8[2*i+1].mv[1];
+            *(uint64_t*)mvc[0] = *(uint64_t*)lX->me8x8[2*i].mv;
+            *(uint64_t*)mvc[1] = *(uint64_t*)lX->me8x8[2*i+1].mv;
 
-            x264_mb_predict_mv( h, 0, 8*i, 2, m->mvp );
+            x264_mb_predict_mv( h, l, 8*i, 2, m->mvp );
             x264_me_search( h, m, mvc, 2 );
 
             /* BI mode */
-            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 16,
-                            m->mv[0], m->mv[1], 16, 8 );
+            h->mc.mc_luma( pix[l], 16, m->p_fref, m->i_stride[0],
+                           m->mv[0], m->mv[1], 16, 8 );
             /* FIXME: ref cost */
             i_part_cost_bi += m->cost_mv;
         }
 
         WEIGHTED_AVG( PIXEL_16x8, pix[0], 16, pix[1], 16 );
-        i_part_cost_bi += h->pixf.mbcmp[PIXEL_16x8]( a->l0.me16x8[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 16 );
+        i_part_cost_bi += h->pixf.mbcmp[PIXEL_16x8]( a->l0.me16x8[i].p_fenc[0], FENC_STRIDE, 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 */
@@ -1582,29 +1777,15 @@ static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
         + (a->i_mb_partition16x8[0]>>2) * 3
         + (a->i_mb_partition16x8[1]>>2);
     a->i_cost16x8bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type16x8];
-
-    if( a->b_mbrd )
-    {
-        if( a->i_cost16x8bi < a->i_best_satd )
-            a->i_best_satd = a->i_cost16x8bi;
-
-        if( a->i_cost16x8bi < a->i_best_satd * 3/2 )
-        {
-            h->mb.i_type = a->i_mb_type16x8;
-            h->mb.i_partition = D_16x8;
-            a->i_cost16x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
-        }
-        else
-            a->i_cost16x8bi = COST_MAX;
-    }
 }
+
 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],
           h->mb.pic.p_fref[1][a->l1.i_ref] };
-    uint8_t pix[2][8*16];
-    int mvc[2][2];
+    DECLARE_ALIGNED_8( uint8_t pix[2][8*16] );
+    DECLARE_ALIGNED_8( int mvc[2][2] );
     int i, l;
 
     h->mb.i_partition = D_8x16;
@@ -1624,25 +1805,23 @@ static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
             m->p_cost_mv = a->p_cost_mv;
 
             LOAD_FENC( m, h->mb.pic.p_fenc, 8*i, 0 );
-            LOAD_HPELS( m, p_fref[l], 8*i, 0 );
+            LOAD_HPELS( m, p_fref[l], l, lX->i_ref, 8*i, 0 );
 
-            mvc[0][0] = lX->me8x8[i].mv[0];
-            mvc[0][1] = lX->me8x8[i].mv[1];
-            mvc[1][0] = lX->me8x8[i+2].mv[0];
-            mvc[1][1] = lX->me8x8[i+2].mv[1];
+            *(uint64_t*)mvc[0] = *(uint64_t*)lX->me8x8[i].mv;
+            *(uint64_t*)mvc[1] = *(uint64_t*)lX->me8x8[i+2].mv;
 
-            x264_mb_predict_mv( h, 0, 4*i, 2, m->mvp );
+            x264_mb_predict_mv( h, l, 4*i, 2, m->mvp );
             x264_me_search( h, m, mvc, 2 );
 
             /* BI mode */
-            h->mc.mc_luma( m->p_fref, m->i_stride[0], pix[l], 8,
-                            m->mv[0], m->mv[1], 8, 16 );
+            h->mc.mc_luma( pix[l], 8, m->p_fref, m->i_stride[0],
+                           m->mv[0], m->mv[1], 8, 16 );
             /* FIXME: ref cost */
             i_part_cost_bi += m->cost_mv;
         }
 
         WEIGHTED_AVG( PIXEL_8x16, pix[0], 8, pix[1], 8 );
-        i_part_cost_bi += h->pixf.mbcmp[PIXEL_8x16]( a->l0.me8x16[i].p_fenc[0], h->mb.pic.i_stride[0], pix[0], 8 );
+        i_part_cost_bi += h->pixf.mbcmp[PIXEL_8x16]( a->l0.me8x16[i].p_fenc[0], FENC_STRIDE, pix[0], 8 );
 
         i_part_cost = a->l0.me8x16[i].cost;
         a->i_mb_partition8x16[i] = D_L0_8x8;
@@ -1666,66 +1845,206 @@ static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
         + (a->i_mb_partition8x16[0]>>2) * 3
         + (a->i_mb_partition8x16[1]>>2);
     a->i_cost8x16bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type8x16];
+}
 
-    if( a->b_mbrd )
+static void x264_mb_analyse_p_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd )
+{
+    int thresh = i_satd * 5/4;
+
+    h->mb.i_type = P_L0;
+    if( a->l0.i_rd16x16 == COST_MAX && a->l0.me16x16.cost <= i_satd * 3/2 )
     {
-        if( a->i_cost8x16bi < a->i_best_satd )
-            a->i_best_satd = a->i_cost8x16bi;
+        h->mb.i_partition = D_16x16;
+        x264_analyse_update_cache( h, a );
+        a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    a->l0.me16x16.cost = a->l0.i_rd16x16;
 
-        if( a->i_cost8x16bi < a->i_best_satd * 3/2 )
+    if( a->l0.i_cost16x8 <= thresh )
+    {
+        h->mb.i_partition = D_16x8;
+        x264_analyse_update_cache( h, a );
+        a->l0.i_cost16x8 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    else
+        a->l0.i_cost16x8 = COST_MAX;
+
+    if( a->l0.i_cost8x16 <= thresh )
+    {
+        h->mb.i_partition = D_8x16;
+        x264_analyse_update_cache( h, a );
+        a->l0.i_cost8x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+    else
+        a->l0.i_cost8x16 = COST_MAX;
+
+    if( a->l0.i_cost8x8 <= thresh )
+    {
+        h->mb.i_type = P_8x8;
+        x264_analyse_update_cache( h, a );
+        a->l0.i_cost8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
+
+        if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 )
         {
-            h->mb.i_type = a->i_mb_type8x16;
-            h->mb.i_partition = D_8x16;
-            a->i_cost8x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
+            /* FIXME: RD per subpartition */
+            int part_bak[4];
+            int i, i_cost;
+            int b_sub8x8 = 0;
+            for( i=0; i<4; i++ )
+            {
+                part_bak[i] = h->mb.i_sub_partition[i];
+                b_sub8x8 |= (part_bak[i] != D_L0_8x8);
+            }
+            if( b_sub8x8 )
+            {
+                h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
+                h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
+                i_cost = x264_rd_cost_mb( h, a->i_lambda2 );
+                if( a->l0.i_cost8x8 < i_cost )
+                {
+                    for( i=0; i<4; i++ )
+                        h->mb.i_sub_partition[i] = part_bak[i];
+                }
+                else
+                   a->l0.i_cost8x8 = i_cost;
+            }
         }
-        else
-            a->i_cost8x16bi = COST_MAX;
     }
+    else
+        a->l0.i_cost8x8 = COST_MAX;
 }
 
-static inline void x264_mb_analyse_transform( x264_t *h )
+static void x264_mb_analyse_b_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter )
 {
-    h->mb.cache.b_transform_8x8_allowed =
-        h->param.analyse.b_transform_8x8
-        && !IS_INTRA( h->mb.i_type ) && x264_mb_transform_8x8_allowed( h );
+    int thresh = i_satd_inter * 17/16;
+
+    if( a->b_direct_available && a->i_rd16x16direct == COST_MAX )
+    {
+        h->mb.i_type = B_DIRECT;
+        x264_analyse_update_cache( h, a );
+        a->i_rd16x16direct = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+
+    //FIXME not all the update_cache calls are needed
+    h->mb.i_partition = D_16x16;
+    /* L0 */
+    if( a->l0.me16x16.cost <= thresh && a->l0.i_rd16x16 == COST_MAX )
+    {
+        h->mb.i_type = B_L0_L0;
+        x264_analyse_update_cache( h, a );
+        a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
 
-    if( h->mb.cache.b_transform_8x8_allowed )
+    /* L1 */
+    if( a->l1.me16x16.cost <= thresh && a->l1.i_rd16x16 == COST_MAX )
+    {
+        h->mb.i_type = B_L1_L1;
+        x264_analyse_update_cache( h, a );
+        a->l1.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+
+    /* BI */
+    if( a->i_cost16x16bi <= thresh && a->i_rd16x16bi == COST_MAX )
+    {
+        h->mb.i_type = B_BI_BI;
+        x264_analyse_update_cache( h, a );
+        a->i_rd16x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+
+    /* 8x8 */
+    if( a->i_cost8x8bi <= thresh && a->i_rd8x8bi == COST_MAX )
+    {
+        h->mb.i_type = B_8x8;
+        h->mb.i_partition = D_8x8;
+        x264_analyse_update_cache( h, a );
+        a->i_rd8x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
+        x264_macroblock_cache_skip( h, 0, 0, 4, 4, 0 );
+    }
+
+    /* 16x8 */
+    if( a->i_cost16x8bi <= thresh && a->i_rd16x8bi == COST_MAX )
+    {
+        h->mb.i_type = a->i_mb_type16x8;
+        h->mb.i_partition = D_16x8;
+        x264_analyse_update_cache( h, a );
+        a->i_rd16x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+
+    /* 8x16 */
+    if( a->i_cost8x16bi <= thresh && a->i_rd8x16bi == COST_MAX )
+    {
+        h->mb.i_type = a->i_mb_type8x16;
+        h->mb.i_partition = D_8x16;
+        x264_analyse_update_cache( h, a );
+        a->i_rd8x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
+    }
+}
+
+static void refine_bidir( x264_t *h, x264_mb_analysis_t *a )
+{
+    const int i_biweight = h->mb.bipred_weight[a->l0.i_ref][a->l1.i_ref];
+    int i;
+
+    switch( h->mb.i_partition )
+    {
+    case D_16x16:
+        if( h->mb.i_type == B_BI_BI )
+            x264_me_refine_bidir( h, &a->l0.me16x16, &a->l1.me16x16, i_biweight );
+        break;
+    case D_16x8:
+        for( i=0; i<2; i++ )
+            if( a->i_mb_partition16x8[i] == D_BI_8x8 )
+                x264_me_refine_bidir( h, &a->l0.me16x8[i], &a->l1.me16x8[i], i_biweight );
+        break;
+    case D_8x16:
+        for( i=0; i<2; i++ )
+            if( a->i_mb_partition8x16[i] == D_BI_8x8 )
+                x264_me_refine_bidir( h, &a->l0.me8x16[i], &a->l1.me8x16[i], i_biweight );
+        break;
+    case D_8x8:
+        for( i=0; i<4; i++ )
+            if( h->mb.i_sub_partition[i] == D_BI_8x8 )
+                x264_me_refine_bidir( h, &a->l0.me8x8[i], &a->l1.me8x8[i], i_biweight );
+        break;
+    }
+}
+
+static inline void x264_mb_analyse_transform( x264_t *h )
+{
+    if( x264_mb_transform_8x8_allowed( h ) && h->param.analyse.b_transform_8x8 )
     {
         int i_cost4, i_cost8;
         /* FIXME only luma mc is needed */
         x264_mb_mc( h );
 
-        i_cost8 = h->pixf.sa8d[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0],
-                                             h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0] );
-        i_cost4 = h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0],
-                                             h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0] );
+        i_cost8 = h->pixf.sa8d[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE,
+                                             h->mb.pic.p_fdec[0], FDEC_STRIDE );
+        i_cost4 = h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE,
+                                             h->mb.pic.p_fdec[0], FDEC_STRIDE );
 
         h->mb.b_transform_8x8 = i_cost8 < i_cost4;
     }
 }
 
-static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t *a, int *i_cost )
+static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t *a, int *i_satd, int *i_rd )
 {
-    h->mb.cache.b_transform_8x8_allowed =
-        h->param.analyse.b_transform_8x8 && x264_mb_transform_8x8_allowed( h );
-
-    if( h->mb.cache.b_transform_8x8_allowed )
+    if( x264_mb_transform_8x8_allowed( h ) && h->param.analyse.b_transform_8x8 )
     {
-        int i_cost8;
+        int i_rd8;
         x264_analyse_update_cache( h, a );
         h->mb.b_transform_8x8 = !h->mb.b_transform_8x8;
         /* FIXME only luma is needed, but the score for comparison already includes chroma */
-        i_cost8 = x264_rd_cost_mb( h, a->i_lambda2 );
+        i_rd8 = x264_rd_cost_mb( h, a->i_lambda2 );
 
-        if( *i_cost >= i_cost8 )
+        if( *i_rd >= i_rd8 )
         {
-            if( *i_cost > 0 )
-                a->i_best_satd = (int64_t)a->i_best_satd * i_cost8 / *i_cost;
-            /* prevent a rare division by zero in x264_mb_analyse_intra */
-            if( a->i_best_satd == 0 )
-                a->i_best_satd = 1;
+            if( *i_rd > 0 )
+                *i_satd = (int64_t)(*i_satd) * i_rd8 / *i_rd;
+            /* prevent a rare division by zero in estimated intra cost */
+            if( *i_satd == 0 )
+                *i_satd = 1;
 
-            *i_cost = i_cost8;
+            *i_rd = i_rd8;
         }
         else
             h->mb.b_transform_8x8 = !h->mb.b_transform_8x8;
@@ -1742,43 +2061,62 @@ void x264_macroblock_analyse( x264_t *h )
     int i_cost = COST_MAX;
     int i;
 
-    /* init analysis */
-    x264_mb_analyse_init( h, &analysis, x264_ratecontrol_qp( h ) );
+    h->mb.i_qp = x264_ratecontrol_qp( h );
+    if( h->param.rc.i_aq_mode )
+        x264_adaptive_quant( h );
+
+    x264_mb_analyse_init( h, &analysis, h->mb.i_qp );
 
     /*--------------------------- Do the analysis ---------------------------*/
     if( h->sh.i_type == SLICE_TYPE_I )
     {
         x264_mb_analyse_intra( h, &analysis, COST_MAX );
+        if( analysis.b_mbrd )
+            x264_intra_rd( h, &analysis, COST_MAX );
 
-        i_cost = analysis.i_sad_i16x16;
+        i_cost = analysis.i_satd_i16x16;
         h->mb.i_type = I_16x16;
-        if( analysis.i_sad_i4x4 < i_cost )
+        if( analysis.i_satd_i4x4 < i_cost )
         {
-            i_cost = analysis.i_sad_i4x4;
+            i_cost = analysis.i_satd_i4x4;
             h->mb.i_type = I_4x4;
         }
-        if( analysis.i_sad_i8x8 < i_cost )
+        if( analysis.i_satd_i8x8 < i_cost )
             h->mb.i_type = I_8x8;
+
+        if( h->mb.i_subpel_refine >= 7 )
+            x264_intra_rd_refine( h, &analysis );
     }
     else if( h->sh.i_type == SLICE_TYPE_P )
     {
         int b_skip = 0;
         int i_intra_cost, i_intra_type;
 
+        h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );
+
         /* Fast P_SKIP detection */
-        if( h->param.analyse.b_fast_pskip &&
-           (( h->mb.i_mb_type_left == P_SKIP ) ||
-            ( h->mb.i_mb_type_top == P_SKIP ) ||
-            ( h->mb.i_mb_type_topleft == P_SKIP ) ||
-            ( h->mb.i_mb_type_topright == P_SKIP )))
+        analysis.b_try_pskip = 0;
+        if( h->param.analyse.b_fast_pskip )
         {
-            b_skip = x264_macroblock_probe_pskip( h );
+            if( h->param.i_threads > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1] )
+                // FIXME don't need to check this if the reference frame is done
+                {}
+            else if( h->param.analyse.i_subpel_refine >= 3 )
+                analysis.b_try_pskip = 1;
+            else if( h->mb.i_mb_type_left == P_SKIP ||
+                     h->mb.i_mb_type_top == P_SKIP ||
+                     h->mb.i_mb_type_topleft == P_SKIP ||
+                     h->mb.i_mb_type_topright == P_SKIP )
+                b_skip = x264_macroblock_probe_pskip( h );
         }
 
+        h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 );
+
         if( b_skip )
         {
             h->mb.i_type = P_SKIP;
             h->mb.i_partition = D_16x16;
+            assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
         }
         else
         {
@@ -1786,12 +2124,13 @@ void x264_macroblock_analyse( x264_t *h )
             int i_type;
             int i_partition;
             int i_thresh16x8;
+            int i_satd_inter, i_satd_intra;
 
             x264_mb_analyse_load_costs( h, &analysis );
 
             x264_mb_analyse_inter_p16x16( h, &analysis );
 
-            if( analysis.b_mbrd && h->mb.i_type == P_SKIP )
+            if( h->mb.i_type == P_SKIP )
                 return;
 
             if( flags & X264_ANALYSE_PSUB16x16 )
@@ -1810,20 +2149,13 @@ void x264_macroblock_analyse( x264_t *h )
             if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
                 analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost )
             {
-                int i;
-
                 i_type = P_8x8;
                 i_partition = D_8x8;
-                h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
-                h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
-
                 i_cost = analysis.l0.i_cost8x8;
 
                 /* Do sub 8x8 */
                 if( flags & X264_ANALYSE_PSUB8x8 )
                 {
-                    int i_cost_bak = i_cost;
-                    int b_sub8x8 = 0;
                     for( i = 0; i < 4; i++ )
                     {
                         x264_mb_analyse_inter_p4x4( h, &analysis, i );
@@ -1833,60 +2165,31 @@ void x264_macroblock_analyse( x264_t *h )
                             h->mb.i_sub_partition[i] = D_L0_4x4;
 
                             x264_mb_analyse_inter_p8x4( h, &analysis, i );
-                            if( analysis.l0.i_cost8x4[i] < i_cost8x8 )
-                            {
-                                h->mb.i_sub_partition[i] = D_L0_8x4;
-                                i_cost8x8 = analysis.l0.i_cost8x4[i];
-                            }
+                            COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost8x4[i],
+                                         h->mb.i_sub_partition[i], D_L0_8x4 );
 
                             x264_mb_analyse_inter_p4x8( h, &analysis, i );
-                            if( analysis.l0.i_cost4x8[i] < i_cost8x8 )
-                            {
-                                h->mb.i_sub_partition[i] = D_L0_4x8;
-                                i_cost8x8 = analysis.l0.i_cost4x8[i];
-                            }
+                            COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost4x8[i],
+                                         h->mb.i_sub_partition[i], D_L0_4x8 );
 
                             i_cost += i_cost8x8 - analysis.l0.me8x8[i].cost;
-                            b_sub8x8 = 1;
                         }
                         x264_mb_cache_mv_p8x8( h, &analysis, i );
                     }
-                    /* TODO: RD per subpartition */
-                    if( b_sub8x8 && analysis.b_mbrd )
-                    {
-                        i_cost = x264_rd_cost_mb( h, analysis.i_lambda2 );
-                        if( i_cost > i_cost_bak )
-                        {
-                            i_cost = i_cost_bak;
-                            h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
-                            h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
-                        }
-                    }
+                    analysis.l0.i_cost8x8 = i_cost;
                 }
             }
 
             /* Now do 16x8/8x16 */
             i_thresh16x8 = analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[2].cost_mv;
-            if( analysis.b_mbrd )
-                i_thresh16x8 = i_thresh16x8 * analysis.i_lambda2 / analysis.i_lambda;
             if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
                 analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost + i_thresh16x8 )
             {
                 x264_mb_analyse_inter_p16x8( h, &analysis );
-                if( analysis.l0.i_cost16x8 < i_cost )
-                {
-                    i_type = P_L0;
-                    i_partition = D_16x8;
-                    i_cost = analysis.l0.i_cost16x8;
-                }
+                COPY3_IF_LT( i_cost, analysis.l0.i_cost16x8, i_type, P_L0, i_partition, D_16x8 );
 
                 x264_mb_analyse_inter_p8x16( h, &analysis );
-                if( analysis.l0.i_cost8x16 < i_cost )
-                {
-                    i_type = P_L0;
-                    i_partition = D_8x16;
-                    i_cost = analysis.l0.i_cost8x16;
-                }
+                COPY3_IF_LT( i_cost, analysis.l0.i_cost8x16, i_type, P_L0, i_partition, D_8x16 );
             }
 
             h->mb.i_partition = i_partition;
@@ -1895,8 +2198,7 @@ void x264_macroblock_analyse( x264_t *h )
             //FIXME mb_type costs?
             if( analysis.b_mbrd )
             {
-                h->mb.i_type = i_type;
-                x264_mb_analyse_transform_rd( h, &analysis, &i_cost );
+                /* refine later */
             }
             else if( i_partition == D_16x16 )
             {
@@ -1957,41 +2259,86 @@ void x264_macroblock_analyse( x264_t *h )
                 }
             }
 
-            x264_mb_analyse_intra( h, &analysis, i_cost );
-            if( h->mb.b_chroma_me && !analysis.b_mbrd &&
-                ( analysis.i_sad_i16x16 < i_cost
-               || analysis.i_sad_i8x8 < i_cost
-               || analysis.i_sad_i4x4 < i_cost ))
+            if( h->mb.b_chroma_me )
             {
                 x264_mb_analyse_intra_chroma( h, &analysis );
-                analysis.i_sad_i16x16 += analysis.i_sad_i8x8chroma;
-                analysis.i_sad_i8x8 += analysis.i_sad_i8x8chroma;
-                analysis.i_sad_i4x4 += analysis.i_sad_i8x8chroma;
+                x264_mb_analyse_intra( h, &analysis, i_cost - analysis.i_satd_i8x8chroma );
+                analysis.i_satd_i16x16 += analysis.i_satd_i8x8chroma;
+                analysis.i_satd_i8x8 += analysis.i_satd_i8x8chroma;
+                analysis.i_satd_i4x4 += analysis.i_satd_i8x8chroma;
             }
+            else
+                x264_mb_analyse_intra( h, &analysis, i_cost );
 
-            i_intra_type = I_16x16;
-            i_intra_cost = analysis.i_sad_i16x16;
+            i_satd_inter = i_cost;
+            i_satd_intra = X264_MIN3( analysis.i_satd_i16x16,
+                                      analysis.i_satd_i8x8,
+                                      analysis.i_satd_i4x4 );
 
-            if( analysis.i_sad_i8x8 < i_intra_cost )
-            {
-                i_intra_type = I_8x8;
-                i_intra_cost = analysis.i_sad_i8x8;
-            }
-            if( analysis.i_sad_i4x4 < i_intra_cost )
+            if( analysis.b_mbrd )
             {
-                i_intra_type = I_4x4;
-                i_intra_cost = analysis.i_sad_i4x4;
+                x264_mb_analyse_p_rd( h, &analysis, X264_MIN(i_satd_inter, i_satd_intra) );
+                i_type = P_L0;
+                i_partition = D_16x16;
+                i_cost = analysis.l0.me16x16.cost;
+                COPY2_IF_LT( i_cost, analysis.l0.i_cost16x8, i_partition, D_16x8 );
+                COPY2_IF_LT( i_cost, analysis.l0.i_cost8x16, i_partition, D_8x16 );
+                COPY3_IF_LT( i_cost, analysis.l0.i_cost8x8, i_partition, D_8x8, i_type, P_8x8 );
+                h->mb.i_type = i_type;
+                h->mb.i_partition = i_partition;
+                if( i_cost < COST_MAX )
+                    x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost );
+                x264_intra_rd( h, &analysis, i_satd_inter * 5/4 );
             }
 
-            if( i_intra_cost < i_cost )
-            {
-                i_type = i_intra_type;
-                i_cost = i_intra_cost;
-            }
+            i_intra_type = I_16x16;
+            i_intra_cost = analysis.i_satd_i16x16;
+            COPY2_IF_LT( i_intra_cost, analysis.i_satd_i8x8, i_intra_type, I_8x8 );
+            COPY2_IF_LT( i_intra_cost, analysis.i_satd_i4x4, i_intra_type, I_4x4 );
+            COPY2_IF_LT( i_cost, i_intra_cost, i_type, i_intra_type );
+
+            if( i_intra_cost == COST_MAX )
+                i_intra_cost = i_cost * i_satd_intra / i_satd_inter + 1;
 
             h->mb.i_type = i_type;
             h->stat.frame.i_intra_cost += i_intra_cost;
             h->stat.frame.i_inter_cost += i_cost;
+            h->stat.frame.i_mbs_analysed++;
+
+            if( h->mb.i_subpel_refine >= 7 )
+            {
+                if( IS_INTRA( h->mb.i_type ) )
+                {
+                    x264_intra_rd_refine( h, &analysis );
+                }
+                else if( i_partition == D_16x16 )
+                {
+                    x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, analysis.l0.me16x16.i_ref );
+                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0 );
+                }
+                else if( i_partition == D_16x8 )
+                {
+                    x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].i_ref );
+                    x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].i_ref );
+                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[0], analysis.i_lambda2, 0 );
+                    x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[1], analysis.i_lambda2, 2 );
+                }
+                else if( i_partition == D_8x16 )
+                {
+                    x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].i_ref );
+                    x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].i_ref );
+                    x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[0], analysis.i_lambda2, 0 );
+                    x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[1], analysis.i_lambda2, 1 );
+                }
+                else if( i_partition == D_8x8 )
+                {
+                    int i8x8;
+                    x264_analyse_update_cache( h, &analysis );
+                    for( i8x8 = 0; i8x8 < 4; i8x8++ )
+                         if( h->mb.i_sub_partition[i8x8] == D_L0_8x8 )
+                             x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i8x8], analysis.i_lambda2, i8x8 );
+                }
+            }
         }
     }
     else if( h->sh.i_type == SLICE_TYPE_B )
@@ -1999,33 +2346,56 @@ void x264_macroblock_analyse( x264_t *h )
         int i_bskip_cost = COST_MAX;
         int b_skip = 0;
 
-        analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h );
+        h->mb.i_type = B_SKIP;
+        if( h->mb.b_direct_auto_write )
+        {
+            /* direct=auto heuristic: prefer whichever mode allows more Skip macroblocks */
+            for( i = 0; i < 2; i++ )
+            {
+                int b_changed = 1;
+                h->sh.b_direct_spatial_mv_pred ^= 1;
+                analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, i && analysis.b_direct_available ? &b_changed : NULL );
+                if( analysis.b_direct_available )
+                {
+                    if( b_changed )
+                    {
+                        x264_mb_mc( h );
+                        b_skip = x264_macroblock_probe_bskip( h );
+                    }
+                    h->stat.frame.i_direct_score[ h->sh.b_direct_spatial_mv_pred ] += b_skip;
+                }
+                else
+                    b_skip = 0;
+            }
+        }
+        else
+            analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, NULL );
+
         if( analysis.b_direct_available )
         {
-            h->mb.i_type = B_SKIP;
-            x264_mb_mc( h );
-            if( analysis.b_mbrd )
+            if( !h->mb.b_direct_auto_write )
+                x264_mb_mc( h );
+            if( h->mb.b_lossless )
+            {
+                /* chance of skip is too small to bother */
+            }
+            else if( analysis.b_mbrd )
             {
-                i_bskip_cost = h->pixf.ssd[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0],
-                                                         h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0] )
-                             + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[1], h->mb.pic.i_stride[1],
-                                                         h->mb.pic.p_fdec[1], h->mb.pic.i_stride[1] )
-                             + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[2], h->mb.pic.i_stride[2],
-                                                         h->mb.pic.p_fdec[2], h->mb.pic.i_stride[2] );
+                i_bskip_cost = ssd_mb( h );
 
                 /* 6 = minimum cavlc cost of a non-skipped MB */
-                if( i_bskip_cost <= 6 * analysis.i_lambda2 )
+                if( i_bskip_cost <= ((6 * analysis.i_lambda2 + 128) >> 8) )
                 {
                     h->mb.i_type = B_SKIP;
                     x264_analyse_update_cache( h, &analysis );
                     return;
                 }
             }
-            else
+            else if( !h->mb.b_direct_auto_write )
             {
                 /* Conditioning the probe on neighboring block types
                  * doesn't seem to help speed or quality. */
-                b_skip = !h->mb.b_lossless && x264_macroblock_probe_bskip( h );
+                b_skip = x264_macroblock_probe_bskip( h );
             }
         }
 
@@ -2047,27 +2417,22 @@ void x264_macroblock_analyse( x264_t *h )
             i_type = B_L0_L0;
             i_partition = D_16x16;
             i_cost = analysis.l0.me16x16.cost;
-            if( analysis.l1.me16x16.cost < i_cost )
-            {
-                i_type = B_L1_L1;
-                i_cost = analysis.l1.me16x16.cost;
-            }
-            if( analysis.i_cost16x16bi < i_cost )
-            {
-                i_type = B_BI_BI;
-                i_cost = analysis.i_cost16x16bi;
-            }
-            if( analysis.i_cost16x16direct < i_cost )
-            {
-                i_type = B_DIRECT;
-                i_cost = analysis.i_cost16x16direct;
-            }
+            COPY2_IF_LT( i_cost, analysis.l1.me16x16.cost, i_type, B_L1_L1 );
+            COPY2_IF_LT( i_cost, analysis.i_cost16x16bi, i_type, B_BI_BI );
+            COPY2_IF_LT( i_cost, analysis.i_cost16x16direct, i_type, B_DIRECT );
 
-            if( i_bskip_cost <= i_cost )
+            if( analysis.b_mbrd && analysis.i_cost16x16direct <= i_cost * 33/32 )
             {
-                h->mb.i_type = B_SKIP;
-                x264_analyse_update_cache( h, &analysis );
-                return;
+                x264_mb_analyse_b_rd( h, &analysis, i_cost );
+                if( i_bskip_cost < analysis.i_rd16x16direct &&
+                    i_bskip_cost < analysis.i_rd16x16bi &&
+                    i_bskip_cost < analysis.l0.i_rd16x16 &&
+                    i_bskip_cost < analysis.l1.i_rd16x16 )
+                {
+                    h->mb.i_type = B_SKIP;
+                    x264_analyse_update_cache( h, &analysis );
+                    return;
+                }
             }
 
             if( flags & X264_ANALYSE_BSUB16x16 )
@@ -2083,33 +2448,24 @@ void x264_macroblock_analyse( x264_t *h )
                         h->mb.i_sub_partition[2] == h->mb.i_sub_partition[3] )
                     {
                         x264_mb_analyse_inter_b16x8( h, &analysis );
-                        if( analysis.i_cost16x8bi < i_cost )
-                        {
-                            i_partition = D_16x8;
-                            i_cost = analysis.i_cost16x8bi;
-                            i_type = analysis.i_mb_type16x8;
-                        }
+                        COPY3_IF_LT( i_cost, analysis.i_cost16x8bi,
+                                     i_type, analysis.i_mb_type16x8,
+                                     i_partition, D_16x8 );
                     }
                     if( h->mb.i_sub_partition[0] == h->mb.i_sub_partition[2] ||
                         h->mb.i_sub_partition[1] == h->mb.i_sub_partition[3] )
                     {
                         x264_mb_analyse_inter_b8x16( h, &analysis );
-                        if( analysis.i_cost8x16bi < i_cost )
-                        {
-                            i_partition = D_8x16;
-                            i_cost = analysis.i_cost8x16bi;
-                            i_type = analysis.i_mb_type8x16;
-                        }
+                        COPY3_IF_LT( i_cost, analysis.i_cost8x16bi,
+                                     i_type, analysis.i_mb_type8x16,
+                                     i_partition, D_8x16 );
                     }
                 }
             }
 
-            h->mb.i_partition = i_partition;
-
             if( analysis.b_mbrd )
             {
-                h->mb.i_type = i_type;
-                x264_mb_analyse_transform_rd( h, &analysis, &i_cost );
+                /* refine later */
             }
             /* refine qpel */
             else if( i_partition == D_16x16 )
@@ -2190,26 +2546,40 @@ void x264_macroblock_analyse( x264_t *h )
                 }
             }
 
-            /* best intra mode */
             x264_mb_analyse_intra( h, &analysis, i_cost );
 
-            if( analysis.i_sad_i16x16 < i_cost )
-            {
-                i_type = I_16x16;
-                i_cost = analysis.i_sad_i16x16;
-            }
-            if( analysis.i_sad_i8x8 < i_cost )
-            {
-                i_type = I_8x8;
-                i_cost = analysis.i_sad_i8x8;
-            }
-            if( analysis.i_sad_i4x4 < i_cost )
+            if( analysis.b_mbrd )
             {
-                i_type = I_4x4;
-                i_cost = analysis.i_sad_i4x4;
+                int i_satd_inter = i_cost;
+                x264_mb_analyse_b_rd( h, &analysis, i_satd_inter );
+                i_type = B_SKIP;
+                i_cost = i_bskip_cost;
+                i_partition = D_16x16;
+                COPY2_IF_LT( i_cost, analysis.l0.i_rd16x16, i_type, B_L0_L0 );
+                COPY2_IF_LT( i_cost, analysis.l1.i_rd16x16, i_type, B_L1_L1 );
+                COPY2_IF_LT( i_cost, analysis.i_rd16x16bi, i_type, B_BI_BI );
+                COPY2_IF_LT( i_cost, analysis.i_rd16x16direct, i_type, B_DIRECT );
+                COPY3_IF_LT( i_cost, analysis.i_rd16x8bi, i_type, analysis.i_mb_type16x8, i_partition, D_16x8 );
+                COPY3_IF_LT( i_cost, analysis.i_rd8x16bi, i_type, analysis.i_mb_type8x16, i_partition, D_8x16 );
+                COPY3_IF_LT( i_cost, analysis.i_rd8x8bi, i_type, B_8x8, i_partition, D_8x8 );
+
+                h->mb.i_type = i_type;
+                h->mb.i_partition = i_partition;
+                x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost );
+                x264_intra_rd( h, &analysis, i_satd_inter * 17/16 );
             }
 
+            COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 );
+            COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 );
+            COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 );
+
             h->mb.i_type = i_type;
+            h->mb.i_partition = i_partition;
+
+            if( h->mb.i_subpel_refine >= 7 && IS_INTRA( i_type ) )
+                x264_intra_rd_refine( h, &analysis );
+            else if( h->param.analyse.b_bidir_me )
+                refine_bidir( h, &analysis );
         }
     }
 
@@ -2219,6 +2589,9 @@ void x264_macroblock_analyse( x264_t *h )
         x264_mb_analyse_transform( h );
 
     h->mb.b_trellis = h->param.analyse.i_trellis;
+    h->mb.b_noise_reduction = h->param.analyse.i_noise_reduction;
+    if( h->mb.b_trellis == 1 || h->mb.b_noise_reduction )
+        h->mb.i_skip_intra = 0;
 }
 
 /*-------------------- Update MB from the analysis ----------------------*/
@@ -2230,17 +2603,13 @@ static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a  )
     {
         case I_4x4:
             for( i = 0; i < 16; i++ )
-            {
-                h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] =
-                    a->i_predict4x4[block_idx_x[i]][block_idx_y[i]];
-            }
+                h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] = a->i_predict4x4[i];
 
             x264_mb_analyse_intra_chroma( h, a );
             break;
         case I_8x8:
             for( i = 0; i < 4; i++ )
-                x264_macroblock_cache_intra8x8_pred( h, 2*(i&1), 2*(i>>1),
-                    a->i_predict8x8[i&1][i>>1] );
+                x264_macroblock_cache_intra8x8_pred( h, 2*(i&1), 2*(i>>1), a->i_predict8x8[i] );
 
             x264_mb_analyse_intra_chroma( h, a );
             break;
@@ -2288,12 +2657,10 @@ static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a  )
 
         case P_SKIP:
         {
-            int mvp[2];
-            x264_mb_predict_mv_pskip( h, mvp );
-            /* */
             h->mb.i_partition = D_16x16;
             x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, 0 );
-            x264_macroblock_cache_mv ( h, 0, 0, 4, 4, 0, mvp[0], mvp[1] );
+            x264_macroblock_cache_mv ( h, 0, 0, 4, 4, 0, h->mb.cache.pskip_mv[0],
+                                                         h->mb.cache.pskip_mv[1] );
             break;
         }
 
@@ -2355,7 +2722,38 @@ static void x264_analyse_update_cache( x264_t *h, x264_mb_analysis_t *a  )
                 break;
             }
     }
+
+#ifndef NDEBUG
+    if( h->param.i_threads > 1 && !IS_INTRA(h->mb.i_type) )
+    {
+        int l;
+        for( l=0; l <= (h->sh.i_type == SLICE_TYPE_B); l++ )
+        {
+            int completed;
+            int ref = h->mb.cache.ref[l][x264_scan8[0]];
+            if( ref < 0 )
+                continue;
+            completed = (l ? h->fref1 : h->fref0)[ ref >> h->mb.b_interlaced ]->i_lines_completed;
+            if( (h->mb.cache.mv[l][x264_scan8[15]][1] >> (2 - h->mb.b_interlaced)) + h->mb.i_mb_y*16 > completed )
+            {
+                x264_log( h, X264_LOG_WARNING, "internal error (MV out of thread range)\n");
+                fprintf(stderr, "mb type: %d \n", h->mb.i_type);
+                fprintf(stderr, "mv: l%dr%d (%d,%d) \n", l, ref,
+                                h->mb.cache.mv[l][x264_scan8[15]][0],
+                                h->mb.cache.mv[l][x264_scan8[15]][1] );
+                fprintf(stderr, "limit: %d \n", h->mb.mv_max_spel[1]);
+                fprintf(stderr, "mb_xy: %d,%d \n", h->mb.i_mb_x, h->mb.i_mb_y);
+                fprintf(stderr, "completed: %d \n", completed );
+                x264_log( h, X264_LOG_WARNING, "recovering by using intra mode\n");
+                x264_mb_analyse_intra( h, a, COST_MAX );
+                h->mb.i_type = I_16x16;
+                h->mb.i_intra16x16_pred_mode = a->i_predict16x16;
+                x264_mb_analyse_intra_chroma( h, a );
+            }
+        }
+    }
+#endif
 }
 
-#include "slicetype_decision.c"
+#include "slicetype.c"