将VP9编码的数据复用到.webm时,FPS不正确

我正在尝试使用FFmpeg将一些video数据复用到WebM文件中。 我通过AVDictionary指定了一个AVDictionary (详见下文),但似乎time_base忽略了我指定的time_base值。 相反,它总是使用1/1000time_base ,因此FPS为1000 。 我的初始化代码如下:

 HRESULT WINAPI InitializeVideoEncoding(Encoder* encoder, LPCSTR codec, LPCSTR outputContainer, LPCSTR* options, UINT optCount) { // Fill the options Log("Loading options."); for (UINT i = 0; i options, key, value, 0) options && optCount > 0) { Log("Failed to initialize encoder options."); return E_FAIL; } // Grab the buffer size early and remove it from the dict so we don't // get complaints from FFmpeg { const char* frameBufKey = "frame_buf_size"; encoder->ioBufSize = 131072; AVDictionaryEntry* e = av_dict_get(encoder->options, frameBufKey, NULL, 0); if (e) { // Set the value and remove from the list. encoder->ioBufSize = strtol(e->value, NULL, 10); av_dict_set(&encoder->options, frameBufKey, NULL, 0); } } // Create the output context avformat_alloc_output_context2(&encoder->outputFormatContext, NULL, outputContainer, NULL); if (!encoder->outputFormatContext) { Log("Couldn't create output format context."); return E_FAIL; } encoder->outputFormat = encoder->outputFormatContext->oformat; // Create the output stream encoder->outputStream = avformat_new_stream(encoder->outputFormatContext, NULL); if (!encoder->outputStream) { Log("Couldn't create output stream."); return E_FAIL; } encoder->outputStream->id = encoder->outputFormatContext->nb_streams - 1; // Find the codec encoder->codec = avcodec_find_encoder_by_name(codec); if (!encoder->codec) { Log("Couldn't find encoder."); return E_FAIL; } // Create the encoding context encoder->encodingContext = avcodec_alloc_context3(encoder->codec); if (!encoder->encodingContext) { Log("Couldn't create encoding context."); return E_FAIL; } // Set the basics encoder->encodingContext->width = encoder->width; encoder->encodingContext->height = encoder->height; // Open the codec int result = avcodec_open2(encoder->encodingContext, encoder->codec, &encoder->options); if (result options) > 0) { // Dump the fields we didn't fill char* dictEntryBuf; av_dict_get_string(encoder->options, &dictEntryBuf, ':', ','); Log("The following provided options were unused:\n%s", dictEntryBuf); av_freep(&dictEntryBuf); } // Set some params afterwards encoder->outputStream->time_base = encoder->encodingContext->time_base; if (encoder->outputFormat->flags & AVFMT_GLOBALHEADER) encoder->encodingContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // Copy necessary information to the stream result = avcodec_parameters_from_context(encoder->outputStream->codecpar, encoder->encodingContext); if (result outputFormatContext, 0, NULL, 1); // Initialize IO callbacks encoder->ioBuf = (LPBYTE)av_malloc(encoder->ioBufSize); Log("Encoder IO buffer size: %d", encoder->ioBufSize); AVIOContext* ioContext = avio_alloc_context(encoder->ioBuf, (int)encoder->ioBufSize, 1, encoder, NULL, WriteStreamCallback, NULL); encoder->outputFormatContext->pb = ioContext; result = avformat_write_header(encoder->outputFormatContext, NULL); if (result < 0) { LogFFmpegError(result, "Couldn't write header."); return E_FAIL; } return S_OK; } 

您会注意到time_base未手动指定。 相反,我正在使用内置字典function,因此我可以控制这些参数,而无需重新编译程序。 我传入的值如下:

 const char* params[] = { "frame_buf_size", "131072", "b", "2000000", "time_base", "1:15", "pixel_format", "yuv420p", "speed", "6", "tile-columns", "4", "frame-parallel", "1", "threads", "8", "static-thresh", "0", "deadline", "realtime", "lag-in-frames", "0", "error-resilient", "1" }; 

我做了一些调查,我的输出流的time_base1/15直到avformat_write_header 。 似乎这个函数调用中的某些东西正在改变时基。

现在,我在FFmpeg邮件列表中读到WebM需要1/1000time_base ,我相信这就是WebM avformat_write_header实现重写流的time_base值的time_base 。 我可能会弄错,但帧速率与时基有关,1000 fps的帧速率对于我用来测试它的video播放器来说太大了(具体来说,是网络浏览器中的媒体扩展播放器) )。

我知道数据包的时间戳很重要,所以下面是我用来为每个数据包提供时间戳的代码:

 // somewhere I create a frame encoder->yuvFrame->pts = encoder->nextPts++; // somewhere I actually write to the muxer: av_packet_rescale_ts(packet, encoder->encodingContext->time_base, encoder->outputStream->time_base); 

简而言之,无论我指定什么time_base ,看起来time_base器都会用1/1000覆盖它。 这是FFmpeg的问题,还是我错过了一些初始化步骤?

目前还不完全清楚你在问什么,但我会尝试提供一些有用的信息。

支持的时基是您正在使用的格式和/或编解码器的属性。 如果格式只支持1/1000,那就是你必须使用的。

时间基准为1/1000并不意味着您的video必须为1000 fps。 这意味着您输入的时间戳需要以1/1000秒为单位(即毫秒)。

只需计算15fps帧的毫秒时间戳,然后再将它们输入。这个计算应该简单如下:

 timestamp = frame_number * 1000 / 15; 

libav *中可能有一个函数可以为您执行此操作。

事实certificate,我的应用程序输出的video文件实际上是有效的。 根据R ..的答案,WebM复用器需要并执行1/1000数字,而不是我应该改变的。 相反,我必须手动设置AVCodecContext的帧速率和AVCodecContext的平均帧速率。 这在WebM标题中写入了必要的信息,并允许我的video在测试播放器中播放。

 encoder->outputStream->time_base = encoder->encodingContext->time_base; // Manually set the frame rate on the codec context encoder->encodingContext->framerate = av_inv_q(encoder->encodingContext->time_base); //Manually set the frame rate of the stream encoder->outputStream->avg_frame_rate = encoder->encodingContext->framerate;