[Ffmpeg-devel] Intra-frame rate control

RLopez rlopez
Sat Apr 7 09:15:07 CEST 2007


Hi,

>> If avcodec.lib can only change Q values at picture boundaries for MPEG2
>> files that's a huge limitation.  The advantage of MPEG2 over MJPEG is the
>> ability to change the Q in the middle of an image.

>The advantage of MPEG2 over MJPEG is P- and B-frames. I'd call adaptive 
>quant rather minor in comparison.

You're right.  I should have said the advantage of MPEG I-frames over MJPEG
is the ability to change the Q in the middle of the image.

>> A common clip people use to show this off is a field of daisies under 
>> a blue sky.  The blue sky can  be encoded well with a high Q value while 
>> the more complex field of daisies portion of the image can be encoded 
>> with a lower Q value.

>But the blue sky also uses much less bitrate at the same QP. So I'm not so 
>sure that the optimal encoding mode is to raise the QP of the sky.
>On the contrary, x264's adaptive quant uses _lower_ QP for smooth 
>gradients like a sky, since any tiny deviation from the gradient will be 
>blatantly visible, whereas small errors in the daisies would be hidden by 
>the masses of detail. I don't think H.264 is so different from MPEG2 as to 
>reverse the direction of that decision...

>> Another problem I'm seeing caused by avcodec.lib only changing Q values
at
>> picture boundaries is that the instantaneous bitrate of an encoded clip
>> jumps around too much.  For example when a complex image follows several
>> black frames the bitrate skyrockets because the rate controller lowered
the
>> Q during the black frames and doesn't readjust it until the end of the
>> complex frame.  This problem is especially bad when working with HD
images.

>Just because it only changes QP between frames doesn't mean it can only 
>react. RC examines the current frame before choosing a QP. The QP chosen 
>for one frame will be independent of the complexity of the previous 
>frames, except insofar as RC reacts to the VBV state or otherwise 
>introduces an explicit dependency (qblur, etc).

I did a test where I encoded 10 flat gray frames(1920x1080) followed by 10
frames of random data using avcodec.lib and again using Pexeltool MPEG2
encoder.  I set the bitrate to 20 Mbs.  Here are the results:

                    avcodec               Pixeltools
Frame #   Frames size   Q values    Frames size   Q values
=======   =======================   ======================
   1         30987    Fixed at 2      83245       1 - 3
   2         30987    Fixed at 2      83242       1 - 3
   3         30987    Fixed at 2      83239     Fixed at 1
   4         30987    Fixed at 2      83239     Fixed at 1
   5         30987    Fixed at 2      83239     Fixed at 1
   6         30987    Fixed at 2      83239     Fixed at 1
   7         30987    Fixed at 2      83239     Fixed at 1
   8         30987    Fixed at 2      83239     Fixed at 1
   9         30987    Fixed at 2      83239     Fixed at 1
  10         30987    Fixed at 2      83239     Fixed at 1
  11       3102876    Fixed at 2      86344       1 - 27
  12       3103653    Fixed at 2      85680      12 - 31
  13       1846080    Fixed at 5      83110      18 - 31
  14       1498372    Fixed at 7      83141      27 - 31
  15       1178371    Fixed at 10     83210      25 - 30
  16        972263    Fixed at 13     83174      24 - 30
  17        819350    Fixed at 16     83189      25 - 29
  18        701635    Fixed at 19     83210      26 - 29
  19        611076    Fixed at 22     83135      28 - 31
  20        535178    Fixed at 25     83227      27 - 31

The average frame size should be 83416.  As you can see avcodec only changes
the Q at picture boundaries and when it hits frame 11 (the first random
frame) the frame rate skyrockets and it only adjusts the q value by about 3
for each subsequent frame as it attempts to bring the bitrate down.  The
Pixeltools encoder varies the Q throughout the frame to keep the bitrate
around 20 Mbs.  At frame 11 the Q values vary widely throughout the frame as
it tries to control the bitrate eventually settling at a point where all the
slices end up with Q values between 27 and 31.  I attached the code I used
for the avcodec test.

Rudy
 
>--Loren Merritt

#include "avformat.h"

int picturebuf[1920*1080/2];
unsigned char outbuf[4*1024*1024];
AVCodecContext ffenc;
AVFrame        picture;

int main(int argc, char* argv[])
{
    int i,j,k,random,size1,size2;
    FILE *fid;
    AVCodec        *codec;

    int bitrate  = 20000000; 
    int width    = 1920; 
    int height   = 1080; 
    int gopsize  = 1;
    int bframes  = 0;
    int ratenum  = 1001;
    int rateden  = 30000;

    av_register_all();
    av_log_set_level(-1);

    avcodec_get_frame_defaults(&picture);
    avpicture_fill((AVPicture *)&picture, 0, PIX_FMT_YUV420P, width,
height);
    size1 = picture.data[1] - picture.data[0];
    size2 = picture.data[2] - picture.data[1];
    avcodec_get_context_defaults(&ffenc);

    ffenc.codec_id                = CODEC_ID_MPEG2VIDEO;
    ffenc.codec_type              = CODEC_TYPE_VIDEO;

    ffenc.sample_aspect_ratio.num = 1;
    ffenc.sample_aspect_ratio.den = 1;
    ffenc.bit_rate                = bitrate;
    ffenc.width                   = width;  
    ffenc.height                  = height;
    ffenc.profile                 = 4;
    ffenc.level                   = 4;
    ffenc.time_base.num           = ratenum;
    ffenc.time_base.den           = rateden;
    ffenc.gop_size                = gopsize;
    ffenc.max_b_frames            = bframes;

    ffenc.scenechange_threshold   = 1000000000;
    ffenc.bit_rate_tolerance      = 4000*1000;
    ffenc.qblur                   = 0.5;
    ffenc.rc_buffer_aggressivity  = 1.0;
    ffenc.pix_fmt                 = PIX_FMT_YUV420P;
    codec = avcodec_find_encoder(ffenc.codec_id);
    avcodec_open(&ffenc, codec);
    
    fid = fopen("c:\\test.mpg","wb");
    for (random=0;random<2;random++) {
        if (!random) for (j=0;j<(1920*1080/2);j++) picturebuf[j] =
0x80808080;
        for (i=0;i<10;i++) {
            if (random) for (j=0;j<(1920*1080/2);j++) picturebuf[j] =
rand();
            picture.data[0] = (unsigned char*) picturebuf;
            picture.data[1] = picture.data[0] + size1;
            picture.data[2] = picture.data[1] + size2;
            k = avcodec_encode_video(&ffenc, outbuf, 16*1024*1024,
&picture);
            fwrite(outbuf,1,k,fid);
        }
    }
    fclose(fid);
    avcodec_close(&ffenc);
    return 0;
}






More information about the ffmpeg-devel mailing list