From: Laurent Aimar Date: Sat, 28 Aug 2004 22:14:26 +0000 (+0000) Subject: * all: 2pass patch by Loren Merritt X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9116d300befee74c92ff3ac9fe7625a57dafab48;p=libx264 * all: 2pass patch by Loren Merritt "Mostly borrowed from libavcodec. There is not much theoretical basis behind my choice of defaults for rc_eq, qcompress, qblur, and ip_factor." git-svn-id: svn://svn.videolan.org/x264/trunk@40 df754926-b1dd-0310-bc7b-ec298dee348c --- diff --git a/Jamfile b/Jamfile index 370aa3b2..652ed6d9 100644 --- a/Jamfile +++ b/Jamfile @@ -24,7 +24,7 @@ SOURCES_C = core/mc.c core/predict.c core/pixel.c core/macroblock.c core/common.c core/mdate.c core/csp.c encoder/analyse.c encoder/me.c encoder/ratecontrol.c encoder/set.c encoder/macroblock.c encoder/cabac.c encoder/cavlc.c - encoder/encoder.c ; + encoder/encoder.c encoder/eval.c ; SOURCES_X86 = core/i386/cpu.asm ; SOURCES_MMX = core/i386/mc-c.c core/i386/dct-c.c core/i386/predict.c core/i386/dct.asm core/i386/pixel.asm core/i386/mc.asm ; diff --git a/core/common.c b/core/common.c index ac975626..b8a157ed 100644 --- a/core/common.c +++ b/core/common.c @@ -68,17 +68,25 @@ void x264_param_default( x264_param_t *param ) param->b_cabac = 0; param->i_cabac_init_idc = -1; - param->b_cbr = 0; - param->i_bitrate = 3000; - param->i_rc_buffer_size = 0; - param->i_rc_init_buffer = 0; - param->i_rc_sens = 100; - param->i_qp_constant = 26; - param->i_qp_min = 0; - param->i_qp_max = 51; - param->i_qp_step = 4; - param->f_ip_factor = 2.0; - param->f_pb_factor = 2.0; + param->rc.b_cbr = 0; + param->rc.i_bitrate = 3000; + param->rc.i_rc_buffer_size = 0; + param->rc.i_rc_init_buffer = 0; + param->rc.i_rc_sens = 100; + param->rc.i_qp_constant = 26; + param->rc.i_qp_min = 0; + param->rc.i_qp_max = 51; + param->rc.i_qp_step = 4; + param->rc.f_ip_factor = 2.0; + param->rc.f_pb_factor = 2.0; + + param->rc.b_stat_write = 0; + param->rc.psz_stat_out = "x264_2pass.log"; + param->rc.b_stat_read = 0; + param->rc.psz_stat_in = "x264_2pass.log"; + param->rc.psz_rc_eq = "(tex^qComp)*(avgTex^(1-qComp))"; + param->rc.f_qcompress = 0.6; + param->rc.f_qblur = 0.5; /* Log */ param->pf_log = x264_log_default; diff --git a/core/common.h b/core/common.h index 935b7f0d..087778cc 100644 --- a/core/common.h +++ b/core/common.h @@ -224,6 +224,8 @@ struct x264_t int i_last_idr; /* How many I non IDR frames from last IDR */ int i_last_i; /* How many P/B frames from last I */ + + int i_input; /* Number of input frames already accepted */ } frames; /* current frame being encoded */ diff --git a/core/frame.c b/core/frame.c index eca2ab63..0ffc0cf3 100644 --- a/core/frame.c +++ b/core/frame.c @@ -68,6 +68,8 @@ x264_frame_t *x264_frame_new( x264_t *h ) frame->i_poc = -1; frame->i_type = X264_TYPE_AUTO; frame->i_qpplus1 = 0; + frame->i_pts = -1; + frame->i_frame = -1; return frame; } diff --git a/core/frame.h b/core/frame.h index da7c4576..14fbece2 100644 --- a/core/frame.h +++ b/core/frame.h @@ -31,6 +31,7 @@ typedef struct int i_type; int i_qpplus1; int64_t i_pts; + int i_frame; /* Presentation frame number */ /* YUV buffer */ int i_plane; diff --git a/encoder/encoder.c b/encoder/encoder.c index bf4003dc..5fdf21a9 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -298,8 +298,14 @@ x264_t *x264_encoder_open ( x264_param_t *param ) x264_t *h = x264_malloc( sizeof( x264_t ) ); int i; - /* */ + /* Create a copy of param */ memcpy( &h->param, param, sizeof( x264_param_t ) ); + if( h->param.rc.psz_stat_out ) + h->param.rc.psz_stat_out = strdup( h->param.rc.psz_stat_out ); + if( h->param.rc.psz_stat_in ) + h->param.rc.psz_stat_in = strdup( h->param.rc.psz_stat_in ); + if( h->param.rc.psz_rc_eq ) + h->param.rc.psz_rc_eq = strdup( h->param.rc.psz_rc_eq ); /* Check parameters validity */ if( param->i_width <= 0 || param->i_height <= 0 ) @@ -417,6 +423,7 @@ x264_t *x264_encoder_open ( x264_param_t *param ) } h->frames.i_last_idr = h->param.i_idrframe; h->frames.i_last_i = h->param.i_iframe; + h->frames.i_input = 0; h->i_ref0 = 0; h->i_ref1 = 0; @@ -896,8 +903,22 @@ int x264_encoder_encode( x264_t *h, x264_frame_copy_picture( h, fenc, pic ); + fenc->i_frame = h->frames.i_input++; + /* 2: get its type */ - if( ( h->frames.i_last_i + 1 >= h->param.i_iframe && h->frames.i_last_idr + 1 >= h->param.i_idrframe ) || + if( h->param.rc.b_stat_read ) + { + /* XXX: trusts that the first pass used compatible B and IDR frequencies */ + fenc->i_type = x264_ratecontrol_slice_type( h, fenc->i_frame ); + if( fenc->i_type == X264_TYPE_I && h->frames.next[0] == NULL && + h->frames.i_last_idr + 1 >= h->param.i_idrframe ) + { + fenc->i_type = X264_TYPE_IDR; + h->i_poc = 0; + h->i_frame_num = 0; + } + } + else if( ( h->frames.i_last_i + 1 >= h->param.i_iframe && h->frames.i_last_idr + 1 >= h->param.i_idrframe ) || pic->i_type == X264_TYPE_IDR ) { /* IDR */ @@ -1101,7 +1122,7 @@ do_encode: x264_slice_write( h, i_nal_type, i_nal_ref_idc ); /* XXX: this scene cut won't work with B frame (it may never create IDR -> bad) */ - if( i_slice_type != SLICE_TYPE_I) + if( i_slice_type != SLICE_TYPE_I && !h->param.rc.b_stat_read ) { int i_bias; @@ -1127,7 +1148,7 @@ do_encode: h->i_frame - 1, h->out.nal[h->out.i_nal-1].i_payload, h->i_last_intra_size, h->i_last_inter_size, - i_mb_i, i_mb, 100 * i_mb_i / i_mb, i_bias, + i_mb_i, i_mb - i_mb_i, 100 * i_mb_i / i_mb, i_bias, h->stat.frame.i_mb_count[P_SKIP], h->stat.frame.i_mb_count[P_L0] ); @@ -1416,6 +1437,14 @@ void x264_encoder_close ( x264_t *h ) x264_frame_delete( h->frames.reference[i] ); } + /* param */ + if( h->param.rc.psz_stat_out ) + free( h->param.rc.psz_stat_out ); + if( h->param.rc.psz_stat_in ) + free( h->param.rc.psz_stat_in ); + if( h->param.rc.psz_rc_eq ) + free( h->param.rc.psz_rc_eq ); + /* rc */ x264_ratecontrol_delete( h ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 95bc90d6..da8e3529 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -5,6 +5,8 @@ * $Id: ratecontrol.c,v 1.1 2004/06/03 19:27:08 fenrir Exp $ * * Authors: Måns Rullgård + * 2 pass code: Michael Niedermayer + * Loren Merritt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,32 +24,55 @@ *****************************************************************************/ #define _ISOC99_SOURCE - +#undef NDEBUG // always check asserts, the speed effect is far too small to disable them #include #include #include #include #include +#include #include "../core/common.h" #include "../core/cpu.h" +#include "../core/macroblock.h" #include "ratecontrol.h" #ifdef SYS_MACOSX #define exp2f(x) ( (float) exp2( (x) ) ) #endif + +typedef struct +{ + int pict_type; + float qscale; + int mv_bits; + int i_tex_bits; + int p_tex_bits; + int misc_bits; + uint64_t expected_bits; + int new_pict_type; + float new_qscale; + int new_qp; + int i_count; + int p_count; + int s_count; + int f_code; + int b_code; +} ratecontrol_entry_t; + struct x264_ratecontrol_t { /* constants */ - float fps; + double fps; int gop_size; int bitrate; - int nmb; /* number of MBs */ + int nmb; /* number of macroblocks in a frame */ int buffer_size; int rcbufrate; int init_qp; + /* 1st pass stuff */ int gop_qp; int buffer_fullness; int frames; /* frames in current gop */ @@ -67,13 +92,71 @@ struct x264_ratecontrol_t int nzcoeffs; /* # of 0-quantized coefficients */ int ncoeffs; /* total # of coefficients */ int overhead; + + /* 2pass stuff */ + FILE *p_stat_file_out; + + int num_entries; /* number of ratecontrol_entry_ts */ + ratecontrol_entry_t *entry; + double last_qscale; + double last_qscale_for[5]; /* last qscale for a specific pict type, used for max_diff & ipb factor stuff */ + int last_non_b_pict_type; + double lmin[5]; /* min qscale by frame type */ + double lmax[5]; + double i_cplx_sum[5]; /* estimated total texture bits in intra MBs at qscale=1 */ + double p_cplx_sum[5]; + double mv_bits_sum[5]; + int frame_count[5]; /* number of frames of each type */ }; + +static int init_pass2(x264_t *); +static float rate_estimate_qscale( x264_t *h, int pict_type ); + +/* Terminology: + * qp = h.264's quantizer + * qscale = an arbitrary linear scale, mappable to qp + */ +static inline double qp2qscale(double qp) +{ + return 0.85 * pow(2.0, ( qp - 12.0 ) / 6.0); +} +static inline double qscale2qp(double qscale) +{ + return 12.0 + 6.0 * log(qscale/0.85) / log(2.0); +} + +static inline double qscale2bits(ratecontrol_entry_t *rce, double qscale) +{ + if(qscale<=0.0) + { + fprintf(stderr, "qscale<=0.0\n"); + qscale = 0.1; + } + return (double)(rce->i_tex_bits + rce->p_tex_bits + 1) * rce->qscale / qscale; +} + +static inline double bits2qscale(ratecontrol_entry_t *rce, double bits) +{ + if(bits<0.9) + { + fprintf(stderr, "bits<0.9\n"); + bits = 1.0; + } + return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / bits; +} + + int x264_ratecontrol_new( x264_t *h ) { - x264_ratecontrol_t *rc = x264_malloc( sizeof( x264_ratecontrol_t ) ); + x264_ratecontrol_t *rc; float bpp; + int i; + /* Needed(?) for 2 pass */ + x264_cpu_restore( h->param.cpu ); + + h->rc = rc = x264_malloc( sizeof( x264_ratecontrol_t ) ); memset(rc, 0, sizeof(*rc)); /* FIXME: use integers */ @@ -83,15 +166,15 @@ int x264_ratecontrol_new( x264_t *h ) rc->fps = 25.0; rc->gop_size = h->param.i_iframe; - rc->bitrate = h->param.i_bitrate * 1000; + rc->bitrate = h->param.rc.i_bitrate * 1000; rc->nmb = ((h->param.i_width + 15) / 16) * ((h->param.i_height + 15) / 16); - rc->qp = h->param.i_qp_constant; + rc->qp = h->param.rc.i_qp_constant; rc->qpa = rc->qp; rc->qpm = rc->qp; - rc->buffer_size = h->param.i_rc_buffer_size * 1000; - rc->buffer_fullness = h->param.i_rc_init_buffer; + rc->buffer_size = h->param.rc.i_rc_buffer_size * 1000; + rc->buffer_fullness = h->param.rc.i_rc_init_buffer; rc->rcbufrate = rc->bitrate / rc->fps; if(rc->buffer_size < rc->rcbufrate){ @@ -125,7 +208,108 @@ int x264_ratecontrol_new( x264_t *h ) x264_log(h, X264_LOG_DEBUG, "%f fps, %i bps, bufsize %i\n", rc->fps, rc->bitrate, rc->buffer_size); - h->rc = rc; + + for( i = 0; i < 5; i++ ) + { + rc->last_qscale_for[i] = qp2qscale(26); + rc->lmin[i] = qp2qscale( h->param.rc.i_qp_min ); + rc->lmax[i] = qp2qscale( h->param.rc.i_qp_max ); + } +#if 0 // FIXME: do we want to assign lmin/lmax based on ip_factor, or leave them all the same? + rc->lmin[SLICE_TYPE_I] /= fabs(h->param.f_ip_factor); + rc->lmax[SLICE_TYPE_I] /= fabs(h->param.f_ip_factor); + rc->lmin[SLICE_TYPE_B] *= fabs(h->param.f_pb_factor); + rc->lmax[SLICE_TYPE_B] *= fabs(h->param.f_pb_factor); +#endif + + /* Load stat file and init 2pass algo */ + if( h->param.rc.b_stat_read ) + { + int stats_size; + char *p, *stats_in; + FILE *stats_file; + + /* read 1st pass stats */ + assert( h->param.rc.psz_stat_in ); + stats_file = fopen( h->param.rc.psz_stat_in, "r"); + if(!stats_file) + { + x264_log(h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n"); + return -1; + } + // FIXME: error checking + fseek(stats_file, 0, SEEK_END); + stats_size = ftell(stats_file); + fseek(stats_file, 0, SEEK_SET); + stats_in = x264_malloc(stats_size+10); + fread(stats_in, 1, stats_size, stats_file); + fclose(stats_file); + + /* find number of pics */ + p = stats_in; + for(i=-1; p; i++){ + p = strchr(p+1, ';'); + } + i += h->param.i_bframe; + rc->entry = (ratecontrol_entry_t*) x264_malloc(i*sizeof(ratecontrol_entry_t)); + memset(rc->entry, 0, i*sizeof(ratecontrol_entry_t)); + rc->num_entries= i; + + /* init all to skipped p frames */ + for(i=0; inum_entries; i++){ + ratecontrol_entry_t *rce = &rc->entry[i]; + rce->pict_type = rce->new_pict_type = SLICE_TYPE_P; + rce->qscale = rce->new_qscale = qp2qscale(20); + rce->misc_bits = rc->nmb + 10; + rce->new_qp = 0; + } + + /* read stats */ + p = stats_in; + for(i=0; i < rc->num_entries - h->param.i_bframe; i++){ + ratecontrol_entry_t *rce; + int picture_number; + int e; + char *next; + float qp; + + next= strchr(p, ';'); + if(next){ + (*next)=0; //sscanf is unbelievably slow on looong strings + next++; + } + e = sscanf(p, " in:%d ", &picture_number); + + assert(picture_number >= 0); + assert(picture_number < rc->num_entries); + rce = &rc->entry[picture_number]; + + e += sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d", + &rce->pict_type, &qp, &rce->i_tex_bits, &rce->p_tex_bits, + &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count); + if(e != 10){ + x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); + return -1; + } + rce->qscale = qp2qscale(qp); + p = next; + } + + x264_free(stats_in); + + if(init_pass2(h) < 0) return -1; + } + + /* Open output file */ + if( h->param.rc.b_stat_write ) + { + rc->p_stat_file_out = fopen( h->param.rc.psz_stat_out, "w" ); + if( rc->p_stat_file_out == NULL ) + { + x264_log(h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n"); + return -1; + } + } return 0; } @@ -133,6 +317,11 @@ int x264_ratecontrol_new( x264_t *h ) void x264_ratecontrol_delete( x264_t *h ) { x264_ratecontrol_t *rc = h->rc; + + if( rc->p_stat_file_out ) + fclose( rc->p_stat_file_out ); + if( rc->entry ) + x264_free(rc->entry); x264_free( rc ); } @@ -146,12 +335,26 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) float kp; int gbuf; - if(!h->param.b_cbr) - return; + rc->slice_type = i_slice_type; + /* Needed ? */ x264_cpu_restore( h->param.cpu ); - rc->slice_type = i_slice_type; + if( h->param.rc.b_stat_read ) + { + int frame = h->fenc->i_frame; + ratecontrol_entry_t *rce = &h->rc->entry[frame]; + + assert( frame >= 0 && frame < rc->num_entries ); + + rce->new_qscale = rate_estimate_qscale( h, i_slice_type ); + rc->qpm = rc->qp = rce->new_qp = (int)(qscale2qp(rce->new_qscale) + 0.5); + return; + } + else if( !h->param.rc.b_cbr ) + { + return; + } switch(i_slice_type){ case SLICE_TYPE_I: @@ -170,13 +373,13 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) #endif qp = x264_clip3(qp, rc->gop_qp - 4, rc->gop_qp + 4); qp = - x264_clip3(qp, h->param.i_qp_min, h->param.i_qp_max); + x264_clip3(qp, h->param.rc.i_qp_min, h->param.rc.i_qp_max); rc->gop_qp = qp; } else if(rc->frames > 4){ rc->gop_qp = rc->init_qp; } - kp = h->param.f_ip_factor * h->param.f_pb_factor; + kp = h->param.rc.f_ip_factor * h->param.rc.f_pb_factor; x264_log(h, X264_LOG_DEBUG,"gbuf=%i bits_gop=%i frames=%i gop_qp=%i\n", gbuf, rc->bits_gop, rc->frames, rc->gop_qp); @@ -188,7 +391,7 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) break; case SLICE_TYPE_P: - kp = h->param.f_pb_factor; + kp = h->param.rc.f_pb_factor; break; case SLICE_TYPE_B: @@ -209,8 +412,8 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) gbits = rc->bits_gop - rc->bits_last_gop; fbits = kp * gbits / - (h->param.f_ip_factor * h->param.f_pb_factor * iframes + - h->param.f_pb_factor * pframes + bframes); + (h->param.rc.f_ip_factor * h->param.rc.f_pb_factor * iframes + + h->param.rc.f_pb_factor * pframes + bframes); minbits = rc->buffer_fullness + rc->rcbufrate - rc->buffer_size; if(minbits < 0) @@ -231,9 +434,9 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) else zn = 0; zn = x264_clip3(zn, 0, rc->ncoeffs); - dqp = h->param.i_rc_sens * exp2f((float) rc->qpa / 6) * + dqp = h->param.rc.i_rc_sens * exp2f((float) rc->qpa / 6) * (zn - rc->nzcoeffs) / rc->nzcoeffs; - dqp = x264_clip3(dqp, -h->param.i_qp_step, h->param.i_qp_step); + dqp = x264_clip3(dqp, -h->param.rc.i_qp_step, h->param.rc.i_qp_step); rc->qp = rc->qpa + dqp; } @@ -246,7 +449,7 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type ) else if(rc->fbits < 1.2 * minbits) rc->qp -= 1; - rc->qp = x264_clip3(rc->qp, h->param.i_qp_min, h->param.i_qp_max); + rc->qp = x264_clip3(rc->qp, h->param.rc.i_qp_min, h->param.rc.i_qp_max); rc->qpm = rc->qp; x264_log(h, X264_LOG_DEBUG, "fbits=%i, qp=%i, z=%i, min=%i, max=%i\n", @@ -269,7 +472,7 @@ void x264_ratecontrol_mb( x264_t *h, int bits ) int dqp; int i; - if( !h->param.b_cbr ) + if( !h->param.rc.b_cbr || h->param.rc.b_stat_read ) return; x264_cpu_restore( h->param.cpu ); @@ -302,12 +505,12 @@ void x264_ratecontrol_mb( x264_t *h, int bits ) zn = 0; zn = x264_clip3(zn, 0, rcoeffs); enz = rc->nzcoeffs * (rc->nmb - rc->mb) / rc->mb; - dqp = (float) 2*h->param.i_rc_sens * exp2f((float) rc->qps / rc->mb / 6) * + dqp = (float) 2*h->param.rc.i_rc_sens * exp2f((float) rc->qps / rc->mb / 6) * (zn - enz) / enz; rc->qpm = x264_clip3(rc->qpm + dqp, rc->qp - 3, rc->qp + 3); if(rbits <= 0) rc->qpm++; - rc->qpm = x264_clip3(rc->qpm, h->param.i_qp_min, h->param.i_qp_max); + rc->qpm = x264_clip3(rc->qpm, h->param.rc.i_qp_min, h->param.rc.i_qp_max); } int x264_ratecontrol_qp( x264_t *h ) @@ -315,11 +518,48 @@ int x264_ratecontrol_qp( x264_t *h ) return h->rc->qpm; } +int x264_ratecontrol_slice_type( x264_t *h, int frame_num ) +{ + if( h->param.rc.b_stat_read ) + { + assert(frame_num < h->rc->num_entries); + switch( h->rc->entry[frame_num].new_pict_type ) + { + case SLICE_TYPE_I: + return X264_TYPE_I; + + case SLICE_TYPE_B: + return X264_TYPE_B; + + case SLICE_TYPE_P: + default: + return X264_TYPE_P; + } + } + else + { + return X264_TYPE_AUTO; + } +} + void x264_ratecontrol_end( x264_t *h, int bits ) { x264_ratecontrol_t *rc = h->rc; - if(!h->param.b_cbr) + if( h->param.rc.b_stat_write ) + { + fprintf( rc->p_stat_file_out, + "in:%d out:%d type:%d q:%.3f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d;\n", + h->fenc->i_frame, h->i_frame-1, + rc->slice_type, (float)rc->qpm, + h->stat.frame.i_itex_bits, h->stat.frame.i_ptex_bits, + h->stat.frame.i_hdr_bits, h->stat.frame.i_misc_bits, + h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_16x16], + h->stat.frame.i_mb_count[P_L0] + h->stat.frame.i_mb_count[P_8x8], + h->stat.frame.i_mb_count[P_SKIP]); + } + + if( !h->param.rc.b_cbr || h->param.rc.b_stat_read ) return; rc->buffer_fullness += rc->rcbufrate - bits; @@ -352,3 +592,292 @@ void x264_ratecontrol_end( x264_t *h, int bits ) rc->frames++; rc->mb = 0; } + +/**************************************************************************** + * 2 pass functions + ***************************************************************************/ +double x264_eval( char *s, double *const_value, const char **const_name, + double (**func1)(void *, double), const char **func1_name, + double (**func2)(void *, double, double), char **func2_name, + void *opaque ); + +/** + * modifies the bitrate curve from pass1 for one frame + */ +static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor) +{ + x264_ratecontrol_t *rcc= h->rc; + double bits; + //double q, avg_cplx; + const int pict_type = rce->new_pict_type; + + x264_cpu_restore( h->param.cpu ); + + //avg_cplx = (rcc->i_cplx_sum[pict_type] + rcc->p_cplx_sum[pict_type]) / rcc->frame_count[pict_type]; + + double const_values[]={ + rce->i_tex_bits * rce->qscale, + rce->p_tex_bits * rce->qscale, + (rce->i_tex_bits + rce->p_tex_bits) * rce->qscale, + rce->mv_bits / rcc->nmb, + (double)rce->i_count / rcc->nmb, + (double)rce->p_count / rcc->nmb, + (double)rce->s_count / rcc->nmb, + rce->pict_type == SLICE_TYPE_I, + rce->pict_type == SLICE_TYPE_P, + rce->pict_type == SLICE_TYPE_B, + h->param.rc.f_qcompress, + rcc->i_cplx_sum[SLICE_TYPE_I] / rcc->frame_count[SLICE_TYPE_I], + rcc->i_cplx_sum[SLICE_TYPE_P] / rcc->frame_count[SLICE_TYPE_P], + rcc->p_cplx_sum[SLICE_TYPE_P] / rcc->frame_count[SLICE_TYPE_P], + rcc->p_cplx_sum[SLICE_TYPE_B] / rcc->frame_count[SLICE_TYPE_B], + (rcc->i_cplx_sum[pict_type] + rcc->p_cplx_sum[pict_type]) / rcc->frame_count[pict_type], + 0 + }; + static const char *const_names[]={ + "iTex", + "pTex", + "tex", + "mv", + "iCount", + "pCount", + "sCount", + "isI", + "isP", + "isB", + "qComp", + "avgIITex", + "avgPITex", + "avgPPTex", + "avgBPTex", + "avgTex", + NULL + }; + static double (*func1[])(void *, double)={ + (void *)bits2qscale, + (void *)qscale2bits, + NULL + }; + static const char *func1_names[]={ + "bits2qp", + "qp2bits", + NULL + }; + + bits = x264_eval((char*)h->param.rc.psz_rc_eq, const_values, const_names, func1, func1_names, NULL, NULL, rce); + + bits *= rate_factor; + if(bits<0.0) bits=0.0; + bits += 1.0; //avoid 1/0 issues + + /* I/B difference */ + if( pict_type==SLICE_TYPE_I && h->param.rc.f_ip_factor > 0 ) + bits *= h->param.rc.f_ip_factor; + else if( pict_type==SLICE_TYPE_B && h->param.rc.f_pb_factor > 0 ) + bits /= h->param.rc.f_pb_factor; + + return bits2qscale(rce, bits); +} + +static double get_diff_limited_q(x264_t *h, ratecontrol_entry_t *rce, double q) +{ + x264_ratecontrol_t *rcc = h->rc; + const int pict_type = rce->new_pict_type; + + // force I/B quants as a function of P quants + const double last_p_q = rcc->last_qscale_for[SLICE_TYPE_P]; + const double last_non_b_q= rcc->last_qscale_for[rcc->last_non_b_pict_type]; + if( pict_type == SLICE_TYPE_I && h->param.rc.f_ip_factor < 0 ) + q = last_p_q / -h->param.rc.f_ip_factor; + else if(pict_type==SLICE_TYPE_B && h->param.rc.f_pb_factor < 0) + q = last_non_b_q * -h->param.rc.f_pb_factor; + + /* last qscale / qdiff stuff */ + if(rcc->last_non_b_pict_type==pict_type || pict_type!=SLICE_TYPE_I) + { + double last_q = rcc->last_qscale_for[pict_type]; + const double max_qscale = qp2qscale(qscale2qp(last_q) + h->param.rc.i_qp_step); + const double min_qscale = qp2qscale(qscale2qp(last_q) - h->param.rc.i_qp_step); + + if (q > max_qscale) q = max_qscale; + else if(q < min_qscale) q = min_qscale; + } + + rcc->last_qscale_for[pict_type] = q; //Note we can't do that after blurring + if(pict_type!=SLICE_TYPE_B) + rcc->last_non_b_pict_type = pict_type; + return q; +} + +static double modify_qscale( x264_t *h, ratecontrol_entry_t *rce, double q ) +{ + x264_ratecontrol_t *rcc = h->rc; + const int pict_type = rce->new_pict_type; + double lmin = rcc->lmin[pict_type]; + double lmax = rcc->lmax[pict_type]; + + if(lmin==lmax /* || !h->param.b_qsquish */){ + if (qlmax) q = lmax; + }else{ + double min2 = log(lmin); + double max2 = log(lmax); + + q = log(q); + q = (q - min2)/(max2-min2) - 0.5; + q *= -4.0; + q = 1.0/(1.0 + exp(q)); + q = q*(max2-min2) + min2; + + q = exp(q); + } + return q; +} + +// update qscale for 1 frame based on actual bits used so far +static float rate_estimate_qscale(x264_t *h, int pict_type) +{ + float q; + float br_compensation; + double diff; + int picture_number = h->fenc->i_frame; + x264_ratecontrol_t *rcc = h->rc; + ratecontrol_entry_t *rce; + double lmin = rcc->lmin[pict_type]; + double lmax = rcc->lmax[pict_type]; + int64_t wanted_bits; + int64_t total_bits = 8*(h->stat.i_slice_size[SLICE_TYPE_I] + + h->stat.i_slice_size[SLICE_TYPE_P] + + h->stat.i_slice_size[SLICE_TYPE_B]); + +//printf("input_pic_num:%d pic_num:%d frame_rate:%d\n", s->input_picture_number, s->picture_number, s->frame_rate); + + rce = &rcc->entry[picture_number]; + + if(pict_type!=SLICE_TYPE_I) + assert(pict_type == rce->new_pict_type); + + wanted_bits = rce->expected_bits; + + diff = total_bits - wanted_bits; + br_compensation = (rcc->buffer_size - diff) / rcc->buffer_size; + if(br_compensation<=0.0) br_compensation=0.001; + + q = rce->new_qscale / br_compensation; + + if (qlmax) q=lmax; + + rcc->last_qscale = q; + return q; +} + +static int init_pass2( x264_t *h ) +{ + x264_ratecontrol_t *rcc = h->rc; + uint64_t all_const_bits = 0; + uint64_t all_available_bits = (uint64_t)(h->param.rc.i_bitrate * 1000 * (double)rcc->num_entries / rcc->fps); + double rate_factor, step, step_mult; + double qblur = h->param.rc.f_qblur; + const int filter_size = (int)(qblur*4) | 1; + double expected_bits; + double *qscale, *blurred_qscale; + int i; + + /* find total/average complexity & const_bits */ + for(i=0; inum_entries; i++){ + ratecontrol_entry_t *rce = &rcc->entry[i]; + rce->new_pict_type = rce->pict_type; + all_const_bits += rce->mv_bits + rce->misc_bits; + rcc->i_cplx_sum[rce->new_pict_type] += rce->i_tex_bits * rce->qscale; + rcc->p_cplx_sum[rce->new_pict_type] += rce->p_tex_bits * rce->qscale; + rcc->mv_bits_sum[rce->new_pict_type] += rce->mv_bits; + rcc->frame_count[rce->new_pict_type] ++; + } + + if( all_available_bits < all_const_bits) + { + x264_log(h, X264_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n", + (int)(all_const_bits * rcc->fps / (rcc->num_entries * 1000))); + return -1; + } + + qscale = x264_malloc(sizeof(double)*rcc->num_entries); + if(filter_size > 1) + blurred_qscale = x264_malloc(sizeof(double)*rcc->num_entries); + else + blurred_qscale = qscale; + + expected_bits = 0; + for(i=0; inum_entries; i++) + expected_bits += qscale2bits(&rcc->entry[i], get_qscale(h, &rcc->entry[i], 1.0)); + step_mult = all_available_bits / expected_bits; + + rate_factor = 0; + for(step = 1E4 * step_mult; step > 1E-7 * step_mult; step*=0.5){ + expected_bits = 0; + rate_factor += step; + + /* find qscale */ + for(i=0; inum_entries; i++){ + qscale[i] = get_qscale(h, &rcc->entry[i], rate_factor); + } + + /* fixed I/B QP relative to P mode */ + for(i=rcc->num_entries-1; i>=0; i--){ + qscale[i] = get_diff_limited_q(h, &rcc->entry[i], qscale[i]); + assert(qscale[i] >= 0); + } + + /* smooth curve */ + if(filter_size > 1){ + assert(filter_size%2==1); + for(i=0; inum_entries; i++){ + ratecontrol_entry_t *rce = &rcc->entry[i]; + const int pict_type = rce->new_pict_type; + int j; + double q=0.0, sum=0.0; + + for(j=0; j= rcc->num_entries) continue; + if(pict_type != rcc->entry[index].new_pict_type) continue; + q += qscale[index] * coeff; + sum += coeff; + } + blurred_qscale[i] = q/sum; + } + } + + /* find expected bits */ + for(i=0; inum_entries; i++){ + ratecontrol_entry_t *rce = &rcc->entry[i]; + double bits; + rce->new_qscale = modify_qscale(h, rce, blurred_qscale[i]); + assert(rce->new_qscale >= 0); + bits = qscale2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits; + + rce->expected_bits = expected_bits; + expected_bits += bits; + } + +//printf("expected:%f available:%d factor:%f\n", expected_bits, (int)all_available_bits, rate_factor); + if(expected_bits > all_available_bits) rate_factor -= step; + } + + x264_free(qscale); + if(filter_size > 1) + x264_free(blurred_qscale); + + if(fabs(expected_bits/all_available_bits - 1.0) > 0.01 ) + { + x264_log( h, X264_LOG_ERROR, "Error: 2pass curve failed to converge\n"); + return -1; + } + + return 0; +} + + diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index b8072c50..13475d3b 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -28,6 +28,7 @@ int x264_ratecontrol_new ( x264_t * ); void x264_ratecontrol_delete( x264_t * ); void x264_ratecontrol_start( x264_t *, int i_slice_type ); +int x264_ratecontrol_slice_type( x264_t *, int i_frame ); void x264_ratecontrol_mb( x264_t *, int bits ); int x264_ratecontrol_qp( x264_t * ); void x264_ratecontrol_end( x264_t *, int bits ); diff --git a/x264.c b/x264.c index 4e9e015a..c657a6fc 100644 --- a/x264.c +++ b/x264.c @@ -120,6 +120,12 @@ static void Help( void ) " --rcbuf Size of VBV buffer\n" " --rcinitbuf Initial VBV buffer occupancy\n" "\n" + " -p, --pass <1|2> Enable 2 pass ratecontrol\n" + " --stats Filename for 2 pass stats\n" + " --rceq Ratecontrol equation\n" + " --qcomp 0.0 => CBR, 1.0 => CQP, 0.6 => default\n" + "\n" + " -A, --analyse Analyse options:\n" " - i4x4\n" " - psub16x16,psub8x8\n" @@ -161,6 +167,10 @@ static int Parse( int argc, char **argv, #define OPT_PBRATIO 261 #define OPT_RCBUF 262 #define OPT_RCIBUF 263 +#define OPT_RCSTATS 264 +#define OPT_RCEQ 265 +#define OPT_QCOMP 266 + static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, @@ -185,12 +195,16 @@ static int Parse( int argc, char **argv, { "rcinitbuf",required_argument, NULL, OPT_RCIBUF }, { "ipratio", required_argument, NULL, OPT_IPRATIO }, { "pbratio", required_argument, NULL, OPT_PBRATIO }, + { "pass", required_argument, NULL, 'p' }, + { "stats", required_argument, NULL, OPT_RCSTATS }, + { "rceq", required_argument, NULL, OPT_RCEQ }, + { "qcomp", required_argument, NULL, OPT_QCOMP }, {0, 0, 0, 0} }; int c; - c = getopt_long( argc, argv, "hi:I:b:r:cxB:q:no:s:A:", + c = getopt_long( argc, argv, "hi:I:b:r:cxB:q:no:s:A:p:", long_options, &long_options_index); if( c == -1 ) @@ -207,8 +221,8 @@ static int Parse( int argc, char **argv, case 0: break; case 'B': - param->i_bitrate = atol( optarg ); - param->b_cbr = 1; + param->rc.i_bitrate = atol( optarg ); + param->rc.b_cbr = 1; break; case 'b': param->i_bframe = atol( optarg ); @@ -233,16 +247,16 @@ static int Parse( int argc, char **argv, break; } case 'q': - param->i_qp_constant = atoi( optarg ); + param->rc.i_qp_constant = atoi( optarg ); break; case OPT_QPMIN: - param->i_qp_min = atoi( optarg ); + param->rc.i_qp_min = atoi( optarg ); break; case OPT_QPMAX: - param->i_qp_max = atoi( optarg ); + param->rc.i_qp_max = atoi( optarg ); break; case OPT_QPSTEP: - param->i_qp_step = atoi( optarg ); + param->rc.i_qp_step = atoi( optarg ); break; case 'r': param->i_frame_reference = atoi( optarg ); @@ -283,19 +297,41 @@ static int Parse( int argc, char **argv, if( strstr( optarg, "psub8x8" ) ) param->analyse.inter |= X264_ANALYSE_PSUB8x8; break; case OPT_RCBUF: - param->i_rc_buffer_size = atoi(optarg); + param->rc.i_rc_buffer_size = atoi(optarg); break; case OPT_RCIBUF: - param->i_rc_init_buffer = atoi(optarg); + param->rc.i_rc_init_buffer = atoi(optarg); break; case OPT_RCSENS: - param->i_rc_sens = atoi(optarg); + param->rc.i_rc_sens = atoi(optarg); break; case OPT_IPRATIO: - param->f_ip_factor = atoi(optarg); + param->rc.f_ip_factor = atoi(optarg); break; case OPT_PBRATIO: - param->f_pb_factor = atoi(optarg); + param->rc.f_pb_factor = atoi(optarg); + break; + case 'p': + { + int i_pass = atoi(optarg); + if( i_pass == 1 ) + param->rc.b_stat_write = 1; + else if( i_pass == 2 ) + param->rc.b_stat_read = 1; + else if( i_pass > 2 ) /* XXX untested */ + param->rc.b_stat_read = + param->rc.b_stat_write = 1; + break; + } + case OPT_RCSTATS: + param->rc.psz_stat_in = optarg; + param->rc.psz_stat_out = optarg; + break; + case OPT_RCEQ: + param->rc.psz_rc_eq = optarg; + break; + case OPT_QCOMP: + param->rc.f_qcompress = atof(optarg); break; default: fprintf( stderr, "unknown option (%c)\n", optopt ); diff --git a/x264.h b/x264.h index b6a7830e..76deec4b 100644 --- a/x264.h +++ b/x264.h @@ -24,7 +24,7 @@ #ifndef _X264_H #define _X264_H 1 -#define X264_BUILD 0x0009 +#define X264_BUILD 0x000a /* x264_t: * opaque handler for decoder and encoder */ @@ -112,18 +112,6 @@ typedef struct int b_cabac; int i_cabac_init_idc; - int i_qp_constant; /* 1-51 */ - int i_qp_min; /* min allowed QP value */ - int i_qp_max; /* max allowed QP value */ - int i_qp_step; /* max QP step between frames */ - - int b_cbr; /* constant bitrate */ - int i_bitrate; - int i_rc_buffer_size; - int i_rc_init_buffer; - int i_rc_sens; /* rate control sensitivity */ - float f_ip_factor; - float f_pb_factor; /* Log */ void (*pf_log)( void *, int i_level, const char *psz, va_list ); @@ -139,6 +127,34 @@ typedef struct int b_psnr; /* Do we compute PSNR stats (save a few % of cpu) */ } analyse; + /* Rate control parameters */ + struct + { + int i_qp_constant; /* 1-51 */ + int i_qp_min; /* min allowed QP value */ + int i_qp_max; /* max allowed QP value */ + int i_qp_step; /* max QP step between frames */ + + int b_cbr; /* constant bitrate */ + int i_bitrate; + int i_rc_buffer_size; + int i_rc_init_buffer; + int i_rc_sens; /* rate control sensitivity */ + float f_ip_factor; + float f_pb_factor; + + /* 2pass */ + int b_stat_write; /* Enable stat writing in psz_stat_out */ + char *psz_stat_out; + int b_stat_read; /* Read stat from psz_stat_in and use it */ + char *psz_stat_in; + + /* 2pass params (same than ffmpeg ones) */ + char *psz_rc_eq; /* 2 pass rate control equation */ + float f_qcompress; /* 0.0 => cbr, 1.0 => constant qp */ + float f_qblur; /* temporally blur quants */ + } rc; + } x264_param_t; /* x264_param_default: