* all: Patch from Måns Rullgård <mru AT mru DOT ath DOT cx>
authorLaurent Aimar <fenrir@videolan.org>
Fri, 6 Aug 2004 18:06:09 +0000 (18:06 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Fri, 6 Aug 2004 18:06:09 +0000 (18:06 +0000)
"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

AUTHORS
core/common.c
core/common.h
encoder/analyse.c
encoder/encoder.c
encoder/ratecontrol.c
encoder/ratecontrol.h
x264.c
x264.h

diff --git a/AUTHORS b/AUTHORS
index af06be2..2b219dc 100644 (file)
--- 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
index a4a21d4..1e3e4c2 100644 (file)
@@ -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;
index 11b9fae..c2764ed 100644 (file)
@@ -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
     {
index aaca97e..27cf993 100644 (file)
@@ -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 )
index f9c0310..1e9d329 100644 (file)
@@ -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 );
index fc0226e..d49cbb8 100644 (file)
@@ -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: Måns Rullgård <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
  * 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;
 }
 
index 5fa3c7c..b8072c5 100644 (file)
 #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 57254ea..a16cf6b 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -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;
                 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 772c6c7..a34be81 100644 (file)
--- 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