如何使用 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
上设置时间戳
我正在使用 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
上设置时间戳