Как установить время вывода кадра с помощью libavcode c? - PullRequest
0 голосов
/ 29 апреля 2020

Я использую 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 с контейнером. .

1 Ответ

1 голос
/ 29 апреля 2020

Вам нужно установить временную метку на AVPacket, прежде чем звонить av_write_frame() или av_interleaved_write_frame()

...