]> git.sesse.net Git - x264/commitdiff
"CRF-max" support with VBV
authorFiona Glaser <fiona@x264.com>
Fri, 19 Mar 2010 21:44:10 +0000 (14:44 -0700)
committerFiona Glaser <fiona@x264.com>
Sat, 27 Mar 2010 19:47:03 +0000 (12:47 -0700)
This is a rather curious feature that may have more use than is initially obvious.
In CRF mode with VBV enabled, CRF-max allows the user to specify a quality level which the encoder will never go below, even due to the effects of VBV.
This is not the same as qpmax, which is not aware of issues like scene complexity.
Setting this WILL cause VBV underflows in any situation where the encoder would have needed to exceed the relevant CRF to avoid underflow.

Why might one want to do this even if it would cause VBV underflows?
In the case of streaming, particularly ultra-low-latency streaming, it may be preferable to drop frames than to display frames that are of too low a quality.
Thus, in extremely complex scenes, rather than display completely awful video, the streaming server could simply drop to a lower framerate.
Scenecuts, which normally look terrible under situations like single-frame VBV, could be handled by just displaying them a bit later and dropping frames to compensate.
In other words, it's better to see the scenecut 150ms delayed than for it to look like a blocky mess for 150ms.

On the caller-side, this would be handled by detecting the output size of x264's frames and dropping future frames to compensate if necessary.

This can also be used in normal encoding simply to ensure that VBV does not hurt quality too much (at the cost of potentially causing underflows).
This can help quite a lot when using single-frame VBV and sliced threads, where VBV can often be somewhat unstable.

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

index a4ec2bb4b4624fa66df4a9ca0f7b702aa87fbc9c..71fce02884e6eff452bc12323daaf78e6a797e48 100644 (file)
@@ -845,6 +845,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
         p->rc.f_rf_constant = atof(value);
         p->rc.i_rc_method = X264_RC_CRF;
     }
+    OPT("crf-max")
+        p->rc.f_rf_constant_max = atof(value);
     OPT("rc-lookahead")
         p->rc.i_lookahead = atoi(value);
     OPT2("qpmin", "qp-min")
@@ -1232,8 +1234,12 @@ char *x264_param2string( x264_param_t *p, int b_res )
             s += sprintf( s, " cplxblur=%.1f qblur=%.1f",
                           p->rc.f_complexity_blur, p->rc.f_qblur );
         if( p->rc.i_vbv_buffer_size )
+        {
             s += sprintf( s, " vbv_maxrate=%d vbv_bufsize=%d",
                           p->rc.i_vbv_max_bitrate, p->rc.i_vbv_buffer_size );
+            if( p->rc.i_rc_method == X264_RC_CRF )
+                s += sprintf( s, " crf-max=%f", p->rc.f_rf_constant_max );
+        }
     }
     else if( p->rc.i_rc_method == X264_RC_CQP )
         s += sprintf( s, " qp=%d", p->rc.i_qp_constant );
index 11a3bf5f7e14ac1fde6c00ce93d2fa357c1d6337..447e77c515e95e1d90600662110ebd7dfd3cefbe 100644 (file)
@@ -1186,6 +1186,11 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
         COPY( rc.f_rf_constant );
         rc_reconfig = 1;
     }
+    if( h->param.rc.f_rf_constant_max != param->rc.f_rf_constant_max )
+    {
+        COPY( rc.f_rf_constant_max );
+        rc_reconfig = 1;
+    }
 
 #undef COPY
 
index c95bbaf42c41bd85b7c0993538605af64ca4bcdb..1ccceb51fc392ffdc9e8fa702c83c356dc903a1e 100644 (file)
@@ -99,6 +99,7 @@ struct x264_ratecontrol_t
     double vbv_max_rate;        /* # of bits added to buffer_fill per second */
     predictor_t *pred;          /* predict frame size from satd */
     int single_frame_vbv;
+    double rate_factor_max_increment; /* Don't allow RF above (CRF + this value). */
 
     /* ABR stuff */
     int    last_satd;
@@ -487,6 +488,15 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init )
         rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size;
         rc->cbr_decay = 1.0 - rc->buffer_rate / rc->buffer_size
                       * 0.5 * X264_MAX(0, 1.5 - rc->buffer_rate * rc->fps / rc->bitrate);
+        if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.f_rf_constant_max )
+        {
+            rc->rate_factor_max_increment = h->param.rc.f_rf_constant_max - h->param.rc.f_rf_constant;
+            if( rc->rate_factor_max_increment <= 0 )
+            {
+                x264_log( h, X264_LOG_WARNING, "CRF max must be greater than CRF\n" );
+                rc->rate_factor_max_increment = 0;
+            }
+        }
         if( b_init )
         {
             if( h->param.rc.f_vbv_buffer_init > 1. )
@@ -1266,8 +1276,11 @@ void x264_ratecontrol_mb( x264_t *h, int bits )
     {
         int i;
         int prev_row_qp = h->fdec->i_row_qp[y];
-        int i_qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, h->param.rc.i_qp_max );
         int i_qp_min = X264_MAX( prev_row_qp - h->param.rc.i_qp_step, h->param.rc.i_qp_min );
+        int i_qp_absolute_max = h->param.rc.i_qp_max;
+        if( rc->rate_factor_max_increment )
+            i_qp_absolute_max = X264_MIN( i_qp_absolute_max, rc->qp_novbv + rc->rate_factor_max_increment );
+        int i_qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, i_qp_absolute_max );
 
         /* B-frames shouldn't use lower QP than their reference frames. */
         if( h->sh.i_type == SLICE_TYPE_B )
@@ -1322,7 +1335,7 @@ void x264_ratecontrol_mb( x264_t *h, int bits )
         }
 
         /* avoid VBV underflow or MinCR violation */
-        while( (rc->qpm < h->param.rc.i_qp_max)
+        while( (rc->qpm < i_qp_absolute_max)
                && ((rc->buffer_fill - b1 < rc->buffer_rate * rc->max_frame_error) ||
                    (rc->frame_size_maximum - b1 < rc->frame_size_maximum * rc->max_frame_error)))
         {
@@ -1765,6 +1778,8 @@ static double clip_qscale( x264_t *h, int pict_type, double q )
     x264_ratecontrol_t *rcc = h->rc;
     double lmin = rcc->lmin[pict_type];
     double lmax = rcc->lmax[pict_type];
+    if( rcc->rate_factor_max_increment )
+        lmax = X264_MIN( lmax, qp2qscale( rcc->qp_novbv + rcc->rate_factor_max_increment ) );
     double q0 = q;
 
     /* B-frames are not directly subject to VBV,
diff --git a/x264.c b/x264.c
index 4712473e2e1bdbe0ba1f6b6ff1990c5c10cde602..ec342d4e4922ea0c106f396b4a0fa1a4dc6a3d6c 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -390,6 +390,8 @@ static void Help( x264_param_t *defaults, int longhelp )
     H0( "      --vbv-maxrate <integer> Max local bitrate (kbit/s) [%d]\n", defaults->rc.i_vbv_max_bitrate );
     H0( "      --vbv-bufsize <integer> Set size of the VBV buffer (kbit) [%d]\n", defaults->rc.i_vbv_buffer_size );
     H2( "      --vbv-init <float>      Initial VBV buffer occupancy [%.1f]\n", defaults->rc.f_vbv_buffer_init );
+    H2( "      --crf-max <float>       With CRF+VBV, limit RF to this value\n"
+        "                                  May cause VBV underflows!\n" );
     H2( "      --qpmin <integer>       Set min QP [%d]\n", defaults->rc.i_qp_min );
     H2( "      --qpmax <integer>       Set max QP [%d]\n", defaults->rc.i_qp_max );
     H2( "      --qpstep <integer>      Set max QP step [%d]\n", defaults->rc.i_qp_step );
@@ -673,7 +675,8 @@ static struct option long_options[] =
     { "ratetol",     required_argument, NULL, 0 },
     { "vbv-maxrate", required_argument, NULL, 0 },
     { "vbv-bufsize", required_argument, NULL, 0 },
-    { "vbv-init",    required_argument, NULL,  0 },
+    { "vbv-init",    required_argument, NULL, 0 },
+    { "crf-max",     required_argument, NULL, 0 },
     { "ipratio",     required_argument, NULL, 0 },
     { "pbratio",     required_argument, NULL, 0 },
     { "chroma-qp-offset", required_argument, NULL, 0 },
diff --git a/x264.h b/x264.h
index 77313c72e3cf93e1571f73281fb8a7d8ea980f8b..9f5eb1dffd89fc9a4cbb868e28c55eab74796fb3 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 89
+#define X264_BUILD 90
 
 /* x264_t:
  *      opaque handler for encoder */
@@ -294,6 +294,7 @@ typedef struct x264_param_t
 
         int         i_bitrate;
         float       f_rf_constant;  /* 1pass VBR, nominal QP */
+        float       f_rf_constant_max;  /* In CRF mode, maximum CRF as caused by VBV */
         float       f_rate_tolerance;
         int         i_vbv_max_bitrate;
         int         i_vbv_buffer_size;