Я использую libavcode c для кодирования некоторых mp4 (формат видео AV_CODEC_ID_MPEG4
). Приведенный ниже код работает нормально, без исключений / предупреждений, но затем выходной файл кодируется со скоростью 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? Вышеприведенный код, похоже, не имеет никакого эффекта.
Единственный способ, которым мне удалось заставить его работать, - использовать устаревший код, вместо того, чтобы выделять собственную структуру кода c и связывать ее, просто изменить тот, который идет с контекстом (фрагмент, аналогичный приведенному выше, средняя часть):
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;
Не уверен, что делать дальше, в приведенном выше коде не рекомендуется связывать код c с контейнером. .