I'm using libavcodec to encode some mp4 (video format is AV_CODEC_ID_MPEG4
).
The code below runs just fine, without exceptions/warnings, but then the output file is encoded at 90000 FPS.
// Please note averror(...) is a simple utility
// function which throws on errors...
const char *outfile = "output.mp4";
AVFormatContext *octx_ = 0;
averror(avformat_alloc_output_context2(&octx_, 0, 0, outfile));
std::unique_ptr<AVFormatContext, void(*)(AVFormatContext*)> octx(octx_, [](AVFormatContext* p){ if(p) avformat_close_input(&p); });
AVStream *strm = avformat_new_stream(octx.get(), 0);
if(!strm)
throw std::runtime_error("avformat_new_stream");
auto *penc = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
if(!penc)
throw std::runtime_error("avcodec_find_encoder");
auto *pc = avcodec_alloc_context3(penc);
std::unique_ptr<AVCodecContext, void(*)(AVCodecContext*)> ocodec(pc, [](AVCodecContext* p){ if(p) avcodec_free_context(&p); });
// setup additinal info about codec
ocodec->pix_fmt = AV_PIX_FMT_YUV420P;
//ocodec->bit_rate = 400000;
ocodec->width = 3440;
ocodec->height = 1440;
ocodec->time_base = (AVRational){1, 60}; // this doesn't work...
ocodec->framerate = (AVRational){60, 1}; // nor this...
// fix about global headers
if(octx->oformat->flags & AVFMT_GLOBALHEADER)
octx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// bind context codec
averror(avcodec_open2(ocodec.get(), penc, 0));
// fill in the context parameters
averror(avcodec_parameters_from_context(strm->codecpar, ocodec.get()));
How can I set to 60 FPS? The above code doesn't seem to have any effect.
The only way I managed to make it work, is by using deprecated code, instead of allocating my own codec structure and associating it, just modify the one coming with the context (similar snippet as above, middle section):
if(!penc)
throw std::runtime_error("avcodec_find_encoder");
//auto *pc = avcodec_alloc_context3(penc);
//std::unique_ptr<AVCodecContext, void(*)(AVCodecContext*)> ocodec(pc, [](AVCodecContext* p){ if(p) {avcodec_free_context(&p);} });
// setup additinal info about codec
AVCodecContext *ocodec = strm->codec; // this is deprecated!
ocodec->codec_id = AV_CODEC_ID_MPEG4;
ocodec->codec_type = AVMEDIA_TYPE_VIDEO;
ocodec->pix_fmt = AV_PIX_FMT_YUV420P;
ocodec->bit_rate = 400000;
ocodec->width = 3440;
ocodec->height = 1440;
ocodec->gop_size = 3;
ocodec->max_b_frames = 2;
ocodec->time_base.num = 1;
ocodec->time_base.den = 60;
Not sure what to do next, the above code has a deprecated way to associating a codec with container...
You need to set the timestamp on the AVPacket
before you call av_write_frame()
or av_interleaved_write_frame()