Commit 20c19c4b authored by Laurent Aimar's avatar Laurent Aimar

* all: Patch from Måns Rullgård <mru AT mru DOT ath DOT cx>

"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
parent 30a244d0
......@@ -33,3 +33,8 @@ E: justin_clay AT hotmail DOT com
C: wheatgerm
D: Inital work on vfw
S: Nova Scotia, Canada
N: Mns Rullgrd
E: mru AT mru.ath DOT cx
D: Rate control
S: Oslo, Norway
......@@ -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;
......
......@@ -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
{
......
......@@ -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 )
......
......@@ -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 );
......
......@@ -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 <fenrir@via.ecp.fr>
* Authors: Mns Rullgrd <mru@mru.ath.cx>
*
* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#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;
}
......@@ -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
......@@ -111,8 +111,15 @@ static void Help( void )
" -r, --ref <integer> Number of references\n"
" -n, --nf Disable loop filter\n"
" -f, --filter <alpha:beta> Loop filter AplhaCO and Beta parameters\n"
"\n"
" -q, --qp <integer> Set QP\n"
" -B, --bitrate <integer> Set bitrate [broken]\n"
" -B, --bitrate <integer> Set bitrate\n"
" --qpmin <integer> Set min QP\n"
" --qpmax <integer> Set max QP\n"
" --qpstep <integer> Set max QP step\n"
" --rcsens <integer> RC sensitivity\n"
" --rcbuf <integer> Size of VBV buffer\n"
" --rcinitbuf <integer> Initial VBV buffer occupancy\n"
"\n"
" -A, --analyse <string> 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;
<