improved 2pass ratecontrol:
authorLoren Merritt <pengvado@videolan.org>
Wed, 17 Nov 2004 18:40:26 +0000 (18:40 +0000)
committerLoren Merritt <pengvado@videolan.org>
Wed, 17 Nov 2004 18:40:26 +0000 (18:40 +0000)
ensures that I-frames have comparable quantizer to the following P-frames,
and produces more consistent quality in areas of fluctuating complexity.

git-svn-id: svn://svn.videolan.org/x264/trunk@61 df754926-b1dd-0310-bc7b-ec298dee348c

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

index cbb1ea4..1d64d2e 100644 (file)
@@ -78,16 +78,17 @@ void    x264_param_default( x264_param_t *param )
     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.f_ip_factor = 1.4;
+    param->rc.f_pb_factor = 1.4;
 
     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.psz_rc_eq = "tex*blurTex^(qComp-1)";
     param->rc.f_qcompress = 0.6;
     param->rc.f_qblur = 0.5;
+    param->rc.f_complexity_blur = 20;
 
     /* Log */
     param->pf_log = x264_log_default;
index dd5fa34..ee51425 100644 (file)
@@ -68,20 +68,13 @@ void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... );
 
 static inline int x264_clip3( int v, int i_min, int i_max )
 {
-    if( v < i_min )
-    {
-        return i_min;
-    }
-    else if( v > i_max )
-    {
-        return i_max;
-    }
-    else
-    {
-        return v;
-    }
+    return ( (v < i_min) ? i_min : (v > i_max) ? i_max : v );
 }
 
+static inline float x264_clip3f( float v, float f_min, float f_max )
+{
+    return ( (v < f_min) ? f_min : (v > f_max) ? f_max : v );
+}
 
 /****************************************************************************
  *
index dab86e3..ee601d4 100644 (file)
@@ -333,14 +333,10 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
     /* Fix parameters values */
     h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, 15 );
     if( h->param.i_idrframe <= 0 )
-    {
         h->param.i_idrframe = 1;
-    }
     if( h->param.i_iframe <= 0 )
-    {
         h->param.i_iframe = 1;
-    }
-    h->param.i_bframe  = x264_clip3( h->param.i_bframe , 0, X264_BFRAME_MAX );
+    h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX );
 
     h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
     h->param.i_deblocking_filter_beta    = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 );
@@ -349,6 +345,11 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     param->analyse.i_subpel_refine = x264_clip3( param->analyse.i_subpel_refine, 0, 5 );
 
+    if( h->param.rc.f_qblur < 0 )
+        h->param.rc.f_qblur = 0;
+    if( h->param.rc.f_complexity_blur < 0 )
+        h->param.rc.f_complexity_blur = 0;
+
     /* VUI */
     if( h->param.vui.i_sar_width > 0 && h->param.vui.i_sar_height > 0 )
     {
index 047493f..89680a4 100644 (file)
@@ -60,8 +60,7 @@ typedef struct
     int i_count;
     int p_count;
     int s_count;
-    int f_code;
-    int b_code;
+    float blurred_complexity;
 } ratecontrol_entry_t;
 
 struct x264_ratecontrol_t
@@ -100,12 +99,13 @@ struct x264_ratecontrol_t
     FILE *p_stat_file_out;
 
     int num_entries;            /* number of ratecontrol_entry_ts */
-    ratecontrol_entry_t *entry;
+    ratecontrol_entry_t *entry; /* FIXME: copy needed data and free this once init is done */
     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 lstep;               /* max change (multiply) in qscale per frame */
     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];
@@ -131,12 +131,12 @@ static inline double qscale2qp(double qscale)
 
 static inline double qscale2bits(ratecontrol_entry_t *rce, double qscale)
 {
-    if(qscale<=0.0)
+    if(qscale<0.1)
     {
-        fprintf(stderr, "qscale<=0.0\n");
+        fprintf(stderr, "qscale<0.1\n");
         qscale = 0.1;
     }
-    return (double)(rce->i_tex_bits + rce->p_tex_bits + 1) * rce->qscale / qscale;
+    return (double)(rce->i_tex_bits + rce->p_tex_bits + .1) * rce->qscale / qscale;
 }
 
 static inline double bits2qscale(ratecontrol_entry_t *rce, double bits)
@@ -146,7 +146,7 @@ static inline double bits2qscale(ratecontrol_entry_t *rce, double bits)
         fprintf(stderr, "bits<0.9\n");
         bits = 1.0;
     }
