diff --git a/common/common.c b/common/common.c index 84bf49f..907a7b8 100644 --- a/common/common.c +++ b/common/common.c @@ -88,6 +88,7 @@ void x264_param_default( x264_param_t *param ) param->rc.f_vbv_buffer_init = 0.9; param->rc.i_qp_constant = 23; param->rc.f_rf_constant = 23; + param->rc.f_cssim = 0.98; param->rc.i_qp_min = 10; param->rc.i_qp_max = 51; param->rc.i_qp_step = 4; @@ -529,6 +530,11 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_rf_constant = atof(value); p->rc.i_rc_method = X264_RC_CRF; } + OPT("cssim") + { + p->rc.f_cssim = atof(value); + p->rc.i_rc_method = X264_RC_CSSIM; + } OPT("rc-lookahead") p->rc.i_lookahead = atoi(value); OPT2("qpmin", "qp-min") @@ -870,6 +876,7 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " rc=%s mbtree=%d", p->rc.i_rc_method == X264_RC_ABR ? ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_buffer_size ? "cbr" : "abr" ) + : p->rc.i_rc_method == X264_RC_CSSIM ? "cssim" : p->rc.i_rc_method == X264_RC_CRF ? "crf" : "cqp", p->rc.b_mb_tree ); if( p->rc.i_rc_method == X264_RC_ABR || p->rc.i_rc_method == X264_RC_CRF ) { @@ -889,14 +896,19 @@ char *x264_param2string( x264_param_t *p, int b_res ) } else if( p->rc.i_rc_method == X264_RC_CQP ) s += sprintf( s, " qp=%d", p->rc.i_qp_constant ); + else if( p->rc.i_rc_method == X264_RC_CSSIM ) + s += sprintf( s, " cssim=%.7f qpmin=%d qpmax=%d", p->rc.f_cssim, p->rc.i_qp_min, p->rc.i_qp_max ); if( !(p->rc.i_rc_method == X264_RC_CQP && p->rc.i_qp_constant == 0) ) { - s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor ); - if( p->i_bframe && !p->rc.b_mb_tree ) - s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor ); - s += sprintf( s, " aq=%d", p->rc.i_aq_mode ); - if( p->rc.i_aq_mode ) - s += sprintf( s, ":%.2f", p->rc.f_aq_strength ); + if( p->rc.i_rc_method != X264_RC_CSSIM ) + { + s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor ); + if( p->i_bframe && !p->rc.b_mb_tree ) + s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor ); + s += sprintf( s, " aq=%d", p->rc.i_aq_mode ); + if( p->rc.i_aq_mode ) + s += sprintf( s, ":%.2f", p->rc.f_aq_strength ); + } if( p->rc.psz_zones ) s += sprintf( s, " zones=%s", p->rc.psz_zones ); else if( p->rc.i_zones ) diff --git a/common/macroblock.c b/common/macroblock.c index 0a9f31e..58d320b 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -740,7 +740,7 @@ int x264_macroblock_cache_init( x264_t *h ) h->mb.i_neighbour8[3] = MB_LEFT|MB_TOP|MB_TOPLEFT; int buf_hpel = (h->param.i_width+48) * sizeof(int16_t); - int buf_ssim = h->param.analyse.b_ssim * 8 * (h->param.i_width/4+3) * sizeof(int); + int buf_ssim = (h->param.analyse.b_ssim || h->param.rc.i_rc_method == X264_RC_CSSIM) * 8 * (h->param.i_width/4+3) * sizeof(int); int me_range = X264_MIN(h->param.analyse.i_me_range, h->param.analyse.i_mv_range); int buf_tesa = (h->param.analyse.i_me_method >= X264_ME_ESA) * ((me_range*2+18) * sizeof(int16_t) + (me_range+4) * (me_range+1) * 4 * sizeof(mvsad_t)); diff --git a/encoder/analyse.c b/encoder/analyse.c index 44a8a50..3bc173a 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -2192,6 +2192,45 @@ static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t * } } +static void x264_rc_constant_ssim( x264_t *h ) +{ + int bak_trellis = h->mb.b_trellis; + int qp = h->mb.i_qp, bqp = h->mb.i_qp; + int prev_dir = 0; + float bdssim, tssim; + + x264_emms(); + bdssim = 2.0*9.0; + tssim = h->param.rc.f_cssim * 9.0; + h->mb.b_trellis = 0; + + while( qp >= h->param.rc.i_qp_min && qp <= h->param.rc.i_qp_max ) + { + float ssim, dssim; + int dir; + h->mb.i_type = I_16x16; + h->mb.b_transform_8x8 = 0; + h->mb.i_qp = qp; + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + x264_macroblock_encode( h ); + x264_emms(); + ssim = x264_pixel_ssim_wxh( &h->pixf, h->mb.pic.p_fenc[0], FENC_STRIDE, h->mb.pic.p_fdec[0], FDEC_STRIDE, 16, 16, h->scratch_buffer ); + dssim = fabs(ssim - tssim); + COPY2_IF_LT( bdssim, dssim, bqp, qp ); + dir = ssim < tssim ? -1 : 1; + if( dir * prev_dir < 0 ) + break; + if( dir == 1 && !h->mb.cbp[h->mb.i_mb_xy] ) + break; + qp += dir; + prev_dir = dir; + } + + h->mb.i_qp = bqp; + h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; + h->mb.b_trellis = bak_trellis; +} + /* Rate-distortion optimal QP selection. * FIXME: More than half of the benefit of this function seems to be * in the way it improves the coding of chroma DC (by decimating or @@ -2275,6 +2314,12 @@ int x264_macroblock_analyse( x264_t *h ) x264_mb_analyse_init( h, &analysis, h->mb.i_qp ); + if( h->param.rc.i_rc_method == X264_RC_CSSIM ) + { + x264_rc_constant_ssim( h ); + x264_mb_analyse_init( h, &analysis, h->mb.i_qp ); + } + /*--------------------------- Do the analysis ---------------------------*/ if( h->sh.i_type == SLICE_TYPE_I ) { diff --git a/encoder/encoder.c b/encoder/encoder.c index 6d28d09..6f33279 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -409,11 +409,12 @@ static int x264_validate_parameters( x264_t *h ) } } - if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 2 ) + if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 3 ) { x264_log( h, X264_LOG_ERROR, "no ratecontrol method specified\n" ); return -1; } + h->param.rc.f_cssim = x264_clip3f( h->param.rc.f_cssim, 0.0, 1.0 ); h->param.rc.f_rf_constant = x264_clip3f( h->param.rc.f_rf_constant, 0, 51 ); h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, 51 ); if( h->param.rc.i_rc_method == X264_RC_CRF ) @@ -452,6 +453,14 @@ static int x264_validate_parameters( x264_t *h ) h->param.rc.i_aq_mode = 0; h->param.rc.b_mb_tree = 0; } + if( h->param.rc.i_rc_method == X264_RC_CSSIM ) + { + h->param.rc.f_rf_constant = 26.f; + h->param.rc.i_qp_constant = 26; + h->param.rc.b_mb_tree = 0; + h->param.rc.f_ip_factor = 1; + h->param.rc.f_pb_factor = 1; + } h->param.rc.i_qp_max = x264_clip3( h->param.rc.i_qp_max, 0, 51 ); h->param.rc.i_qp_min = x264_clip3( h->param.rc.i_qp_min, 0, h->param.rc.i_qp_max ); @@ -570,8 +579,8 @@ static int x264_validate_parameters( x264_t *h ) h->param.rc.f_aq_strength = x264_clip3f( h->param.rc.f_aq_strength, 0, 3 ); if( h->param.rc.f_aq_strength == 0 ) h->param.rc.i_aq_mode = 0; - /* MB-tree requires AQ to be on, even if the strength is zero. */ - if( !h->param.rc.i_aq_mode && h->param.rc.b_mb_tree ) + /* MB-tree or CSSIM requires AQ to be on, even if the strength is zero. */ + if( (!h->param.rc.i_aq_mode && h->param.rc.b_mb_tree) || (h->param.rc.i_rc_method == X264_RC_CSSIM) ) { h->param.rc.i_aq_mode = 1; h->param.rc.f_aq_strength = 0; @@ -770,6 +779,7 @@ x264_t *x264_encoder_open ( x264_param_t *param ) h->frames.b_have_lowres = !h->param.rc.b_stat_read && ( h->param.rc.i_rc_method == X264_RC_ABR || h->param.rc.i_rc_method == X264_RC_CRF + || h->param.rc.i_rc_method == X264_RC_CSSIM || h->param.i_bframe_adaptive || h->param.i_scenecut_threshold || h->param.rc.b_mb_tree ); @@ -826,8 +836,9 @@ x264_t *x264_encoder_open ( x264_param_t *param ) h->out.i_nal = 0; h->out.i_bitstream = X264_MAX( 1000000, h->param.i_width * h->param.i_height * 4 - * ( h->param.rc.i_rc_method == X264_RC_ABR ? pow( 0.95, h->param.rc.i_qp_min ) - : pow( 0.95, h->param.rc.i_qp_constant ) * X264_MAX( 1, h->param.rc.f_ip_factor ))); + * ((h->param.rc.i_rc_method == X264_RC_ABR || h->param.rc.i_rc_method == X264_RC_CSSIM) + ? pow( 0.95, h->param.rc.i_qp_min ) + : pow( 0.95, h->param.rc.i_qp_constant ) * X264_MAX( 1, h->param.rc.f_ip_factor ))); h->thread[0] = h; h->i_thread_num = 0; diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 47491d9..bcebdf5 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -322,7 +322,7 @@ int x264_ratecontrol_new( x264_t *h ) CHECKED_MALLOCZERO( h->rc, h->param.i_threads * sizeof(x264_ratecontrol_t) ); rc = h->rc; - rc->b_abr = h->param.rc.i_rc_method != X264_RC_CQP && !h->param.rc.b_stat_read; + rc->b_abr = (h->param.rc.i_rc_method != X264_RC_CQP && h->param.rc.i_rc_method != X264_RC_CSSIM) && !h->param.rc.b_stat_read; rc->b_2pass = h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.b_stat_read; /* FIXME: use integers */ @@ -345,16 +345,16 @@ int x264_ratecontrol_new( x264_t *h ) rc->last_non_b_pict_type = -1; rc->cbr_decay = 1.0; - if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.b_stat_read ) + if( h->param.rc.i_rc_method != X264_RC_ABR && h->param.rc.b_stat_read ) { - x264_log(h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n"); + x264_log(h, X264_LOG_ERROR, "Non-ABR rate control is incompatible with 2pass.\n"); return -1; } if( h->param.rc.i_vbv_buffer_size ) { - if( h->param.rc.i_rc_method == X264_RC_CQP ) + if( h->param.rc.i_rc_method == X264_RC_CQP || h->param.rc.i_rc_method == X264_RC_CSSIM ) { - x264_log(h, X264_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n"); + x264_log(h, X264_LOG_WARNING, "VBV is incompatible with constant %s, ignored.\n", h->param.rc.i_rc_method == X264_RC_CQP ? "QP" : "SSIM"); h->param.rc.i_vbv_max_bitrate = 0; h->param.rc.i_vbv_buffer_size = 0; } diff --git a/x264.c b/x264.c index 32e6570..25c49c3 100644 --- a/x264.c +++ b/x264.c @@ -203,6 +203,7 @@ static void Help( x264_param_t *defaults, int b_longhelp ) H0( " -q, --qp Set QP (0-51, 0=lossless)\n" ); H0( " -B, --bitrate Set bitrate (kbit/s)\n" ); H0( " --crf Quality-based VBR (0-51, 0=lossless) [%.1f]\n", defaults->rc.f_rf_constant ); + H1( " --cssim Force all macroblocks to this SSIM\n" ); H0( " --rc-lookahead Number of frames for frametype lookahead [%d]\n", defaults->rc.i_lookahead ); H0( " --vbv-maxrate Max local bitrate (kbit/s) [%d]\n", defaults->rc.i_vbv_max_bitrate ); H0( " --vbv-bufsize Set size of the VBV buffer (kbit) [%d]\n", defaults->rc.i_vbv_buffer_size ); @@ -406,6 +407,7 @@ static struct option long_options[] = { "qpmax", required_argument, NULL, 0 }, { "qpstep", required_argument, NULL, 0 }, { "crf", required_argument, NULL, 0 }, + { "cssim", required_argument, NULL, 0 }, { "rc-lookahead",required_argument, NULL, 0 }, { "ref", required_argument, NULL, 'r' }, { "asm", required_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 964e093..b525512 100644 --- a/x264.h +++ b/x264.h @@ -86,6 +86,7 @@ typedef struct x264_t x264_t; #define X264_RC_CQP 0 #define X264_RC_CRF 1 #define X264_RC_ABR 2 +#define X264_RC_CSSIM 3 #define X264_AQ_NONE 0 #define X264_AQ_VARIANCE 1 #define X264_AQ_AUTOVARIANCE 2 @@ -263,6 +264,7 @@ typedef struct x264_param_t int i_bitrate; float f_rf_constant; /* 1pass VBR, nominal QP */ + float f_cssim; float f_rate_tolerance; int i_vbv_max_bitrate; int i_vbv_buffer_size;