Using various posts sprinkled around the Internet, including this one here on SO, I've been able to understand how to use the FFmpeg cli to generate a CBR video bitrate using the x264 codec (wrapped in an MPEG-2 transport stream). Note: I'm concerned with the video bitrate - nothing else.
ffmpeg -i cbr_test_file_input.mp4 -c:v libx264 -pix_fmt yuv420p -b:v 6000000 -preset fast -tune film -g 25 -x264-params vbv-maxrate=6000:vbv-bufsize=6000:force-cfr=1:nal-hrd=cbr -flags +ildct+ilme x264_cbr_test_output.ts
However, I'm trying to approach this from an FFmpeg C-API point of view. I'm having issues. I've knocked together some code to try do something very similar to what is being done in the FFmpeg CLI. I can generate a transport stream of what I think should be CBR, but the profile of the video bitrate is very different from what I thought was the FFmpeg cli equivalent:
The initialisation of the AVCodecContext looks something like:
av_dict_set(&pDict, "preset", "faster", 0);
av_dict_set(&pDict, "tune", "film", 0);
av_dict_set_int(&pDict, "rc-lookahead", 25, 0);
pCdcCtxOut->width = pCdcCtxIn->width;
pCdcCtxOut->height = pCdcCtxIn->height;
pCdcCtxOut->pix_fmt = AV_PIX_FMT_YUV420P;
pCdcCtxOut->gop_size = 25;
// Going for 6Mbit/s
pCdcCtxOut->bit_rate = 6000000;
//pCdcCtxOut->rc_min_rate = pCdcCtxOut->bit_rate;
pCdcCtxOut->rc_max_rate = pCdcCtxOut->bit_rate;
pCdcCtxOut->rc_buffer_size = pCdcCtxOut->bit_rate;
pCdcCtxOut->rc_initial_buffer_occupancy = static_cast<int>((pCdcCtxOut->bit_rate * 9) / 10);
std::string strParams = "vbv-maxrate="
+ std::to_string(pCdcCtxOut->bit_rate / 1000)
+ ":vbv-bufsize="
+ std::to_string(pCdcCtxOut->bit_rate / 1000)
+ ":force-cfr=1:nal-hrd=cbr";
av_dict_set(&pDict, "x264-params", strParams.c_str(), 0);
pCdcCtxOut->field_order = AV_FIELD_TT;
pCdcCtxOut->flags = (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME | AV_CODEC_FLAG_CLOSED_GOP);
// WARN: Make some assumptions here!
pCdcCtxOut->time_base = AVRational{1,25};
pCdcCtxOut->framerate = AVRational{25,1};
pCdcCtxOut->sample_aspect_ratio = AVRational{64,45};
The output graphs appear very different:
Above is the FFmpeg CLI output - video bitrate holds fairly steady.
Above is the output of my sample application - some significant dips in the video bitrate.
I've taken this a step further and created a git repo consisting of:
- Code of sample application
- Test input file (.mp4)
- Outputs (.ts file) of tests
- Graphs of output bitrates.