From: Laurent Aimar Date: Fri, 6 Aug 2004 18:06:09 +0000 (+0000) Subject: * all: Patch from Måns Rullgård X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=20c19c4b3a001c9e02775fdba040725a438db795;p=x264 * all: Patch from Måns Rullgård "Here's a patch that adds some kind of rate control. I suppose it is by no means perfect, but it's much better than constant quantizer. It also has a very crude scene change detection that sometimes avoids a buffer underflow by reencoding oversized P/B frames as I frames." git-svn-id: svn://svn.videolan.org/x264/trunk@17 df754926-b1dd-0310-bc7b-ec298dee348c --- diff --git a/AUTHORS b/AUTHORS index af06be2a..2b219dc3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,3 +33,8 @@ E: justin_clay AT hotmail DOT com C: wheatgerm D: Inital work on vfw S: Nova Scotia, Canada + +N: Måns Rullgård +E: mru AT mru.ath DOT cx +D: Rate control +S: Oslo, Norway diff --git a/core/common.c b/core/common.c index a4a21d44..1e3e4c2e 100644 --- a/core/common.c +++ b/core/common.c @@ -72,8 +72,17 @@ 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->analyse.intra = X264_ANALYSE_I4x4; param->analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16; diff --git a/core/common.h b/core/common.h index 11b9fae9..c2764ede 100644 --- a/core/common.h +++ b/core/common.h @@ -314,6 +314,10 @@ struct x264_t /* rate control encoding only */ x264_ratecontrol_t *rc; + int i_last_inter_size; + int i_last_intra_size; + int i_last_intra_qp; + /* stats */ struct { diff --git a/encoder/analyse.c b/encoder/analyse.c index aaca97e0..27cf9938 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -30,6 +30,7 @@ #include "../core/macroblock.h" #include "macroblock.h" #include "me.h" +#include "ratecontrol.h" typedef struct { @@ -846,8 +847,7 @@ void x264_macroblock_analyse( x264_t *h ) x264_mb_analysis_t analysis; int i; - /* qp TODO implement a nice RC */ - h->mb.qp[h->mb.i_mb_xy] = x264_clip3( h->pps->i_pic_init_qp + h->sh.i_qp_delta + 0, 0, 51 ); + h->mb.qp[h->mb.i_mb_xy] = x264_ratecontrol_qp(h); /* FIXME check if it's 12 */ if( h->mb.qp[h->mb.i_mb_xy] - h->mb.i_last_qp < -12 ) diff --git a/encoder/encoder.c b/encoder/encoder.c index f9c03105..1e9d329b 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -36,7 +36,7 @@ #include "macroblock.h" //#define DEBUG_MB_TYPE -#define DEBUG_DUMP_FRAME 1 +#define DEBUG_DUMP_FRAME 0 static int64_t i_mtime_encode_frame = 0; @@ -396,7 +396,10 @@ x264_t *x264_encoder_open ( x264_param_t *param ) x264_csp_init( h->param.cpu, h->param.i_csp, &h->csp ); /* rate control */ - h->rc = x264_ratecontrol_new( &h->param ); + x264_ratecontrol_new( h ); + + h->i_last_intra_size = 0; + h->i_last_inter_size = 0; /* stat */ h->stat.i_slice_count[SLICE_TYPE_I] = 0; @@ -676,6 +679,8 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id const int i_mb_y = mb_xy / h->sps->i_mb_width; const int i_mb_x = mb_xy % h->sps->i_mb_width; + int mb_spos = bs_pos(&h->out.bs); + /* load cache */ x264_macroblock_cache_load( h, i_mb_x, i_mb_y ); @@ -741,6 +746,8 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id x264_macroblock_cache_save( h ); i_mb_count[h->mb.i_type]++; + + x264_ratecontrol_mb(h, bs_pos(&h->out.bs) - mb_spos); } if( h->param.b_cabac ) @@ -878,20 +885,6 @@ int x264_encoder_encode( x264_t *h, } fenc->i_poc = h->i_poc; - if( fenc->i_type == X264_TYPE_IDR ) - { - h->frames.i_last_idr = 0; - h->frames.i_last_i = 0; - } - else if( fenc->i_type == X264_TYPE_I ) - { - h->frames.i_last_idr++; - h->frames.i_last_i = 0; - } - else - { - h->frames.i_last_i++; - } /* 3: Update current/next */ if( fenc->i_type == X264_TYPE_B ) @@ -941,6 +934,23 @@ int x264_encoder_encode( x264_t *h, } x264_frame_put( h->frames.unused, h->fenc ); /* Safe to do it now, we don't use frames.unused for the rest */ +do_encode: + + if( h->fenc->i_type == X264_TYPE_IDR ) + { + h->frames.i_last_idr = 0; + h->frames.i_last_i = 0; + } + else if( h->fenc->i_type == X264_TYPE_I ) + { + h->frames.i_last_idr++; + h->frames.i_last_i = 0; + } + else + { + h->frames.i_last_i++; + } + /* ------------------- Setup frame context ----------------------------- */ /* 5: Init data dependant of frame type */ TIMER_START( i_mtime_encode_frame ); @@ -980,8 +990,8 @@ int x264_encoder_encode( x264_t *h, /* ------------------- Init ----------------------------- */ /* Init the rate control */ - x264_ratecontrol_start( h->rc, i_slice_type ); - i_global_qp = x264_ratecontrol_qp( h->rc ); + x264_ratecontrol_start( h, i_slice_type ); + i_global_qp = x264_ratecontrol_qp( h ); if( h->fenc->i_qpplus1 > 0 ) { i_global_qp = x264_clip3( h->fenc->i_qpplus1 - 1, 0, 51 ); @@ -1021,6 +1031,59 @@ int x264_encoder_encode( x264_t *h, /* Write the slice */ x264_slice_write( h, i_nal_type, i_nal_ref_idc, i_mb_count ); +#if 1 + if( i_slice_type != SLICE_TYPE_I) + { + /* Bad P will be reencoded as I */ + if( i_slice_type == SLICE_TYPE_P && + h->out.nal[h->out.i_nal-1].i_payload > h->i_last_intra_size + + h->i_last_intra_size * (3+h->i_last_intra_qp - i_global_qp) / 16 && + i_mb_count[I_4x4] + i_mb_count[I_16x16] > i_mb_count[P_SKIP] + i_mb_count[P_L0]/2 && + h->out.nal[h->out.i_nal-1].i_payload > 2 * h->i_last_inter_size && + h->frames.i_last_i > 4) + { + + fprintf( stderr, "scene cut at %d size=%d last I:%d last P:%d Intra:%d Skip:%d PL0:%d\n", + 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_count[I_4x4] + i_mb_count[I_16x16], + i_mb_count[P_SKIP], + i_mb_count[P_L0] ); + + /* Restore frame num */ + h->i_frame_num--; + + /* Do IDR if needed and if we can (won't work with B frames) */ + if( h->frames.next[0] == NULL && + h->frames.i_last_idr + 1 >= h->param.i_idrframe ) + { + /* Reset */ + h->i_poc = 0; + h->i_frame_num = 0; + + /* Reinit field of fenc */ + h->fenc->i_type = X264_TYPE_IDR; + h->fenc->i_poc = h->i_poc; + + /* Next Poc */ + h->i_poc += 2; + } + else + { + h->fenc->i_type = X264_TYPE_I; + } + goto do_encode; + } + h->i_last_inter_size = h->out.nal[h->out.i_nal-1].i_payload; + } + else + { + h->i_last_intra_size = h->out.nal[h->out.i_nal-1].i_payload; + h->i_last_intra_qp = i_global_qp; + } +#endif + /* End bitstream, set output */ *pi_nal = h->out.i_nal; *pp_nal = &h->out.nal[0]; @@ -1050,12 +1113,12 @@ int x264_encoder_encode( x264_t *h, /* increase frame count */ h->i_frame++; - /* update rc */ - x264_ratecontrol_end( h->rc, h->out.nal[h->out.i_nal-1].i_payload * 8 ); - /* restore CPU state (before using float again) */ x264_cpu_restore( h->param.cpu ); + /* update rc */ + x264_ratecontrol_end( h, h->out.nal[h->out.i_nal-1].i_payload * 8 ); + TIMER_STOP( i_mtime_encode_frame ); /* ---------------------- Compute/Print statistics --------------------- */ @@ -1077,8 +1140,9 @@ int x264_encoder_encode( x264_t *h, } /* print stat */ - fprintf( stderr, "frame=%4d NAL=%d Slice:%c Poc:%-3d I4x4:%-5d I16x16:%-5d P:%-5d SKIP:%-3d size=%d bytes PSNR Y:%2.2f U:%2.2f V:%2.2f\n", + fprintf( stderr, "frame=%4d QP=%i NAL=%d Slice:%c Poc:%-3d I4x4:%-5d I16x16:%-5d P:%-5d SKIP:%-3d size=%d bytes PSNR Y:%2.2f U:%2.2f V:%2.2f\n", h->i_frame - 1, + i_global_qp, i_nal_ref_idc, i_slice_type == SLICE_TYPE_I ? 'I' : (i_slice_type == SLICE_TYPE_P ? 'P' : 'B' ), frame_psnr->i_poc, @@ -1225,7 +1289,7 @@ void x264_encoder_close ( x264_t *h ) } /* rc */ - x264_ratecontrol_delete( h->rc ); + x264_ratecontrol_delete( h ); x264_macroblock_cache_end( h ); x264_free( h->out.p_bitstream ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index fc0226e7..d49cbb87 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -4,7 +4,7 @@ * Copyright (C) 2003 Laurent Aimar * $Id: ratecontrol.c,v 1.1 2004/06/03 19:27:08 fenrir Exp $ * - * Authors: Laurent Aimar + * Authors: Måns Rullgård * * 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 @@ -21,75 +21,286 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ +#define _ISOC99_SOURCE + #include #include #include +#include +#include #include "../core/common.h" +#include "../core/cpu.h" #include "ratecontrol.h" +struct x264_ratecontrol_t +{ + /* constants */ + float fps; + int gop_size; + int bitrate; + int nmb; /* number of MBs */ + int buffer_size; + int rcbufrate; + int init_qp; + + int gop_qp; + int buffer_fullness; + int frames; /* frames in current gop */ + int pframes; + int slice_type; + int mb; /* MBs processed in current frame */ + int bits_gop; /* allocated bits current gop */ + int bits_last_gop; /* bits consumed in gop */ + int qp; /* qp for current frame */ + int qpm; /* qp for next MB */ + int qpa; /* average qp for last frame */ + int qps; + int qp_avg_p; /* average QP for P frames */ + int qp_last_p; + int fbits; /* bits allocated for current frame */ + int ufbits; /* bits used for current frame */ + int nzcoeffs; /* # of 0-quantized coefficients */ + int ncoeffs; /* total # of coefficients */ + int overhead; +}; -x264_ratecontrol_t *x264_ratecontrol_new( x264_param_t *param ) +int x264_ratecontrol_new( x264_t *h ) { x264_ratecontrol_t *rc = x264_malloc( sizeof( x264_ratecontrol_t ) ); + float bpp; + + memset(rc, 0, sizeof(*rc)); + + rc->fps = h->param.f_fps > 0.1 ? h->param.f_fps : 25.0f; + rc->gop_size = h->param.i_iframe; + rc->bitrate = h->param.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->qpa = rc->qp; + rc->qpm = rc->qp; - rc->fps = param->f_fps > 0.1 ? param->f_fps : 25.0f; - rc->i_iframe = param->i_iframe; - rc->i_bitrate = param->i_bitrate * 1000; + rc->buffer_size = h->param.i_rc_buffer_size; + if(rc->buffer_size <= 0) + rc->buffer_size = rc->bitrate / 2; + rc->buffer_fullness = h->param.i_rc_init_buffer; + rc->rcbufrate = rc->bitrate / rc->fps; - rc->i_qp_last = 26; - rc->i_qp = param->i_qp_constant; + bpp = rc->bitrate / (rc->fps * h->param.i_width * h->param.i_height); + if(bpp <= 0.6) + rc->init_qp = 31; + else if(bpp <= 1.4) + rc->init_qp = 25; + else if(bpp <= 2.4) + rc->init_qp = 20; + else + rc->init_qp = 10; + rc->gop_qp = rc->init_qp; - rc->i_frames = 0; - rc->i_size = 0; + rc->bits_last_gop = 0; - return rc; +/* fprintf(stderr, "%f fps, %i bps, bufsize %i\n", */ +/* rc->fps, rc->bitrate, rc->buffer_size); */ + + h->rc = rc; + + return 0; } -void x264_ratecontrol_delete( x264_ratecontrol_t *rc ) +void x264_ratecontrol_delete( x264_t *h ) { + x264_ratecontrol_t *rc = h->rc; x264_free( rc ); } -void x264_ratecontrol_start( x264_ratecontrol_t *rc, int i_slice_type ) +void x264_ratecontrol_start( x264_t *h, int i_slice_type ) { - rc->i_slice_type = i_slice_type; + x264_ratecontrol_t *rc = h->rc; + int gframes, iframes, pframes, bframes; + int minbits, maxbits; + int gbits, fbits; + int zn = 0; + float kp; + int gbuf; + + if(!h->param.b_cbr) + return; + + x264_cpu_restore( h->param.cpu ); + + rc->slice_type = i_slice_type; + + switch(i_slice_type){ + case SLICE_TYPE_I: + gbuf = rc->buffer_fullness + (rc->gop_size-1) * rc->rcbufrate; + rc->bits_gop = gbuf - rc->buffer_size / 2; + + if(!rc->mb && rc->pframes){ + int qp = (float) rc->qp_avg_p / rc->pframes + 0.5; +#if 0 /* JM does this without explaining why */ + int gdq = (float) rc->gop_size / 15 + 0.5; + if(gdq > 2) + gdq = 2; + qp -= gdq; + if(qp > rc->qp_last_p - 2) + qp--; +#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); + rc->gop_qp = qp; + } else { + rc->gop_qp = rc->init_qp; + } + + kp = h->param.f_ip_factor * h->param.f_pb_factor; + + rc->bits_last_gop = 0; + rc->frames = 0; + rc->pframes = 0; + rc->qp_avg_p = 0; + break; + + case SLICE_TYPE_P: + kp = h->param.f_pb_factor; + break; + + case SLICE_TYPE_B: + kp = 1.0; + break; + + default: + fprintf(stderr, "x264: ratecontrol: unknown slice type %i\n", + i_slice_type); + kp = 1.0; + break; + } + + gframes = rc->gop_size - rc->frames; + iframes = gframes / rc->gop_size; + pframes = gframes / (h->param.i_bframe + 1) - iframes; + bframes = gframes - pframes - iframes; + + 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); + + minbits = rc->buffer_fullness + rc->rcbufrate - rc->buffer_size; + if(minbits < 0) + minbits = 0; + maxbits = rc->buffer_fullness; + rc->fbits = x264_clip3(fbits, minbits, maxbits); + + if(i_slice_type == SLICE_TYPE_I){ + rc->qp = rc->gop_qp; + } else if(rc->ncoeffs){ + int dqp; + + zn = rc->ncoeffs - + rc->fbits * (rc->ncoeffs - rc->nzcoeffs) / rc->ufbits; + dqp = h->param.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); + rc->qp = rc->qpa + dqp; + } + + if(rc->fbits > 0.8 * maxbits) + rc->qp += 1; + else if(rc->fbits > 0.9 * maxbits) + rc->qp += 2; + else if(rc->fbits < 1.2 * minbits) + rc->qp -= 1; + else if(rc->fbits < 1.1 * minbits) + rc->qp -= 2; + + rc->qp = x264_clip3(rc->qp, h->param.i_qp_min, h->param.i_qp_max); + rc->qpm = rc->qp; + +/* fprintf(stderr, "fbits=%i, qp=%i, z=%i, min=%i, max=%i\n", */ +/* rc->fbits, rc->qpm, zn, minbits, maxbits); */ + + rc->fbits -= rc->overhead; + rc->ufbits = 0; + rc->ncoeffs = 0; + rc->nzcoeffs = 0; + rc->mb = 0; + rc->qps = 0; } -int x264_ratecontrol_qp( x264_ratecontrol_t *rc ) +void x264_ratecontrol_mb( x264_t *h, int bits ) { - return x264_clip3( rc->i_qp, 1, 51 ); + x264_ratecontrol_t *rc = h->rc; + int rbits; + int zn, enz; + int dqp; + int i; + + x264_cpu_restore( h->param.cpu ); + + rc->qps += rc->qpm; + rc->ufbits += bits; + rc->mb++; + + for(i = 0; i < 16 + 8; i++) + rc->nzcoeffs += 16 - h->mb.cache.non_zero_count[x264_scan8[i]]; + rc->ncoeffs += 16 * (16 + 8); + + if(rc->mb < rc->nmb / 16) + return; + else if(rc->mb == rc->nmb) + return; + + rbits = rc->fbits - rc->ufbits; +/* if(rbits < 0) */ +/* rbits = 0; */ + + zn = (rc->nmb - rc->mb) * 16 * 24; + if(rc->ufbits) + zn -= rbits * (rc->ncoeffs - rc->nzcoeffs) / rc->ufbits; + enz = rc->nzcoeffs * (rc->nmb - rc->mb) / rc->mb; + dqp = (float) 2*h->param.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); } -void x264_ratecontrol_end( x264_ratecontrol_t *rc, int bits ) +int x264_ratecontrol_qp( x264_t *h ) { - return; -#if 0 - int i_avg; - int i_target = rc->i_bitrate / rc->fps; - int i_qp = rc->i_qp; + return h->rc->qpm; +} - rc->i_qp_last = rc->i_qp; - rc->i_frames++; - rc->i_size += bits / 8; +void x264_ratecontrol_end( x264_t *h, int bits ) +{ + x264_ratecontrol_t *rc = h->rc; - i_avg = 8 * rc->i_size / rc->i_frames; + if(!h->param.b_cbr) + return; - if( rc->i_slice_type == SLICE_TYPE_I ) - { - i_target = i_target * 20 / 10; + rc->buffer_fullness += rc->rcbufrate - bits; + if(rc->buffer_fullness < 0){ + fprintf(stderr, "x264: buffer underflow %i\n", rc->buffer_fullness); + rc->buffer_fullness = 0; } - if( i_avg > i_target * 11 / 10 ) - { - i_qp = rc->i_qp + ( i_avg / i_target - 1 ); - } - else if( i_avg < i_target * 9 / 10 ) - { - i_qp = rc->i_qp - ( i_target / i_avg - 1 ); + rc->qpa = rc->qps / rc->mb; + if(rc->slice_type == SLICE_TYPE_P){ + rc->qp_avg_p += rc->qpa; + rc->qp_last_p = rc->qpa; + rc->pframes++; } - rc->i_qp = x264_clip3( i_qp, rc->i_qp_last - 2, rc->i_qp_last + 2 ); -#endif + rc->overhead = bits - rc->ufbits; + +/* fprintf(stderr, " bits=%i, qp=%i, z=%i, zr=%6.3f, buf=%i\n", */ +/* bits, rc->qpa, rc->nzcoeffs, */ +/* (float) rc->nzcoeffs / rc->ncoeffs, rc->buffer_fullness); */ + + rc->bits_last_gop += bits; + rc->frames++; + rc->mb = 0; } diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index 5fa3c7c9..b8072c50 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -24,29 +24,13 @@ #ifndef _RATECONTROL_H #define _RATECONTROL_H 1 -struct x264_ratecontrol_t -{ - float fps; - int i_iframe; +int x264_ratecontrol_new ( x264_t * ); +void x264_ratecontrol_delete( x264_t * ); - int i_bitrate; - int i_qp_last; - int i_qp; - - int i_slice_type; - - int i_frames; - int64_t i_size; - -}; - - -x264_ratecontrol_t *x264_ratecontrol_new ( x264_param_t * ); -void x264_ratecontrol_delete( x264_ratecontrol_t * ); - -void x264_ratecontrol_start( x264_ratecontrol_t *, int i_slice_type ); -int x264_ratecontrol_qp( x264_ratecontrol_t * ); -void x264_ratecontrol_end( x264_ratecontrol_t *, int bits ); +void x264_ratecontrol_start( x264_t *, int i_slice_type ); +void x264_ratecontrol_mb( x264_t *, int bits ); +int x264_ratecontrol_qp( x264_t * ); +void x264_ratecontrol_end( x264_t *, int bits ); #endif diff --git a/x264.c b/x264.c index 57254eac..a16cf6b4 100644 --- a/x264.c +++ b/x264.c @@ -111,8 +111,15 @@ static void Help( void ) " -r, --ref Number of references\n" " -n, --nf Disable loop filter\n" " -f, --filter Loop filter AplhaCO and Beta parameters\n" + "\n" " -q, --qp Set QP\n" - " -B, --bitrate Set bitrate [broken]\n" + " -B, --bitrate Set bitrate\n" + " --qpmin Set min QP\n" + " --qpmax Set max QP\n" + " --qpstep Set max QP step\n" + " --rcsens RC sensitivity\n" + " --rcbuf Size of VBV buffer\n" + " --rcinitbuf Initial VBV buffer occupancy\n" "\n" " -A, --analyse Analyse options:\n" " - i4x4\n" @@ -147,6 +154,14 @@ static int Parse( int argc, char **argv, for( ;; ) { int long_options_index; +#define OPT_QPMIN 256 +#define OPT_QPMAX 257 +#define OPT_QPSTEP 258 +#define OPT_RCSENS 259 +#define OPT_IPRATIO 260 +#define OPT_PBRATIO 261 +#define OPT_RCBUF 262 +#define OPT_RCIBUF 263 static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, @@ -158,11 +173,19 @@ static int Parse( int argc, char **argv, { "filter", required_argument, NULL, 'f' }, { "cabac", no_argument, NULL, 'c' }, { "qp", required_argument, NULL, 'q' }, + { "qpmin", required_argument, NULL, OPT_QPMIN }, + { "qpmax", required_argument, NULL, OPT_QPMAX }, + { "qpstep", required_argument, NULL, OPT_QPSTEP }, { "ref", required_argument, NULL, 'r' }, { "no-asm", no_argument, NULL, 'C' }, { "sar", required_argument, NULL, 's' }, { "output", required_argument, NULL, 'o' }, { "analyse", required_argument, NULL, 'A' }, + { "rcsens", required_argument, NULL, OPT_RCSENS }, + { "rcbuf", required_argument, NULL, OPT_RCBUF }, + { "rcinitbuf",required_argument, NULL, OPT_RCIBUF }, + { "ipratio", required_argument, NULL, OPT_IPRATIO }, + { "pbratio", required_argument, NULL, OPT_PBRATIO }, {0, 0, 0, 0} }; @@ -186,6 +209,7 @@ static int Parse( int argc, char **argv, break; case 'B': param->i_bitrate = atol( optarg ); + param->b_cbr = 1; break; case 'b': param->i_bframe = atol( optarg ); @@ -212,6 +236,15 @@ static int Parse( int argc, char **argv, case 'q': param->i_qp_constant = atoi( optarg ); break; + case OPT_QPMIN: + param->i_qp_min = atoi( optarg ); + break; + case OPT_QPMAX: + param->i_qp_max = atoi( optarg ); + break; + case OPT_QPSTEP: + param->i_qp_step = atoi( optarg ); + break; case 'r': param->i_frame_reference = atoi( optarg ); break; @@ -250,7 +283,21 @@ static int Parse( int argc, char **argv, if( strstr( optarg, "psub16x16" ) ) param->analyse.inter |= X264_ANALYSE_PSUB16x16; if( strstr( optarg, "psub8x8" ) ) param->analyse.inter |= X264_ANALYSE_PSUB8x8; break; - + case OPT_RCBUF: + param->i_rc_buffer_size = atoi(optarg); + break; + case OPT_RCIBUF: + param->i_rc_init_buffer = atoi(optarg); + break; + case OPT_RCSENS: + param->i_rc_sens = atoi(optarg); + break; + case OPT_IPRATIO: + param->f_ip_factor = atoi(optarg); + break; + case OPT_PBRATIO: + param->f_pb_factor = atoi(optarg); + break; default: fprintf( stderr, "unknown option (%c)\n", optopt ); return -1; diff --git a/x264.h b/x264.h index 772c6c7f..a34be810 100644 --- a/x264.h +++ b/x264.h @@ -104,7 +104,17 @@ typedef struct int i_cabac_init_idc; int i_qp_constant; /* 1-51 */ - int i_bitrate; /* not working yet */ + 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; /* Encoder analyser parameters */ struct