rendered paste bodyIndex: 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} */