-    return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / bits;
+    return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + .1) / bits;
 }
 
 
@@ -215,6 +215,7 @@ int x264_ratecontrol_new( x264_t *h )
     }
 
 
+    rc->lstep = exp2f(h->param.rc.i_qp_step / 6.0);
     for( i = 0; i < 5; i++ )
     {
         rc->last_qscale_for[i] = qp2qscale(26);
@@ -378,8 +379,7 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type )
                 qp--;
 #endif
             qp = x264_clip3(qp, rc->gop_qp - 4, rc->gop_qp + 4);
-            qp =
-                x264_clip3(qp, h->param.rc.i_qp_min, h->param.rc.i_qp_max);
+            qp = 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;
@@ -616,7 +616,6 @@ 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;
 
     double const_values[]={
@@ -636,6 +635,7 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
         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],
+        rce->blurred_complexity,
         0
     };
     static const char *const_names[]={
@@ -655,6 +655,7 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
         "avgPPTex",
         "avgBPTex",
         "avgTex",
+        "blurTex",
         NULL
     };
     static double (*func1[])(void *, double)={
@@ -670,6 +671,10 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
 
     bits = x264_eval((char*)h->param.rc.psz_rc_eq, const_values, const_names, func1, func1_names, NULL, NULL, rce);
 
+    // avoid NaN's in the rc_eq
+    if(bits != bits || rce->i_tex_bits + rce->p_tex_bits == 0)
+        bits = 0;
+
     bits *= rate_factor;
     if(bits<0.0) bits=0.0;
     bits += 1.0; //avoid 1/0 issues
@@ -700,42 +705,35 @@ static double get_diff_limited_q(x264_t *h, ratecontrol_entry_t *rce, double q)
     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);
+        double max_qscale = last_q * rcc->lstep;
+        double min_qscale = last_q / rcc->lstep;
 
         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
+    rcc->last_qscale_for[pict_type] = q;
     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 )
+// clip a qscale to between lmin and lmax
+static double clip_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];
+    double lmin = h->rc->lmin[rce->new_pict_type];
+    double lmax = h->rc->lmax[rce->new_pict_type];
 
-    if(lmin==lmax /* || !h->param.b_qsquish */){
-        if     (q<lmin) q = lmin;
-        else if(q>lmax) q = lmax;
+    if(lmin==lmax){
+        return lmin;
     }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 = (log(q) - min2)/(max2-min2) - 0.5;
+        q = 1.0/(1.0 + exp(-4*q));
         q = q*(max2-min2) + min2;
-
-        q = exp(q);
+        return exp(q);
     }
-    return q;
 }
 
 // update qscale for 1 frame based on actual bits used so far
@@ -749,7 +747,6 @@ static float rate_estimate_qscale(x264_t *h, int pict_type)
     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]);
@@ -761,17 +758,12 @@ static float rate_estimate_qscale(x264_t *h, int pict_type)
     if(pict_type!=SLICE_TYPE_I)
         assert(pict_type == rce->new_pict_type);
 
-    wanted_bits = rce->expected_bits;
-
-    diff = total_bits - wanted_bits;
+    diff = (int64_t)total_bits - (int64_t)rce->expected_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;
-
+    q = x264_clip3f(q, lmin, lmax);
     rcc->last_qscale = q;
     return q;
 }
@@ -783,7 +775,9 @@ static int init_pass2( x264_t *h )
     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;
+    double cplxblur = h->param.rc.f_complexity_blur;
     const int filter_size = (int)(qblur*4) | 1;
+    const int cplx_filter_size = (int)(cplxblur*2);
     double expected_bits;
     double *qscale, *blurred_qscale;
     int i;
@@ -806,19 +800,51 @@ static int init_pass2( x264_t *h )
         return -1;
     }
 
