]> granicus.if.org Git - libx264/commitdiff
* all: 2pass patch by Loren Merritt <lorenm AT u.washington DOT edu>
authorLaurent Aimar <fenrir@videolan.org>
Sat, 28 Aug 2004 22:14:26 +0000 (22:14 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sat, 28 Aug 2004 22:14:26 +0000 (22:14 +0000)
 "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

Jamfile
core/common.c
core/common.h
core/frame.c
core/frame.h
encoder/encoder.c
encoder/ratecontrol.c
encoder/ratecontrol.h
x264.c
x264.h

diff --git a/Jamfile b/Jamfile
index 370aa3b2e19668a0410ad214017cf9864f6d9b1f..652ed6d92712d1116974e0d67e9b6380e9d76468 100644 (file)
--- 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 ;
index ac97562644d86286bafbfee67a595cb112e9c752..b8a157ed134dd477bbf1d09d66ab2c8479d62032 100644 (file)
@@ -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;
index 935b7f0d8c119f8a41f425ca7afe30e658deaf26..087778ccf0e8039894c7b0d210fb937b4b91129e 100644 (file)
@@ -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 */
index eca2ab63f38e15f7300832361637e7ce55d7dbd7..0ffc0cf3567d7b7aaaa69afc9cdb01abd4535f61 100644 (file)
@@ -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;
 }
index da7c45762ff94f70a12bf94f57fa891cc8906710..14fbece298d377f71eb40d2b5b5ee480dfba7d3c 100644 (file)
@@ -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;
index bf4003dcf91de2ab5bb09cf1d3cba5e537f5a15a..5fdf21a9c6c33b415d98b0f72a7f80bb3c7b8002 100644 (file)
@@ -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 );
 
index 95bc90d65abfc1cecbe8f6176c0b550ba46f4f3f..da8e352972bb03db5ccd14a4f0c94b3f162a5639 100644 (file)
@@ -5,6 +5,8 @@
  * $Id: ratecontrol.c,v 1.1 2004/06/03 19:27:08 fenrir Exp $
  *
  * Authors: Måns Rullgård <mru@mru.ath.cx>
+ * 2 pass code: Michael Niedermayer <michaelni@gmx.at>
+ *              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
  *****************************************************************************/
 
 #define _ISOC99_SOURCE
-
+#undef NDEBUG // always check asserts, the speed effect is far too small to disable them
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 #include <limits.h>
+#include <assert.h>
 
 #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; i<rc->num_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     (q<lmin) q = lmin;
+        else if(q>lmax) 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     (q<lmin) q=lmin;
+    else if(q>lmax) 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; i<rcc->num_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; i<rcc->num_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; i<rcc->num_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; i<rcc->num_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<filter_size; j++){
+                    int index = i+j-filter_size/2;
+                    double d = index-i;
+                    double coeff = qblur==0 ? 1.0 : exp(-d*d/(qblur*qblur));
+                    if(index < 0 || index >= 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; i<rcc->num_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;
+}
+
+
index b8072c506afae4c2dada068474db5fb5cc92140e..13475d3b470fd09f492374b28caf3aa5f6c70e9c 100644 (file)
@@ -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 4e9e015a1faf9390f94b7f6387cd4815e3f2306a..c657a6fc2af0d50e14f3efb2d867988cd8ba7bf9 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -120,6 +120,12 @@ static void Help( void )
              "      --rcbuf <integer>       Size of VBV buffer\n"
              "      --rcinitbuf <integer>   Initial VBV buffer occupancy\n"
              "\n"
+             "  -p, --pass <1|2>            Enable 2 pass ratecontrol\n"
+             "      --stats <string>        Filename for 2 pass stats\n"
+             "      --rceq <string>         Ratecontrol equation\n"
+             "      --qcomp <float>         0.0 => CBR, 1.0 => CQP, 0.6 => default\n"
+             "\n"
+
              "  -A, --analyse <string>      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 b6a7830e1f5e8288fac193fc1533363a6e06251b..76deec4ba2b40d3abd875c0a5508cbad66dbc831 100644 (file)
--- 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: