[Ffmpeg-devel] [patch] rc buffer bits reservation for I-frames

Jindrich Makovicka makovick
Fri Nov 24 16:11:32 CET 2006


Hi,

when using a short RC buffer and tight bitrate restrictions (typically
when encoding for DVB), the rate control sometimes tends to use too
much bits for P-frames, and when an I-frame gets encoded, there is not
enough bits available, causing a sudden quality decrease.

The attached patch adds an option to reserve a specified multiple of
the last I-frame size in the RC buffer. Default value if 0, i.e.
unchanged from the current state.

Sample mpeg2 movies with reservation factor set to 0 and 1 are available at

http://kmlinux.fjfi.cvut.cz/~makovick/res0.avi

http://kmlinux.fjfi.cvut.cz/~makovick/res1.avi .

The movies were encoded using mplayer with -lavcopts
vcodec=mpeg2video:mbd=2:vbitrate=1500:vrc_maxrate=1500:vrc_buf_size=750

The difference is clearly visible when you open the movies in avidemux
and look at the I-frames.

Regards,
-- 
Jindrich Makovicka
-------------- next part --------------
Index: utils.c
===================================================================
--- utils.c	(revision 7165)
+++ utils.c	(working copy)
@@ -539,6 +539,7 @@
 {"minrate", "set min video bitrate tolerance (in bits/s)", OFFSET(rc_min_rate), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, V|E},
 {"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, V|E},
 {"rc_buf_aggressivity", NULL, OFFSET(rc_buffer_aggressivity), FF_OPT_TYPE_FLOAT, 1.0, FLT_MIN, FLT_MAX, V|E},
+{"rc_buf_iframe_reserve", NULL, OFFSET(rc_buffer_iframe_reserve), FF_OPT_TYPE_FLOAT, 0.0, 0.0, FLT_MAX, V|E},
 {"i_qfactor", "qp factor between p and i frames", OFFSET(i_quant_factor), FF_OPT_TYPE_FLOAT, -0.8, -FLT_MAX, FLT_MAX, V|E},
 {"i_qoffset", "qp offset between p and i frames", OFFSET(i_quant_offset), FF_OPT_TYPE_FLOAT, 0.0, -FLT_MAX, FLT_MAX, V|E},
 {"rc_init_cplx", "initial complexity for 1-pass encoding", OFFSET(rc_initial_cplx), FF_OPT_TYPE_FLOAT, DEFAULT, -FLT_MAX, FLT_MAX, V|E},
Index: avcodec.h
===================================================================
--- avcodec.h	(revision 7165)
+++ avcodec.h	(working copy)
@@ -1131,6 +1131,7 @@
      */
     int rc_buffer_size;
     float rc_buffer_aggressivity;
+    float rc_buffer_iframe_reserve;
 
     /**
      * qscale factor between p and i frames.
Index: ratecontrol.c
===================================================================
--- ratecontrol.c	(revision 7165)
+++ ratecontrol.c	(working copy)
@@ -125,6 +125,7 @@
         rcc->last_qscale_for[i]=FF_QP2LAMBDA * 5;
     }
     rcc->buffer_index= s->avctx->rc_initial_buffer_occupancy;
+    rcc->prev_iframe_bits= 0;
 
     if(s->flags&CODEC_FLAG_PASS2){
         int i;
@@ -426,7 +427,7 @@
     *qmax_ret= qmax;
 }
 
-static double modify_qscale(MpegEncContext *s, RateControlEntry *rce, double q, int frame_num){
+static double modify_qscale(MpegEncContext *s, RateControlEntry *rce, double q, int frame_num, double reserve){
     RateControlContext *rcc= &s->rc_context;
     int qmin, qmax;
     double bits;
@@ -446,7 +447,7 @@
 //printf("q:%f\n", q);
     /* buffer overflow/underflow protection */
     if(buffer_size){
-        double expected_size= rcc->buffer_index;
+        double expected_size= rcc->buffer_index - reserve;
         double q_limit;
 
         if(min_rate){
@@ -455,7 +456,7 @@
             else if(d<0.0001) d=0.0001;
             q*= pow(d, 1.0/s->avctx->rc_buffer_aggressivity);
 
-            q_limit= bits2qp(rce, FFMAX((min_rate - buffer_size + rcc->buffer_index)*3, 1));
+            q_limit= bits2qp(rce, FFMAX((min_rate - buffer_size + rcc->buffer_index - reserve)*3, 1));
             if(q > q_limit){
                 if(s->avctx->debug&FF_DEBUG_RC){
                     av_log(s->avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit);
@@ -470,7 +471,7 @@
             else if(d<0.0001) d=0.0001;
             q/= pow(d, 1.0/s->avctx->rc_buffer_aggressivity);
 
-            q_limit= bits2qp(rce, FFMAX(rcc->buffer_index/3, 1));
+            q_limit= bits2qp(rce, FFMAX((rcc->buffer_index - reserve)/3, 1));
             if(q < q_limit){
                 if(s->avctx->debug&FF_DEBUG_RC){
                     av_log(s->avctx, AV_LOG_DEBUG, "limiting QP %f -> %f\n", q, q_limit);
@@ -711,6 +712,8 @@
         q= rce->new_qscale / br_compensation;
 //printf("%f %f %f last:%d var:%d type:%d//\n", q, rce->new_qscale, br_compensation, s->frame_bits, var, pict_type);
     }else{
+        double reserve;
+        
         rce->pict_type=
         rce->new_pict_type= pict_type;
         rce->mc_mb_var_sum= pic->mc_mb_var_sum;
@@ -763,8 +766,17 @@
         }
         assert(q>0.0);
 
-        q= modify_qscale(s, rce, q, picture_number);
+        if (pict_type != I_TYPE)
+            reserve = rcc->prev_iframe_bits * s->avctx->rc_buffer_iframe_reserve;
+        else
+            reserve = 0;
 
+        q= modify_qscale(s, rce, q, picture_number, reserve);
+
+        if (pict_type == I_TYPE) {
+            rcc->prev_iframe_bits = predict_size(&rcc->pred[I_TYPE], q, sqrt(var));
+        }
+
         rcc->pass1_wanted_bits+= s->bit_rate/fps;
 
         assert(q>0.0);
@@ -888,7 +900,7 @@
         for(i=0; i<rcc->num_entries; i++){
             RateControlEntry *rce= &rcc->entry[i];
             double bits;
-            rce->new_qscale= modify_qscale(s, rce, blured_qscale[i], i);
+            rce->new_qscale= modify_qscale(s, rce, blured_qscale[i], i, 0);
             bits= qp2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits;
 //printf("%d %f\n", rce->new_bits, blured_qscale[i]);
             bits += 8*ff_vbv_update(s, bits);
Index: ratecontrol.h
===================================================================
--- ratecontrol.h	(revision 7165)
+++ ratecontrol.h	(working copy)
@@ -63,6 +63,7 @@
     int num_entries;              ///< number of RateControlEntries
     RateControlEntry *entry;
     double buffer_index;          ///< amount of bits in the video/audio buffer
+    double prev_iframe_bits;
     Predictor pred[5];
     double short_term_qsum;       ///< sum of recent qscales
     double short_term_qcount;     ///< count of recent qscales



More information about the ffmpeg-devel mailing list