+    if(cplxblur<.01)
+        cplxblur = .01;
+    for(i=0; i<rcc->num_entries; i++){
+        ratecontrol_entry_t *rce = &rcc->entry[i];
+        double weight, weight_sum = 0;
+        double cplx_sum = 0;
+        double mask = 1.0;
+        int j;
+        /* weighted average of cplx of future frames */
+        for(j=1; j<cplx_filter_size && j<rcc->num_entries-i; j++){
+            ratecontrol_entry_t *rcj = &rcc->entry[i+j];
+            mask *= (double)(rcc->nmb + rcj->i_count) / rcc->nmb;
+            weight = mask * exp(-j*j/(cplxblur*cplxblur));
+            if(weight < .0001)
+                break;
+            weight_sum += weight;
+            cplx_sum += weight * (rcj->i_tex_bits + rcj->p_tex_bits) * rce->qscale;
+        }
+        /* weighted average of cplx of past frames */
+        mask = 1.0;
+        for(j=0; j<cplx_filter_size && j<=i; j++){
+            ratecontrol_entry_t *rcj = &rcc->entry[i-j];
+            weight = mask * exp(-j*j/(cplxblur*cplxblur));
+            weight_sum += weight;
+            cplx_sum += weight * (rcj->i_tex_bits + rcj->p_tex_bits) * rce->qscale;
+            mask *= (double)(rcc->nmb + rcj->i_count) / rcc->nmb;
+            if(weight < .0001)
+                break;
+        }
+        rce->blurred_complexity = cplx_sum / weight_sum;
+    }
+
     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;
+    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));
     step_mult = all_available_bits / expected_bits;
 
     rate_factor = 0;
-    for(step = 1E4 * step_mult; step > 1E-7 * step_mult; step*=0.5){
+    for(step = 1E4 * step_mult; step > 1E-7 * step_mult; step *= 0.5){
         expected_bits = 0;
         rate_factor += step;
 
@@ -859,7 +885,7 @@ static int init_pass2( x264_t *h )
         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]);
+            rce->new_qscale = clip_qscale(h, rce, blurred_qscale[i]);
             assert(rce->new_qscale >= 0);
             bits = qscale2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits;
 
@@ -879,9 +905,8 @@ static int init_pass2( x264_t *h )
     {
         double avgq = 0;
         for(i=0; i<rcc->num_entries; i++)
-            if(rcc->entry[i].new_pict_type == SLICE_TYPE_P)
-                avgq += rcc->entry[i].new_qscale;
-        avgq = qscale2qp(avgq / rcc->frame_count[SLICE_TYPE_P]);
+            avgq += rcc->entry[i].new_qscale;
+        avgq = qscale2qp(avgq / rcc->num_entries);
 
         x264_log(h, X264_LOG_ERROR, "Error: 2pass curve failed to converge\n");
         x264_log(h, X264_LOG_ERROR, "expected bits: %llu, available: %llu, avg QP: %.4lf\n", (uint64_t)expected_bits, all_available_bits, avgq);
diff --git a/x264.c b/x264.c
index e34b27c..9ced41b 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -127,6 +127,8 @@ static void Help( void )
              "      --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"
+             "      --cplxblur <float>      reduce fluctuations in QP (before curve compression)\n"
+             "      --qblur <float>         reduce fluctuations in QP (after curve compression)\n"
              "\n"
 
              "  -A, --analyse <string>      Analyse options:\n"
@@ -180,6 +182,8 @@ static int  Parse( int argc, char **argv,
 #define OPT_QUIET 268
 #define OPT_SUBME 269
 #define OPT_SCENECUT 270
+#define OPT_QBLUR 271
+#define OPT_CPLXBLUR 272
 
         static struct option long_options[] =
         {
@@ -211,6 +215,8 @@ static int  Parse( int argc, char **argv,
             { "stats",   required_argument, NULL, OPT_RCSTATS },
             { "rceq",    required_argument, NULL, OPT_RCEQ },
             { "qcomp",   required_argument, NULL, OPT_QCOMP },
+            { "qblur",   required_argument, NULL, OPT_QBLUR },
+            { "cplxblur",required_argument, NULL, OPT_CPLXBLUR },
             { "no-psnr", no_argument,       NULL, OPT_NOPSNR },
             { "quiet",   no_argument,       NULL, OPT_QUIET },
             {0, 0, 0, 0}
@@ -353,7 +359,12 @@ static int  Parse( int argc, char **argv,
             case OPT_QCOMP:
                 param->rc.f_qcompress = atof(optarg);
                 break;
-
+            case OPT_QBLUR:
+                param->rc.f_qblur = atof(optarg);
+                break;
+            case OPT_CPLXBLUR:
+                param->rc.f_complexity_blur = atof(optarg);
+                break;
             case OPT_NOPSNR:
                 param->analyse.b_psnr = 0;
                 break;
diff --git a/x264.h b/x264.h
index e6b7ba3..b276d66 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -26,7 +26,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 0x000b
+#define X264_BUILD 0x000c
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -158,6 +158,7 @@ typedef struct
         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 */
     } rc;
 
 } x264_param_t;