Commit c8b1a477 authored by Loren Merritt's avatar Loren Merritt

Zoned ratecontrol.


git-svn-id: svn://svn.videolan.org/x264/trunk@237 df754926-b1dd-0310-bc7b-ec298dee348c
parent 0072b802
......@@ -95,6 +95,7 @@ void x264_param_default( x264_param_t *param )
param->rc.f_qcompress = 0.6;
param->rc.f_qblur = 0.5;
param->rc.f_complexity_blur = 20;
param->rc.i_zones = 0;
/* Log */
param->pf_log = x264_log_default;
......
......@@ -126,6 +126,9 @@ struct x264_ratecontrol_t
double p_cplx_sum[5];
double mv_bits_sum[5];
int frame_count[5]; /* number of frames of each type */
int i_zones;
x264_zone_t *zones;
};
......@@ -249,6 +252,30 @@ int x264_ratecontrol_new( x264_t *h )
rc->lmax[SLICE_TYPE_B] *= fabs(h->param.f_pb_factor);
#endif
if( h->param.rc.i_zones > 0 )
{
for( i = 0; i < h->param.rc.i_zones; i++ )
{
x264_zone_t z = h->param.rc.zones[i];
if( z.i_start < 0 || z.i_start > z.i_end )
{
x264_log( h, X264_LOG_ERROR, "invalid zone: start=%d end=%d\n",
z.i_start, z.i_end );
return -1;
}
else if( !z.b_force_qp && z.f_bitrate_factor <= 0 )
{
x264_log( h, X264_LOG_ERROR, "invalid zone: bitrate_factor=%f\n",
z.f_bitrate_factor );
return -1;
}
}
rc->i_zones = h->param.rc.i_zones;
rc->zones = x264_malloc( rc->i_zones * sizeof(x264_zone_t) );
memcpy( rc->zones, h->param.rc.zones, rc->i_zones * sizeof(x264_zone_t) );
}
/* Load stat file and init 2pass algo */
if( h->param.rc.b_stat_read )
{
......@@ -383,8 +410,8 @@ void x264_ratecontrol_delete( x264_t *h )
}
x264_free( rc->psz_stat_file_tmpname );
}
if( rc->entry )
x264_free(rc->entry);
x264_free( rc->entry );
x264_free( rc->zones );
x264_free( rc );
}
......@@ -543,11 +570,12 @@ double x264_eval( char *s, double *const_value, const char **const_name,
/**
* modify the bitrate curve from pass1 for one frame
*/
static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor)
static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num)
{
x264_ratecontrol_t *rcc= h->rc;
const int pict_type = rce->pict_type;
double q;
int i;
double const_values[]={
rce->i_tex_bits * rce->qscale,
......@@ -601,13 +629,28 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
};
q = x264_eval((char*)h->param.rc.psz_rc_eq, const_values, const_names, func1, func1_names, NULL, NULL, rce);
q /= rate_factor;
// avoid NaN's in the rc_eq
if(q != q || rce->i_tex_bits + rce->p_tex_bits + rce->mv_bits == 0)
q = rcc->last_qscale;
else
else {
rcc->last_rceq = q;
q /= rate_factor;
rcc->last_qscale = q;
}
for( i = rcc->i_zones-1; i >= 0; i-- )
{
x264_zone_t *z = &rcc->zones[i];
if( frame_num >= z->i_start && frame_num <= z->i_end )
{
if( z->b_force_qp )
q = qp2qscale(z->i_qp);
else
q /= z->f_bitrate_factor;
break;
}
}
return q;
}
......@@ -835,13 +878,12 @@ static float rate_estimate_qscale(x264_t *h, int pict_type)
rce.s_count = 0;
rce.qscale = 1;
rce.pict_type = pict_type;
rcc->last_rceq = get_qscale(h, &rce, 1);
q = get_qscale(h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame);
wanted_bits = h->fenc->i_frame * rcc->bitrate / rcc->fps;
abr_buffer *= X264_MAX( 1, sqrt(h->fenc->i_frame/25) );
overflow = x264_clip3f( 1.0 + (total_bits - wanted_bits) / abr_buffer, .5, 2 );
q = rcc->last_rceq * overflow * rcc->cplxr_sum / rcc->wanted_bits_window;
q *= overflow;
if( pict_type == SLICE_TYPE_I
/* should test _next_ pict type, but that isn't decided yet */
......@@ -959,7 +1001,7 @@ static int init_pass2( x264_t *h )
expected_bits = 1;
for(i=0; i<rcc->num_entries; i++)
expected_bits += qscale2bits(&rcc->entry[i], get_qscale(h, &rcc->entry[i], 1.0));
expected_bits += qscale2bits(&rcc->entry[i], get_qscale(h, &rcc->entry[i], 1.0, i));
step_mult = all_available_bits / expected_bits;
rate_factor = 0;
......@@ -974,7 +1016,7 @@ static int init_pass2( x264_t *h )
/* find qscale */
for(i=0; i<rcc->num_entries; i++){
qscale[i] = get_qscale(h, &rcc->entry[i], rate_factor);
qscale[i] = get_qscale(h, &rcc->entry[i], rate_factor, i);
}
/* fixed I/B qscale relative to P */
......
......@@ -163,6 +163,8 @@ static void Help( x264_param_t *defaults )
"\n"
" -h, --help Print this help\n"
"\n"
"Frame-type options:\n"
"\n"
" -I, --keyint <integer> Maximum GOP size [%d]\n"
" -i, --min-keyint <integer> Minimum GOP size [%d]\n"
" --scenecut <integer> How aggressively to insert extra I-frames [%d]\n"
......@@ -176,6 +178,8 @@ static void Help( x264_param_t *defaults )
" --nf Disable loop filter\n"
" -f, --filter <alpha:beta> Loop filter AlphaC0 and Beta parameters [%d:%d]\n"
"\n"
"Ratecontrol:\n"
"\n"
" -q, --qp <integer> Set QP [%d]\n"
" -B, --bitrate <integer> Set bitrate\n"
" --qpmin <integer> Set min QP [%d]\n"
......@@ -200,9 +204,18 @@ static void Help( x264_param_t *defaults )
" --cplxblur <float> Reduce fluctuations in QP (before curve compression) [%.1f]\n"
" --qblur <float> Reduce fluctuations in QP (after curve compression) [%.1f]\n"
"\n"
" --zones <zone0>/<zone1>/...\n"
" Tweak the bitrate of some regions of the video\n"
" Each zone is of the form\n"
" <start frame>,<end frame>,<option>\n"
" where <option> is either\n"
" q=<integer> (force QP)\n"
" or b=<float> (bitrate multiplier)\n"
"\n"
"Analysis:\n"
"\n"
" -A, --analyse <string> Analyse options: [\"i4x4,p8x8,b8x8\"]\n"
" - i4x4\n"
" - p8x8, p4x4, b8x8\n"
" - i4x4, p8x8, p4x4, b8x8\n"
" - none, all\n"
" --direct <string> Direct MV prediction mode [\"temporal\"]\n"
" - none, spatial, temporal\n"
......@@ -215,6 +228,8 @@ static void Help( x264_param_t *defaults )
" -m, --subme <integer> Subpixel motion estimation quality: 1=fast, 5=best. [%d]\n"
" --no-chroma-me Ignore chroma in motion estimation\n"
"\n"
"Input/Output:\n"
"\n"
" --level <integer> Specify level (as defined by Annex A)\n"
" --sar width:height Specify Sample Aspect Ratio\n"
" --fps <float|rational> Specify framerate\n"
......@@ -337,6 +352,7 @@ static int Parse( int argc, char **argv,
#define OPT_VBVINIT 289
#define OPT_VISUALIZE 290
#define OPT_SEEK 291
#define OPT_ZONES 292
static struct option long_options[] =
{
......@@ -384,6 +400,7 @@ static int Parse( int argc, char **argv,
{ "qcomp", required_argument, NULL, OPT_QCOMP },
{ "qblur", required_argument, NULL, OPT_QBLUR },
{ "cplxblur",required_argument, NULL, OPT_CPLXBLUR },
{ "zones", required_argument, NULL, OPT_ZONES },
{ "no-psnr", no_argument, NULL, OPT_NOPSNR },
{ "quiet", no_argument, NULL, OPT_QUIET },
{ "verbose", no_argument, NULL, 'v' },
......@@ -622,6 +639,33 @@ static int Parse( int argc, char **argv,
case OPT_CPLXBLUR:
param->rc.f_complexity_blur = atof(optarg);
break;
case OPT_ZONES:
{
int i;
char *p;
param->rc.i_zones = 1;
for( p = optarg; *p; p++ )
param->rc.i_zones += (*p == '/');
param->rc.zones = (x264_zone_t*)malloc( param->rc.i_zones * sizeof(x264_zone_t) );
p = optarg;
for( i = 0; i < param->rc.i_zones; i++)
{
x264_zone_t *z = &param->rc.zones[i];
if( 3 == sscanf(p, "%u,%u,q=%u", &z->i_start, &z->i_end, &z->i_qp) )
z->b_force_qp = 1;
else if( 3 == sscanf(p, "%u,%u,b=%f", &z->i_start, &z->i_end, &z->f_bitrate_factor) )
z->b_force_qp = 0;
else
{
char *slash = strchr(p, '/');
if(slash) *slash = '\0';
fprintf( stderr, "invalid zone: \"%s\"\n", p );
return -1;
}
p = strchr(p, '/') + 1;
}
}
break;
case OPT_NOPSNR:
param->analyse.b_psnr = 0;
break;
......
......@@ -26,7 +26,7 @@
#include <stdarg.h>
#define X264_BUILD 25
#define X264_BUILD 26
/* x264_t:
* opaque handler for decoder and encoder */
......@@ -91,6 +91,14 @@ typedef struct x264_t x264_t;
#define X264_LOG_INFO 2
#define X264_LOG_DEBUG 3
typedef struct
{
int i_start, i_end;
int b_force_qp;
int i_qp;
float f_bitrate_factor;
} x264_zone_t;
typedef struct
{
/* CPU flags */
......@@ -179,11 +187,13 @@ typedef struct
int b_stat_read; /* Read stat from psz_stat_in and use it */
char *psz_stat_in;
/* 2pass params (same than ffmpeg ones) */
/* 2pass params (same as 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 */
float f_complexity_blur; /* temporally blur complexity */
int i_zones;
x264_zone_t *zones; /* ratecontrol overrides */
} rc;
int b_aud; /* generate access unit delimiters */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment