Index: encoder/slicetype_decision.c =================================================================== --- encoder/slicetype_decision.c (revision 540) +++ encoder/slicetype_decision.c (working copy) @@ -38,6 +38,7 @@ h->mb.i_me_method = X264_MIN( X264_ME_HEX, h->param.analyse.i_me_method ); // maybe dia? h->mb.i_subpel_refine = 4; // 3 should be enough, but not tweaking for speed now h->mb.b_chroma_me = 0; + x264_macroblock_thread_init( h ); } int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, @@ -61,7 +62,6 @@ int i_cost_bak; int l, i; - h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, &fenc->lowres[0][i_pel_offset], i_stride, 8 ); if( !p0 && !p1 && !b ) @@ -155,34 +155,37 @@ { int mvc[4][2] = {{0}}, i_mvc; int16_t (*fenc_mv)[2] = &fenc->mv[l][i_mb_xy]; - i_mvc = 0; - if( i_mb_x > 0 ) - { - mvc[i_mvc][0] = fenc_mv[-1][0]; - mvc[i_mvc][1] = fenc_mv[-1][1]; - i_mvc++; - } - if( i_mb_y > 0 ) - { - mvc[i_mvc][0] = fenc_mv[-i_mb_stride][0]; - mvc[i_mvc][1] = fenc_mv[-i_mb_stride][1]; - i_mvc++; - if( i_mb_x < h->sps->i_mb_width - 1 ) - { - mvc[i_mvc][0] = fenc_mv[-i_mb_stride+1][0]; - mvc[i_mvc][1] = fenc_mv[-i_mb_stride+1][1]; - i_mvc++; - } - if( i_mb_x > 0 ) - { - mvc[i_mvc][0] = fenc_mv[-i_mb_stride-1][0]; - mvc[i_mvc][1] = fenc_mv[-i_mb_stride-1][1]; - i_mvc++; - } - } - m[l].mvp[0] = x264_median( mvc[0][0], mvc[1][0], mvc[2][0] ); - m[l].mvp[1] = x264_median( mvc[0][1], mvc[1][1], mvc[2][1] ); +#define LOAD_MVP(m)\ + i_mvc = 0;\ + if( i_mb_x > 0 )\ + {\ + mvc[i_mvc][0] = fenc_mv[-1][0];\ + mvc[i_mvc][1] = fenc_mv[-1][1];\ + i_mvc++;\ + }\ + if( i_mb_y > 0 )\ + {\ + mvc[i_mvc][0] = fenc_mv[-i_mb_stride][0];\ + mvc[i_mvc][1] = fenc_mv[-i_mb_stride][1];\ + i_mvc++;\ + if( i_mb_x < h->sps->i_mb_width - 1 )\ + {\ + mvc[i_mvc][0] = fenc_mv[-i_mb_stride+1][0];\ + mvc[i_mvc][1] = fenc_mv[-i_mb_stride+1][1];\ + i_mvc++;\ + }\ + if( i_mb_x > 0 )\ + {\ + mvc[i_mvc][0] = fenc_mv[-i_mb_stride-1][0];\ + mvc[i_mvc][1] = fenc_mv[-i_mb_stride-1][1];\ + i_mvc++;\ + }\ + }\ + m.mvp[0] = x264_median( mvc[0][0], mvc[1][0], mvc[2][0] );\ + m.mvp[1] = x264_median( mvc[0][1], mvc[1][1], mvc[2][1] ); + LOAD_MVP( m[l] ); + x264_me_search( h, &m[l], mvc, i_mvc ); i_bcost = X264_MIN( i_bcost, m[l].cost + 3 ); @@ -463,3 +466,57 @@ memcpy( h->fdec->i_row_satd, h->fenc->i_row_satd, h->sps->i_mb_height * sizeof(int) ); return cost; } + +int x264_rc_aq_motion( x264_t *h, int *sads ) +{ + x264_mb_analysis_t a; + x264_me_t m; + const int i_stride = h->fenc->i_stride[0]; + const int i_mb_stride = h->sps->i_mb_width; + int i_mb_x, i_mb_y; + x264_frame_t *fref = NULL; + int i; + + for( i=0; h->frames.current[i] && !fref; i++ ) + if( h->frames.current[i]->i_frame == h->fenc->i_frame+1 ) + fref = h->frames.current[i]; + for( i=0; h->frames.next[i] && !fref; i++ ) + if( h->frames.next[i]->i_frame == h->fenc->i_frame+1 ) + fref = h->frames.next[i]; + if( !fref ) + return 0; + x264_frame_expand_border( fref ); + + x264_lowres_context_init( h, &a ); + h->mb.i_me_method = X264_ME_DIA; + h->mb.i_subpel_refine = 1; + h->mb.b_chroma_me = 0; + + m.i_pixel = PIXEL_16x16; + m.p_cost_mv = a.p_cost_mv; + m.i_stride[0] = i_stride; + m.p_fenc[0] = h->mb.pic.p_fenc[0]; + + for( i_mb_y = 0; i_mb_y < h->sps->i_mb_height; i_mb_y++ ) + for( i_mb_x = 0; i_mb_x < h->sps->i_mb_width; i_mb_x++ ) + { + int i_mb_xy = i_mb_x+i_mb_y*i_mb_stride; + int pix_off = 16*(i_mb_x+i_mb_y*i_stride); + int mvc[4][2] = {{0}}, i_mvc; + int16_t (*fenc_mv)[2] = &h->fenc->mv[0][i_mb_xy]; + + h->mc.copy[PIXEL_16x16]( m.p_fenc[0], FENC_STRIDE, + &h->fenc->plane[0][pix_off], i_stride, 16 ); + m.p_fref[0] = &fref->plane[0][pix_off]; + LOAD_MVP( m ); + + x264_me_search( h, &m, mvc, i_mvc ); + + fenc_mv[0][0] = m.mv[0]; + fenc_mv[0][1] = m.mv[1]; + + sads[i_mb_xy] = m.cost - m.cost_mv; + } + + return 1; +} Index: encoder/encoder.c =================================================================== --- encoder/encoder.c (revision 540) +++ encoder/encoder.c (working copy) @@ -359,6 +359,7 @@ h->param.rc.i_rc_method = X264_RC_CQP; h->param.rc.f_ip_factor = 1; h->param.rc.f_pb_factor = 1; + h->param.rc.i_qp_min = 0; h->param.analyse.b_transform_8x8 = 0; h->param.analyse.b_psnr = 0; h->param.analyse.i_chroma_qp_offset = 0; @@ -548,6 +549,8 @@ /* Init frames. */ h->frames.i_delay = h->param.i_bframe; + if( h->param.rc.i_aq_tcplx ) + h->frames.i_delay++; h->frames.i_max_ref0 = h->param.i_frame_reference; h->frames.i_max_ref1 = h->sps->vui.i_num_reorder_frames; h->frames.i_max_dpb = h->sps->vui.i_max_dec_frame_buffering + 1; @@ -958,6 +961,7 @@ } h->mb.i_last_qp = h->sh.i_qp; h->mb.i_last_dqp = 0; + x264_macroblock_thread_init( h ); for( mb_xy = h->sh.i_first_mb, i_skip = 0; mb_xy < h->sh.i_last_mb; mb_xy++ ) { Index: encoder/ratecontrol.c =================================================================== --- encoder/ratecontrol.c (revision 540) +++ encoder/ratecontrol.c (working copy) @@ -150,6 +150,9 @@ int bframes; /* # consecutive B-frames before this P-frame */ int bframe_bits; /* total cost of those frames */ + /* psy stuff */ + int *mb_aq_offs; /* per-macroblock offset from the frame's qp */ + int i_zones; x264_zone_t *zones; }; @@ -161,7 +164,9 @@ static void update_vbv( x264_t *h, int bits ); static double predict_size( predictor_t *p, double q, double var ); static void update_predictor( predictor_t *p, double q, double var, double bits ); +static void adaptive_quant( x264_t *h ); int x264_rc_analyse_slice( x264_t *h ); +int x264_rc_aq_motion( x264_t *h, int *sads ); /* Terminology: * qp = h.264's quantizer @@ -463,6 +468,12 @@ x264_free( p ); } + if( h->param.rc.i_aq_tcplx && h->param.i_bframe ) + x264_log( h, X264_LOG_WARNING, "tcplx mask has not been tested with B-frames. use at your own risk.\n" ); + + if( h->param.rc.i_aq_tcplx ) + rc->mb_aq_offs = x264_malloc( h->mb.i_mb_count * sizeof(int) ); + return 0; } @@ -550,6 +561,7 @@ } x264_free( rc->psz_stat_file_tmpname ); } + x264_free( rc->mb_aq_offs ); x264_free( rc->entry ); x264_free( rc->zones ); x264_free( rc ); @@ -619,6 +631,9 @@ q = rc->qp_constant[ i_slice_type ]; rc->qpm = rc->qp = q; } + + if( h->param.rc.i_aq_tcplx ) + adaptive_quant( h ); } double predict_row_size( x264_t *h, int y, int qp ) @@ -713,7 +728,11 @@ int x264_ratecontrol_qp( x264_t *h ) { - return h->rc->qpm; + x264_ratecontrol_t *rc = h->rc; + int qp = rc->qpm; + if( rc->mb_aq_offs ) + qp += rc->mb_aq_offs[h->mb.i_mb_xy]; + return x264_clip3( qp, h->param.rc.i_qp_min, h->param.rc.i_qp_max ); } /* In 2pass, force the same frame types as in the 1st pass */ @@ -1504,4 +1523,19 @@ return 0; } +static void adaptive_quant( x264_t *h ) +{ + x264_ratecontrol_t *rc = h->rc; + int mb_xy; + int valid = x264_rc_aq_motion( h, rc->mb_aq_offs ); + if(!valid) + { + memset( rc->mb_aq_offs, 0, h->mb.i_mb_count*sizeof(int) ); + return; + } + for( mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ ) + { + rc->mb_aq_offs[mb_xy] = x264_clip3( rc->mb_aq_offs[mb_xy] * h->param.rc.i_aq_tcplx >> 12, 0, 6 ); + } +} Index: x264.c =================================================================== --- x264.c (revision 540) +++ x264.c (working copy) @@ -186,6 +186,8 @@ " --qcomp QP curve compression: 0.0 => CBR, 1.0 => CQP [%.2f]\n" " --cplxblur Reduce fluctuations in QP (before curve compression) [%.1f]\n" " --qblur Reduce fluctuations in QP (after curve compression) [%.1f]\n" + " --aq-tcplx Increase QP in MBs that won't be used for\n" + " inter prediction [%d]\n" "\n" " --zones //...\n" " Tweak the bitrate of some regions of the video\n" @@ -315,6 +317,7 @@ defaults->rc.f_qcompress, defaults->rc.f_complexity_blur, defaults->rc.f_qblur, + defaults->rc.i_aq_tcplx, strtable_lookup( x264_direct_pred_names, defaults->analyse.i_direct_mv_pred ), strtable_lookup( x264_motion_est_names, defaults->analyse.i_me_method ), defaults->analyse.i_me_range, @@ -390,6 +393,7 @@ { int b_error = 0; int long_options_index; +#define OPT_AQ_TCPLX 942 #define OPT_QPMIN 256 #define OPT_QPMAX 257 #define OPT_QPSTEP 258 @@ -512,6 +516,7 @@ { "cplxblur",required_argument, NULL, OPT_CPLXBLUR }, { "zones", required_argument, NULL, OPT_ZONES }, { "qpfile", required_argument, NULL, OPT_QPFILE }, + { "aq-tcplx", required_argument, NULL, OPT_AQ_TCPLX }, { "threads", required_argument, NULL, OPT_THREADS }, { "thread-input", no_argument, NULL, OPT_THREAD_INPUT }, { "no-psnr", no_argument, NULL, OPT_NOPSNR }, @@ -813,6 +818,9 @@ param->i_scenecut_threshold = -1; param->b_bframe_adaptive = 0; break; + case OPT_AQ_TCPLX: + param->rc.i_aq_tcplx = atoi(optarg); + break; case OPT_THREADS: param->i_threads = atoi(optarg); break; Index: common/macroblock.c =================================================================== --- common/macroblock.c (revision 540) +++ common/macroblock.c (working copy) @@ -924,6 +924,25 @@ memset( h->mb.cache.skip, 0, X264_SCAN8_SIZE * sizeof( int8_t ) ); } +void x264_macroblock_thread_init( x264_t *h ) +{ + /* fdec: fenc: + * yyyyyyy + * yYYYY YYYY + * yYYYY YYYY + * yYYYY YYYY + * yYYYY YYYY + * uuu vvv UUVV + * uUU vVV UUVV + * uUU vVV + */ + h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; + h->mb.pic.p_fenc[1] = h->mb.pic.fenc_buf + 16*FENC_STRIDE; + h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 16*FENC_STRIDE + 8; + h->mb.pic.p_fdec[0] = h->mb.pic.fdec_buf + 2*FDEC_STRIDE; + h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE; + h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE + 16; +} void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) { @@ -946,23 +965,6 @@ h->mb.i_b4_xy = i_mb_4x4; h->mb.i_neighbour = 0; - /* fdec: fenc: - * yyyyyyy - * yYYYY YYYY - * yYYYY YYYY - * yYYYY YYYY - * yYYYY YYYY - * uuu vvv UUVV - * uUU vVV UUVV - * uUU vVV - */ - h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; - h->mb.pic.p_fenc[1] = h->mb.pic.fenc_buf + 16*FENC_STRIDE; - h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 16*FENC_STRIDE + 8; - h->mb.pic.p_fdec[0] = h->mb.pic.fdec_buf + 2*FDEC_STRIDE; - h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE; - h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE + 16; - /* load picture pointers */ for( i = 0; i < 3; i++ ) { Index: common/macroblock.h =================================================================== --- common/macroblock.h (revision 540) +++ common/macroblock.h (working copy) @@ -231,6 +231,7 @@ int x264_macroblock_cache_init( x264_t *h ); void x264_macroblock_slice_init( x264_t *h ); +void x264_macroblock_thread_init( x264_t *h ); void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ); void x264_macroblock_cache_save( x264_t *h ); void x264_macroblock_cache_end( x264_t *h ); Index: x264.h =================================================================== --- x264.h (revision 540) +++ x264.h (working copy) @@ -246,6 +246,8 @@ x264_zone_t *zones; /* ratecontrol overrides */ int i_zones; /* sumber of zone_t's */ char *psz_zones; /* alternate method of specifying zones */ + + int i_aq_tcplx; /* AQ */ } rc; /* Muxing parameters */