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 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 + +! #define X264_BUILD 60 + + /* x264_t: + * opaque handler for encoder */ +--- 35,41 ---- + + #include + +! #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} */