How do you reconfigure the bitrate during encoding?

Hello,

In the past few weeks, I have been trying to change the bitrate of an encoded video on the fly. I am doing real-time game live streaming, and being able to do this would be helpful.

I have not found any solution to this, but I found this in NvEncodeAPI.h:

/**
 * Indicates Dynamic Encode Bitrate Change Support.
 * Support added from NvEncodeAPI version 2.0.
 * \n 0 : Dynamic Encode bitrate change not supported.
 * \n 1 : Dynamic Encode bitrate change supported.
 */
NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE,

I have not found this usage of NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE anywhere else in the whole Video SDK, so I am wondering: is this available for us to use? How would I get around to using it?

I found a function called NvEncReconfigureEncoder that allows the bitrate and resolution of the encoded video to change during encoding.

I gave it a shot, and reconfiguring the bitrate does not work. Reconfiguring the resolution works (though not perfectly - it ends up cropped if reducing resolution).

I also went to check the capabilities via NvEncGetEncodeCaps. NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE is supported.

I used the NvEncoder sample. What I did was call NvEncReconfigureEncoder in the CNvEncoder::EncodeMain function in NvEncoder.cpp, where the encoding loop occurs (line 20-30 below):

for (int frm = encodeConfig.startFrameIdx; frm <= encodeConfig.endFrameIdx; frm++)
{
    numBytesRead = 0;
    loadframe(yuv, hInput, frm, encodeConfig.width, encodeConfig.height, numBytesRead, encodeConfig.isYuv444);
    if (numBytesRead == 0)
        break;

    EncodeFrameConfig stEncodeFrame;
    memset(&stEncodeFrame, 0, sizeof(stEncodeFrame));
    stEncodeFrame.yuv[0] = yuv[0];
    stEncodeFrame.yuv[1] = yuv[1];
    stEncodeFrame.yuv[2] = yuv[2];

    stEncodeFrame.stride[0] = encodeConfig.width;
    stEncodeFrame.stride[1] = (encodeConfig.isYuv444) ? encodeConfig.width : encodeConfig.width / 2;
    stEncodeFrame.stride[2] = (encodeConfig.isYuv444) ? encodeConfig.width : encodeConfig.width / 2;
    stEncodeFrame.width = encodeConfig.width;
    stEncodeFrame.height = encodeConfig.height;
    // ... original stuff above ...
    if (frm == encodeConfig.endFrameIdx / 2)
    {
        NvEncPictureCommand encPicCommand;
        
        encPicCommand.bBitrateChangePending = true;
        encPicCommand.newVBVSize = encodeConfig.vbvSize;
        encPicCommand.newBitrate = 250000;
            
        NVENCSTATUS status = m_pNvHWEncoder->NvEncReconfigureEncoder(&encPicCommand);
        // status returns NV_ENC_SUCCESS
    }
    // ... original stuff below ...
    EncodeFrame(&stEncodeFrame, false, encodeConfig.width, encodeConfig.height);
    numFramesEncoded++;
}

Did anyone else manage to get NvEncReconfigureEncoder to work? Maybe I did it wrongly?

Hi

A few questions:

  1. What is the SDK package version that you are using?
  2. What driver version are you using?
  3. Can you try reconfiguring the bitrate only? What is the result?

Thanks

Hi,

  1. I am using Video Codec SDK 6.0.1
  2. 369.49. This is the latest driver for the GRID K520.
  3. I have done that in my 2nd post and it has no effect. The file size of the video with and without the reconfiguration is exactly the same.

Edit: I gave the wrong SDK version earlier

Hi,

It turns out that the rate control mode is the culprit. The default setting without any -options is “constant QP”, which ignores any bitrate settings.

Changing the -rcmode to “Single pass VBR” solves this issue.