Problem with rate control in encoding for CBR. In these examples, typical VCD settings are used. Same settings with each. The first example is done with vanilla CVS 20040509 build. Problems. # All video with separate I and P frames encoded with a maximum bitrate, ie CBR video suffers from very noticeable pulsing - considerably more than other codecs. To reproduce: Use the "vcd" target setting to encode any video. Particularly noticeable on higher quality video with low motion. This is due to problem with rate control in CBR (ie, where maxrate is used). The nature of the problem: Video consists of i-frames and p-frames (and sometimes b-frames) i-frames typically require 2 or 3 times the bandwidth of p-frames. The rate limiting code around line 433 of ratecontrol.c works in this way: # There is a rate control buffer. Each frame takes up some of the rate control buffer # The rate control code estimates the quality of the next frame according to how much space is left for it in the buffer. It does this so that each frame takes up maximum one third of the remaining buffer size. However, the i-frames typically require much more space than this. Reducing i-frames to this size requires slaugtering their quality factor, and the i-frames all end up way lower quality (by factor of 2 or 3) than all the other frames. An i-frame needs a specially large amount of buffer space - much more than would be expected for a p-frame - for the same quality level. What needs to be done: # Increase the amount of buffer space that a single frame may occupy. This will allow some frames to take up much more space than other frames. # The aim of this code is to alter the quality as little as possible. It needs to enforce a hard limit to prevent buffer underflows, but other than that it shouldn't alter the quality of frames as much as it does. # Where it does alter the quality of frames, it should do so in a way to ensure that the *quality* of frames are all treated equally. At the moment, the quality of larger frames such as i-frames suffers at the expense of the quality of p-frames. # It shouldn't be necessary for the rate control code to take into account that some frames are larger than others, but it might help to do so, especially for i-frames. The below patch is a quick patch that I came up with to solve some of the problems. It cuts down on pulsing dramatically, and in many cases will allow i-frames the correct q factor. Almost no pulsing is visible after this. However, it still doesn't solve other problems with rate control. The "output_after.mpeg" file shows the output from ffmpeg after this patch is applied. Other problems with rate control: # When encoding MPEG1/MPEG2, there are always one or more instances of "rc buffer underflow" near the very start, ie in the first one second or so. Although I can't think of how to fix this or what the problem is, no other MPEG1 encoders I know suffer from this problem - video is always crystal clear even at the very start. With ffmpeg it seems to take about a half second or so of really bad quality for it to stabilize. This is the patch I mentioned earlier which helps reduce the pulsing, but not the other bugs: --- ../ffmpeg-cvs-2004-05-09/libavcodec/ratecontrol.c Sun Feb 15 00:37:58 2004 +++ ./libavcodec/ratecontrol.c Sun May 9 21:58:00 2004 @@ -421,7 +421,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)*5, 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); @@ -431,12 +431,13 @@ } if(max_rate){ - double d= 2*expected_size/buffer_size; + double factor = (rce->pict_type == I_TYPE) ? 4.4 : 1.55; + double d= factor*expected_size/buffer_size; if(d>1.0) d=1.0; 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/1.7, 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);