All pastes #1165374 Raw Edit

Miscellany

public text v1 · immutable
#1165374 ·published 2008-08-11 00:06 UTC
rendered paste body
Index: contrib/Jamfile
===================================================================
--- contrib/Jamfile	(revision 1622)
+++ contrib/Jamfile	(working copy)
@@ -407,6 +407,7 @@
         LIBX264_PATCH += " $(PATCH) -p1 < ../patch-x264-solaris.patch && " ;
     }
     LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-idr.patch && " ;
+    LIBX264_PATCH += "$(PATCH) -p1 < ../patch-x264-psytrellis.patch && " ;
 	Depends $(<) : $(>) ;
     Depends lib  : $(<) ;
 }
Index: contrib/patch-x264-psytrellis.patch
===================================================================
--- contrib/patch-x264-psytrellis.patch	(revision 0)
+++ contrib/patch-x264-psytrellis.patch	(revision 0)
@@ -0,0 +1,687 @@
+diff -rc ./common/common.c ../x264/common/common.c
+*** ./common/common.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/common/common.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 117,122 ****
+--- 117,123 ----
+                           | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16;
+      param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL;
+      param->analyse.i_me_method = X264_ME_HEX;
++     param->analyse.f_psy_rd = 1.0;
+      param->analyse.i_me_range = 16;
+      param->analyse.i_subpel_refine = 5;
+      param->analyse.b_chroma_me = 1;
+***************
+*** 464,469 ****
+--- 465,472 ----
+          p->analyse.i_mv_range_thread = atoi(value);
+      OPT2("subme", "subq")
+          p->analyse.i_subpel_refine = atoi(value);
++     OPT("psy-rd")
++         p->analyse.f_psy_rd = atof(value);
+      OPT("bime")
+          p->analyse.b_bidir_me = atobool(value);
+      OPT("chroma-me")
+***************
+*** 856,861 ****
+--- 859,865 ----
+      s += sprintf( s, " analyse=%#x:%#x", p->analyse.intra, p->analyse.inter );
+      s += sprintf( s, " me=%s", x264_motion_est_names[ p->analyse.i_me_method ] );
+      s += sprintf( s, " subme=%d", p->analyse.i_subpel_refine );
++     s += sprintf( s, " psy_rd=%.1f", p->analyse.f_psy_rd );
+      s += sprintf( s, " brdo=%d", p->analyse.b_bframe_rdo );
+      s += sprintf( s, " mixed_ref=%d", p->analyse.b_mixed_references );
+      s += sprintf( s, " me_range=%d", p->analyse.i_me_range );
+diff -rc ./common/common.h ../x264/common/common.h
+*** ./common/common.h	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/common/common.h	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 342,349 ****
+      x264_frame_t    *fref1[16+3];     /* ref list 1 */
+      int             b_ref_reorder[2];
+  
+- 
+- 
+      /* Current MB DCT coeffs */
+      struct
+      {
+--- 342,347 ----
+***************
+*** 454,459 ****
+--- 452,467 ----
+              DECLARE_ALIGNED_16( int16_t i8x8_dct_buf[3][64] );
+              DECLARE_ALIGNED_16( int16_t i4x4_dct_buf[15][16] );
+  
++             /* Psy trellis DCT data */
++             DECLARE_ALIGNED_16( int16_t fenc_dct8[4][64] );
++             DECLARE_ALIGNED_16( int16_t fenc_dct4[16][16] );
++ 
++             /* SATD scores for psy RD */
++             int fenc_satd[4][4];
++             int fenc_satd_sum;
++             int fenc_sa8d[2][2];
++             int fenc_sa8d_sum;
++ 
+              /* pointer over mb of the frame to be compressed */
+              uint8_t *p_fenc[3];
+  
+diff -rc ./common/dct.h ../x264/common/dct.h
+*** ./common/dct.h	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/common/dct.h	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 41,46 ****
+--- 41,57 ----
+  };
+  #undef W
+  
++ #define W(i) (i==0 ? FIX8(1.76777) :\
++               i==1 ? FIX8(1.11803) :\
++               i==2 ? FIX8(0.70711) :0)
++ static const uint16_t x264_dct4_weight_tab[16] = {
++     W(0), W(1), W(0), W(1),
++     W(1), W(2), W(1), W(2),
++     W(0), W(1), W(0), W(1),
++     W(1), W(2), W(1), W(2)
++ };
++ #undef W
++ 
+  /* inverse squared */
+  #define W(i) (i==0 ? FIX8(3.125) :\
+                i==1 ? FIX8(1.25) :\
+diff -rc ./encoder/analyse.c ../x264/encoder/analyse.c
+*** ./encoder/analyse.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/encoder/analyse.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 467,472 ****
+--- 467,524 ----
+      }
+  }
+  
++ /* For trellis=2, we need to do this for both sizes of DCT, for trellis=1 we only need to use it on the chosen mode. */
++ static void inline x264_psy_trellis_init( x264_t *h, int do_both_dct )
++ {
++     DECLARE_ALIGNED_16( int16_t dct8x8[4][8][8] );
++     DECLARE_ALIGNED_16( int16_t dct4x4[16][4][4] );
++     DECLARE_ALIGNED_16( uint8_t zero[16*FDEC_STRIDE] ) = {0};
++     int i;
++ 
++     if( do_both_dct || h->mb.b_transform_8x8 )
++     {
++         h->dctf.sub16x16_dct8( dct8x8, h->mb.pic.p_fenc[0], zero );
++         for( i = 0; i < 4; i++ )
++             h->zigzagf.scan_8x8( h->mb.pic.fenc_dct8[i], dct8x8[i] );
++     }
++     if( do_both_dct || !h->mb.b_transform_8x8)
++     {
++         h->dctf.sub16x16_dct( dct4x4, h->mb.pic.p_fenc[0], zero );
++         for( i = 0; i < 16; i++ )
++             h->zigzagf.scan_4x4( h->mb.pic.fenc_dct4[i], dct4x4[i] );
++     }
++ }
++ 
++ /* Pre-calculate fenc satd scores for psy RD, minus DC coefficients */
++ static inline void x264_mb_cache_fenc_satd( x264_t *h )
++ {
++     DECLARE_ALIGNED_16(uint8_t zero[16]) = {0};
++     uint8_t *fenc;
++     int x, y, satd_sum = 0, sa8d_sum = 0;
++     if( !h->param.analyse.i_psy_rd )
++         return;
++     for( y = 0; y < 4; y++ )
++         for( x = 0; x < 4; x++ )
++         {
++             fenc = h->mb.pic.p_fenc[0]+x*4+y*4*FENC_STRIDE;
++             h->mb.pic.fenc_satd[y][x] = h->pixf.satd[PIXEL_4x4]( zero, 0, fenc, FENC_STRIDE )
++                                       - (h->pixf.sad[PIXEL_4x4]( zero, 0, fenc, FENC_STRIDE )>>1);
++             satd_sum += h->mb.pic.fenc_satd[y][x];
++         }
++     for( y = 0; y < 2; y++ )
++         for( x = 0; x < 2; x++ )
++         {
++             fenc = h->mb.pic.p_fenc[0]+x*8+y*8*FENC_STRIDE;
++             h->mb.pic.fenc_sa8d[y][x] = h->pixf.sa8d[PIXEL_8x8]( zero, 0, fenc, FENC_STRIDE )
++                                       - (h->pixf.sad[PIXEL_8x8]( zero, 0, fenc, FENC_STRIDE )>>2);
++             sa8d_sum += h->mb.pic.fenc_sa8d[y][x];
++         }
++     h->mb.pic.fenc_satd_sum = satd_sum;
++     h->mb.pic.fenc_sa8d_sum = sa8d_sum;
++     if( h->param.analyse.i_trellis == 2 )
++         x264_psy_trellis_init( h, 1 );
++ }
++ 
+  static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a )
+  {
+      int i;
+***************
+*** 1016,1027 ****
+      assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
+  
+      h->mb.i_type = P_L0;
+!     if( a->b_mbrd && a->l0.me16x16.i_ref == 0
+!         && *(uint32_t*)a->l0.me16x16.mv == *(uint32_t*)h->mb.cache.pskip_mv )
+      {
+!         h->mb.i_partition = D_16x16;
+!         x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv );
+!         a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+      }
+  }
+  
+--- 1068,1082 ----
+      assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
+  
+      h->mb.i_type = P_L0;
+!     if( a->b_mbrd )
+      {
+!         x264_mb_cache_fenc_satd( h );
+!         if( a->l0.me16x16.i_ref == 0 && *(uint32_t*)a->l0.me16x16.mv == *(uint32_t*)h->mb.cache.pskip_mv )
+!         {
+!             h->mb.i_partition = D_16x16;
+!             x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv );
+!             a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
+!         }
+      }
+  }
+  
+***************
+*** 1906,1912 ****
+  
+  static void x264_mb_analyse_b_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter )
+  {
+!     int thresh = i_satd_inter * 17/16;
+  
+      if( a->b_direct_available && a->i_rd16x16direct == COST_MAX )
+      {
+--- 1961,1967 ----
+  
+  static void x264_mb_analyse_b_rd( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter )
+  {
+!     int thresh = i_satd_inter * (17 + (!!h->param.analyse.i_psy_rd))/16;
+  
+      if( a->b_direct_available && a->i_rd16x16direct == COST_MAX )
+      {
+***************
+*** 2046,2052 ****
+      }
+  }
+  
+- 
+  /*****************************************************************************
+   * x264_macroblock_analyse:
+   *****************************************************************************/
+--- 2101,2106 ----
+***************
+*** 2065,2070 ****
+--- 2119,2126 ----
+      /*--------------------------- Do the analysis ---------------------------*/
+      if( h->sh.i_type == SLICE_TYPE_I )
+      {
++         if( analysis.b_mbrd )
++             x264_mb_cache_fenc_satd( h );
+          x264_mb_analyse_intra( h, &analysis, COST_MAX );
+          if( analysis.b_mbrd )
+              x264_intra_rd( h, &analysis, COST_MAX );
+***************
+*** 2342,2347 ****
+--- 2398,2406 ----
+      {
+          int i_bskip_cost = COST_MAX;
+          int b_skip = 0;
++         
++         if( analysis.b_mbrd )
++             x264_mb_cache_fenc_satd( h );
+  
+          h->mb.i_type = B_SKIP;
+          if( h->mb.b_direct_auto_write )
+***************
+*** 2588,2593 ****
+--- 2647,2654 ----
+  
+      h->mb.b_trellis = h->param.analyse.i_trellis;
+      h->mb.b_noise_reduction = !!h->param.analyse.i_noise_reduction;
++     if( !IS_SKIP(h->mb.i_type) && h->param.analyse.i_psy_rd && h->param.analyse.i_trellis == 1 )
++         x264_psy_trellis_init( h, 0 );
+      if( h->mb.b_trellis == 1 || h->mb.b_noise_reduction )
+          h->mb.i_skip_intra = 0;
+  }
+diff -rc ./encoder/encoder.c ../x264/encoder/encoder.c
+*** ./encoder/encoder.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/encoder/encoder.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 411,416 ****
+--- 411,417 ----
+          h->param.analyse.b_fast_pskip = 0;
+          h->param.analyse.i_noise_reduction = 0;
+          h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 6 );
++         h->param.analyse.f_psy_rd = 0;
+      }
+      if( h->param.rc.i_rc_method == X264_RC_CQP )
+      {
+***************
+*** 482,491 ****
+          h->param.analyse.inter &= ~X264_ANALYSE_I8x8;
+          h->param.analyse.intra &= ~X264_ANALYSE_I8x8;
+      }
+-     h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -12, 12);
+      if( !h->param.b_cabac )
+          h->param.analyse.i_trellis = 0;
+      h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 );
+      h->param.rc.i_aq_mode = x264_clip3( h->param.rc.i_aq_mode, 0, 2 );
+      if( h->param.rc.f_aq_strength <= 0 )
+          h->param.rc.i_aq_mode = 0;
+--- 483,505 ----
+          h->param.analyse.inter &= ~X264_ANALYSE_I8x8;
+          h->param.analyse.intra &= ~X264_ANALYSE_I8x8;
+      }
+      if( !h->param.b_cabac )
+          h->param.analyse.i_trellis = 0;
+      h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 );
++     h->param.analyse.f_psy_rd = x264_clip3f( h->param.analyse.f_psy_rd, 0, 10 );
++     //if( h->param.analyse.i_subpel_refine < 6)
++     //    h->param.analyse.f_psy_rd = 0;
++     if( h->param.analyse.f_psy_rd )
++     {
++         h->param.analyse.i_psy_rd = FIX8( h->param.analyse.f_psy_rd );
++         /* Psy RDO increases overall quantizers to improve the quality of luma--this indirectly hurts chroma quality */
++         /* so we lower the chroma QP offset to compensate */
++         h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_rd < 0.25 ? 1 : 2;
++         /* Psy trellis has a similar effect. */
++         if( h->param.analyse.i_trellis )
++             h->param.analyse.i_chroma_qp_offset -= 2;
++     }
++     h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -12, 12);
+      h->param.rc.i_aq_mode = x264_clip3( h->param.rc.i_aq_mode, 0, 2 );
+      if( h->param.rc.f_aq_strength <= 0 )
+          h->param.rc.i_aq_mode = 0;
+diff -rc ./encoder/macroblock.c ../x264/encoder/macroblock.c
+*** ./encoder/macroblock.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/encoder/macroblock.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 94,100 ****
+      h->dctf.sub4x4_dct( dct4x4, p_src, p_dst );
+  
+      if( h->mb.b_trellis )
+!         x264_quant_4x4_trellis( h, dct4x4, CQM_4IY, i_qscale, DCT_LUMA_4x4, 1 );
+      else
+          h->quantf.quant_4x4( dct4x4, h->quant4_mf[CQM_4IY][i_qscale], h->quant4_bias[CQM_4IY][i_qscale] );
+  
+--- 94,100 ----
+      h->dctf.sub4x4_dct( dct4x4, p_src, p_dst );
+  
+      if( h->mb.b_trellis )
+!         x264_quant_4x4_trellis( h, dct4x4, CQM_4IY, i_qscale, DCT_LUMA_4x4, 1, idx );
+      else
+          h->quantf.quant_4x4( dct4x4, h->quant4_mf[CQM_4IY][i_qscale], h->quant4_bias[CQM_4IY][i_qscale] );
+  
+***************
+*** 121,127 ****
+      h->dctf.sub8x8_dct8( dct8x8, p_src, p_dst );
+  
+      if( h->mb.b_trellis )
+!         x264_quant_8x8_trellis( h, dct8x8, CQM_8IY, i_qscale, 1 );
+      else 
+          h->quantf.quant_8x8( dct8x8, h->quant8_mf[CQM_8IY][i_qscale], h->quant8_bias[CQM_8IY][i_qscale] );
+  
+--- 121,127 ----
+      h->dctf.sub8x8_dct8( dct8x8, p_src, p_dst );
+  
+      if( h->mb.b_trellis )
+!         x264_quant_8x8_trellis( h, dct8x8, CQM_8IY, i_qscale, 1, idx );
+      else 
+          h->quantf.quant_8x8( dct8x8, h->quant8_mf[CQM_8IY][i_qscale], h->quant8_bias[CQM_8IY][i_qscale] );
+  
+***************
+*** 163,169 ****
+  
+          /* quant/scan/dequant */
+          if( h->mb.b_trellis )
+!             x264_quant_4x4_trellis( h, dct4x4[i], CQM_4IY, i_qscale, DCT_LUMA_AC, 1 );
+          else
+              h->quantf.quant_4x4( dct4x4[i], h->quant4_mf[CQM_4IY][i_qscale], h->quant4_bias[CQM_4IY][i_qscale] );
+  
+--- 163,169 ----
+  
+          /* quant/scan/dequant */
+          if( h->mb.b_trellis )
+!             x264_quant_4x4_trellis( h, dct4x4[i], CQM_4IY, i_qscale, DCT_LUMA_AC, 1, i );
+          else
+              h->quantf.quant_4x4( dct4x4[i], h->quant4_mf[CQM_4IY][i_qscale], h->quant4_bias[CQM_4IY][i_qscale] );
+  
+***************
+*** 447,453 ****
+                  if( h->mb.b_noise_reduction )
+                      h->quantf.denoise_dct_core( *dct8x8[idx], h->nr_residual_sum[1], h->nr_offset[1], 64 );
+                  if( h->mb.b_trellis )
+!                     x264_quant_8x8_trellis( h, dct8x8[idx], CQM_8PY, i_qp, 0 );
+                  else
+                      h->quantf.quant_8x8( dct8x8[idx], h->quant8_mf[CQM_8PY][i_qp], h->quant8_bias[CQM_8PY][i_qp] );
+  
+--- 447,453 ----
+                  if( h->mb.b_noise_reduction )
+                      h->quantf.denoise_dct_core( *dct8x8[idx], h->nr_residual_sum[1], h->nr_offset[1], 64 );
+                  if( h->mb.b_trellis )
+!                     x264_quant_8x8_trellis( h, dct8x8[idx], CQM_8PY, i_qp, 0, idx );
+                  else
+                      h->quantf.quant_8x8( dct8x8[idx], h->quant8_mf[CQM_8PY][i_qp], h->quant8_bias[CQM_8PY][i_qp] );
+  
+***************
+*** 495,501 ****
+                      if( h->mb.b_noise_reduction )
+                          h->quantf.denoise_dct_core( *dct4x4[idx], h->nr_residual_sum[0], h->nr_offset[0], 16 );
+                      if( h->mb.b_trellis )
+!                         x264_quant_4x4_trellis( h, dct4x4[idx], CQM_4PY, i_qp, DCT_LUMA_4x4, 0 );
+                      else
+                          h->quantf.quant_4x4( dct4x4[idx], h->quant4_mf[CQM_4PY][i_qp], h->quant4_bias[CQM_4PY][i_qp] );
+  
+--- 495,501 ----
+                      if( h->mb.b_noise_reduction )
+                          h->quantf.denoise_dct_core( *dct4x4[idx], h->nr_residual_sum[0], h->nr_offset[0], 16 );
+                      if( h->mb.b_trellis )
+!                         x264_quant_4x4_trellis( h, dct4x4[idx], CQM_4PY, i_qp, DCT_LUMA_4x4, 0, idx );
+                      else
+                          h->quantf.quant_4x4( dct4x4[idx], h->quant4_mf[CQM_4PY][i_qp], h->quant4_bias[CQM_4PY][i_qp] );
+  
+diff -rc ./encoder/macroblock.h ../x264/encoder/macroblock.h
+*** ./encoder/macroblock.h	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/encoder/macroblock.h	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 50,58 ****
+  void x264_cabac_mb_skip( x264_t *h, int b_skip );
+  
+  void x264_quant_4x4_trellis( x264_t *h, int16_t dct[4][4], int i_quant_cat,
+!                              int i_qp, int i_ctxBlockCat, int b_intra );
+  void x264_quant_8x8_trellis( x264_t *h, int16_t dct[8][8], int i_quant_cat,
+!                              int i_qp, int b_intra );
+  
+  void x264_noise_reduction_update( x264_t *h );
+  
+--- 50,58 ----
+  void x264_cabac_mb_skip( x264_t *h, int b_skip );
+  
+  void x264_quant_4x4_trellis( x264_t *h, int16_t dct[4][4], int i_quant_cat,
+!                              int i_qp, int i_ctxBlockCat, int b_intra, int idx );
+  void x264_quant_8x8_trellis( x264_t *h, int16_t dct[8][8], int i_quant_cat,
+!                              int i_qp, int b_intra, int idx );
+  
+  void x264_noise_reduction_update( x264_t *h );
+  
+diff -rc ./encoder/rdo.c ../x264/encoder/rdo.c
+*** ./encoder/rdo.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/encoder/rdo.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 50,70 ****
+  
+  #define COPY_CABAC h->mc.memcpy_aligned( &cabac_tmp.f8_bits_encoded, &h->cabac.f8_bits_encoded, \
+          sizeof(x264_cabac_t) - offsetof(x264_cabac_t,f8_bits_encoded) )
+!     
+! static int ssd_mb( x264_t *h )
+! {
+!     return h->pixf.ssd[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE,
+!                                      h->mb.pic.p_fdec[0], FDEC_STRIDE )
+!          + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[1], FENC_STRIDE,
+!                                      h->mb.pic.p_fdec[1], FDEC_STRIDE )
+!          + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[2], FENC_STRIDE,
+!                                      h->mb.pic.p_fdec[2], FDEC_STRIDE );
+  }
+  
+! static int ssd_plane( x264_t *h, int size, int p, int x, int y )
+  {
+!     return h->pixf.ssd[size]( h->mb.pic.p_fenc[p] + x+y*FENC_STRIDE, FENC_STRIDE,
+!                               h->mb.pic.p_fdec[p] + x+y*FDEC_STRIDE, FDEC_STRIDE );
+  }
+  
+  static int x264_rd_cost_mb( x264_t *h, int i_lambda2 )
+--- 50,131 ----
+  
+  #define COPY_CABAC h->mc.memcpy_aligned( &cabac_tmp.f8_bits_encoded, &h->cabac.f8_bits_encoded, \
+          sizeof(x264_cabac_t) - offsetof(x264_cabac_t,f8_bits_encoded) )
+! 
+! #define ADD_ABS_SATD(satdtype, pixel)\
+!     satd += abs((h->pixf.satdtype[pixel]( zero, 0, fdec, FDEC_STRIDE ) - dc_coef)\
+!           - sum_##satdtype( h, pixel, x, y ));
+! 
+! /* Sum the cached SATDs to avoid repeating them. */
+! static inline int sum_satd( x264_t *h, int pixel, int x, int y )
+! {
+!     int satd = 0;
+!     int min_x = x>>2;
+!     int min_y = y>>2;
+!     int max_x = (x>>2) + (x264_pixel_size[pixel].w>>2);
+!     int max_y = (y>>2) + (x264_pixel_size[pixel].h>>2);
+!     if( pixel == PIXEL_16x16 )
+!         return h->mb.pic.fenc_satd_sum;
+!     for( y = min_y; y < max_y; y++ )
+!         for( x = min_x; x < max_x; x++ )
+!             satd += h->mb.pic.fenc_satd[y][x];
+!     return satd;
+! }
+! 
+! static inline int sum_sa8d( x264_t *h, int pixel, int x, int y )
+! {
+!     int sa8d = 0;
+!     int min_x = x>>3;
+!     int min_y = y>>3;
+!     int max_x = (x>>3) + (x264_pixel_size[pixel].w>>3);
+!     int max_y = (y>>3) + (x264_pixel_size[pixel].h>>3);
+!     if( pixel == PIXEL_16x16 )
+!         return h->mb.pic.fenc_sa8d_sum;
+!     for( y = min_y; y < max_y; y++ )
+!         for( x = min_x; x < max_x; x++ )
+!             sa8d += h->mb.pic.fenc_sa8d[y][x];
+!     return sa8d;
+! }
+! 
+! /* Psy RD distortion metric: SSD plus "Absolute Difference of Complexities" */
+! /* SATD and SA8D are used to measure block complexity. */
+! /* Blocks with a complexity most similar to that of the source are scored best. */
+! /* The difference between SATD and SA8D scores are both used to avoid bias from the DCT size.  Using SATD */
+! /* only, for example, results in overusage of 8x8dct, while the opposite occurs when using SA8D. */
+! /* This is because frequencies stored in an 8x8dct sum up to a larger value when viewed through a 4x4 */
+! /* transform and vice versa with a 4x4dct and an 8x8 transform. */
+! /* SSD is still used as the primary RD metric; this value is merely added to it for psy purposes. */
+! 
+! /* FIXME:  Is there a better metric than averaged SATD/SA8D difference for complexity difference? */
+! /* Hadamard transform is recursive, so a SATD+SA8D can be done faster by taking advantage of this fact. */
+! /* This optimization can also be used in non-RD transform decision. */
+! 
+! static inline int ssd_plane( x264_t *h, int size, int p, int x, int y )
+! {
+!     DECLARE_ALIGNED_16(uint8_t zero[16]) = {0};
+!     int satd = 0;
+!     uint8_t *fdec = h->mb.pic.p_fdec[p] + x + y*FDEC_STRIDE;
+!     uint8_t *fenc = h->mb.pic.p_fenc[p] + x + y*FENC_STRIDE;
+!     if( p == 0 && h->param.analyse.i_psy_rd )
+!     {
+!         int dc_coef = h->pixf.sad[size](zero, 0, fdec, FDEC_STRIDE) >> 1;
+!         ADD_ABS_SATD(satd, size);
+!         /* If the plane is smaller than 8x8, we can't do an SA8D; this probably isn't a big problem. */
+!         if(size <= PIXEL_8x8)
+!         {
+!             dc_coef >>= 1;
+!             ADD_ABS_SATD(sa8d, size);
+!             satd >>= 1;
+!         }
+!         satd = (satd * h->param.analyse.i_psy_rd * x264_lambda_tab[h->mb.i_qp] + 128) >> 8;
+!     }
+!     return h->pixf.ssd[size](fenc, FENC_STRIDE, fdec, FDEC_STRIDE) + satd;
+  }
+  
+! static inline int ssd_mb( x264_t *h )
+  {
+!     return ssd_plane(h, PIXEL_16x16, 0, 0, 0)
+!          + ssd_plane(h, PIXEL_8x8,   1, 0, 0)
+!          + ssd_plane(h, PIXEL_8x8,   2, 0, 0);
+  }
+  
+  static int x264_rd_cost_mb( x264_t *h, int i_lambda2 )
+***************
+*** 267,273 ****
+  };
+  
+  typedef struct {
+!     uint64_t score;
+      int level_idx; // index into level_tree[]
+      uint8_t cabac_state[10]; //just the contexts relevant to coding abs_level_m1
+  } trellis_node_t;
+--- 328,334 ----
+  };
+  
+  typedef struct {
+!     int64_t score;
+      int level_idx; // index into level_tree[]
+      uint8_t cabac_state[10]; //just the contexts relevant to coding abs_level_m1
+  } trellis_node_t;
+***************
+*** 296,302 ****
+  static inline void quant_trellis_cabac( x264_t *h, int16_t *dct,
+                                   const uint16_t *quant_mf, const int *unquant_mf,
+                                   const int *coef_weight, const uint8_t *zigzag,
+!                                  int i_ctxBlockCat, int i_lambda2, int b_ac, int i_coefs )
+  {
+      int abs_coefs[64], signs[64];
+      trellis_node_t nodes[2][8];
+--- 357,363 ----
+  static inline void quant_trellis_cabac( x264_t *h, int16_t *dct,
+                                   const uint16_t *quant_mf, const int *unquant_mf,
+                                   const int *coef_weight, const uint8_t *zigzag,
+!                                  int i_ctxBlockCat, int i_lambda2, int b_ac, int i_coefs, int idx )
+  {
+      int abs_coefs[64], signs[64];
+      trellis_node_t nodes[2][8];
+***************
+*** 428,435 ****
+          // that are better left coded, especially at QP > 40.
+          for( abs_level = q; abs_level >= q-1; abs_level-- )
+          {
+!             int d = i_coef - ((unquant_mf[zigzag[i]] * abs_level + 128) >> 8);
+!             uint64_t ssd = (int64_t)d*d * coef_weight[i];
+  
+              for( j = 0; j < 8; j++ )
+              {
+--- 489,508 ----
+          // that are better left coded, especially at QP > 40.
+          for( abs_level = q; abs_level >= q-1; abs_level-- )
+          {
+!             int unquant_abs_level = ((unquant_mf[zigzag[i]] * abs_level + 128) >> 8);
+!             int d = i_coef - unquant_abs_level;
+!             int64_t ssd;
+!             /* Psy trellis: bias in favor of higher AC coefficients in the reconstructed frame. */
+!             if( h->param.analyse.i_psy_rd && i != 0 )
+!             {
+!                 int orig_coef = (i_coefs == 64) ? h->mb.pic.fenc_dct8[idx][i] : h->mb.pic.fenc_dct4[idx][i];
+!                 int predicted_coef = abs(orig_coef - i_coef * signs[i] );
+!                 int psy_value = h->param.analyse.i_psy_rd * abs(predicted_coef + unquant_abs_level * signs[i]);
+!                 int psy_weight = (i_coefs == 64) ? x264_dct8_weight_tab[zigzag[i]] : x264_dct4_weight_tab[zigzag[i]];
+!                 ssd = (int64_t)d*d * coef_weight[i] - psy_weight * (psy_value>>2);
+!             }
+!             else
+!                 ssd = (int64_t)d*d * coef_weight[i];
+  
+              for( j = 0; j < 8; j++ )
+              {
+***************
+*** 493,516 ****
+  
+  
+  void x264_quant_4x4_trellis( x264_t *h, int16_t dct[4][4], int i_quant_cat,
+!                              int i_qp, int i_ctxBlockCat, int b_intra )
+  {
+      int b_ac = (i_ctxBlockCat == DCT_LUMA_AC);
+      quant_trellis_cabac( h, (int16_t*)dct,
+          h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp],
+          x264_dct4_weight2_zigzag[h->mb.b_interlaced],
+          x264_zigzag_scan4[h->mb.b_interlaced],
+!         i_ctxBlockCat, lambda2_tab[b_intra][i_qp], b_ac, 16 );
+  }
+  
+  
+  void x264_quant_8x8_trellis( x264_t *h, int16_t dct[8][8], int i_quant_cat,
+!                              int i_qp, int b_intra )
+  {
+      quant_trellis_cabac( h, (int16_t*)dct,
+          h->quant8_mf[i_quant_cat][i_qp], h->unquant8_mf[i_quant_cat][i_qp],
+          x264_dct8_weight2_zigzag[h->mb.b_interlaced],
+          x264_zigzag_scan8[h->mb.b_interlaced],
+!         DCT_LUMA_8x8, lambda2_tab[b_intra][i_qp], 0, 64 );
+  }
+  
+--- 566,589 ----
+  
+  
+  void x264_quant_4x4_trellis( x264_t *h, int16_t dct[4][4], int i_quant_cat,
+!                              int i_qp, int i_ctxBlockCat, int b_intra, int idx )
+  {
+      int b_ac = (i_ctxBlockCat == DCT_LUMA_AC);
+      quant_trellis_cabac( h, (int16_t*)dct,
+          h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp],
+          x264_dct4_weight2_zigzag[h->mb.b_interlaced],
+          x264_zigzag_scan4[h->mb.b_interlaced],
+!         i_ctxBlockCat, lambda2_tab[b_intra][h->mb.i_qp], b_ac, 16, idx );
+  }
+  
+  
+  void x264_quant_8x8_trellis( x264_t *h, int16_t dct[8][8], int i_quant_cat,
+!                              int i_qp, int b_intra, int idx )
+  {
+      quant_trellis_cabac( h, (int16_t*)dct,
+          h->quant8_mf[i_quant_cat][i_qp], h->unquant8_mf[i_quant_cat][i_qp],
+          x264_dct8_weight2_zigzag[h->mb.b_interlaced],
+          x264_zigzag_scan8[h->mb.b_interlaced],
+!         DCT_LUMA_8x8, lambda2_tab[b_intra][h->mb.i_qp], 0, 64, idx );
+  }
+  
+diff -rc ./x264.c ../x264/x264.c
+*** ./x264.c	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/x264.c	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 243,248 ****
+--- 243,251 ----
+      H0( "  -m, --subme <integer>       Subpixel motion estimation and partition\n"
+          "                                  decision quality: 1=fast, 7=best. [%d]\n", defaults->analyse.i_subpel_refine );
+      H0( "      --b-rdo                 RD based mode decision for B-frames. Requires subme 6.\n" );
++     H0( "      --psy-rd                Strength of mode decision psychovisual optimization [\"%.1f\"]\n"
++         "                              Does nothing at subme < 6.\n",
++                                        defaults->analyse.f_psy_rd );
+      H0( "      --mixed-refs            Decide references on a per partition basis\n" );
+      H1( "      --no-chroma-me          Ignore chroma in motion estimation\n" );
+      H1( "      --bime                  Jointly optimize both MVs in B-frames\n" );
+***************
+*** 411,416 ****
+--- 414,420 ----
+              { "mvrange", required_argument, NULL, 0 },
+              { "mvrange-thread", required_argument, NULL, 0 },
+              { "subme",   required_argument, NULL, 'm' },
++             { "psy-rd",   required_argument, NULL, 0 },
+              { "b-rdo",   no_argument,       NULL, 0 },
+              { "mixed-refs", no_argument,    NULL, 0 },
+              { "no-chroma-me", no_argument,  NULL, 0 },
+diff -rc ./x264.h ../x264/x264.h
+*** ./x264.h	2008-07-15 08:43:54.000000000 -0700
+--- ../x264/x264.h	2008-08-10 16:40:09.000000000 -0700
+***************
+*** 35,41 ****
+  
+  #include <stdarg.h>
+  
+! #define X264_BUILD 60
+  
+  /* x264_t:
+   *      opaque handler for encoder */
+--- 35,41 ----
+  
+  #include <stdarg.h>
+  
+! #define X264_BUILD 61
+  
+  /* x264_t:
+   *      opaque handler for encoder */
+***************
+*** 239,244 ****
+--- 239,246 ----
+          int          b_fast_pskip; /* early SKIP detection on P-frames */
+          int          b_dct_decimate; /* transform coefficient thresholding on P-frames */
+          int          i_noise_reduction; /* adaptive pseudo-deadzone */
++         float        f_psy_rd; /* Psy RD strength */
++         int          i_psy_rd; /* Psy RD strength--fixed point value*/
+  
+          /* the deadzone size that will be used in luma quantization */
+          int          i_luma_deadzone[2]; /* {inter, intra} */