如何使用 libavcodec 设置输出帧时间?

How do I set output frame time using libavcodec?

我正在使用 libavcodec 对一些 mp4 进行编码(视频格式为 AV_CODEC_ID_MPEG4)。 下面的代码运行得很好,没有 exceptions/warnings,但输出文件以 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()));

如何设置为 60 FPS? 上面的代码好像没有什么效果。

我设法让它工作的唯一方法是使用已弃用的代码,而不是分配我自己的编解码器结构并关联它,只需修改上下文中的那个(与上面的代码段类似,中间部分):

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;

不确定下一步该怎么做,上面的代码有一种将编解码器与容器相关联的方法已弃用...

您需要在调用 av_write_frame()av_interleaved_write_frame()

之前在 AVPacket 上设置时间戳