在FFmpeg中计算帧编码之前的PTS

时间:2014-01-03 17:22:58

标签: libav pts

如何在FFmpeg C API编码之前计算帧的正确PTS值?

使用函数avcodec_encode_video2进行编码,然后按av_interleaved_write_frame编写。

我找到了一些公式,但没有一个公式不起作用。

他们正在doxygen example使用

frame->pts = 0;
for (;;) {
    // encode & write frame
    // ...
    frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
}

This blog说公式必须是这样的:

  

(1 / FPS)*采样率*帧数

有人只使用帧号设置pts:

frame->pts = videoCodecCtx->frame_number;

或替代方式:

int64_t now = av_gettime();
frame->pts = av_rescale_q(now, (AVRational){1, 1000000}, videoCodecCtx->time_base);

最后一个:

// 40 * 90 means 40 ms and 90 because of the 90kHz by the standard for PTS-values. 
frame->pts = encodedFrames * 40 * 90;

哪一个是正确的?我认为这个问题的答案不仅对我有帮助。

2 个答案:

答案 0 :(得分:9)

在尝试代码之前,更好地考虑PTS会更好。

你正在做的是划分3"时间集"一起。第一个是我们习惯的时间,基于每秒1000毫秒,每分钟60秒,依此类推。第二个是您正在使用的特定编解码器的编解码器时间。每个编解码器都有一种想要表示时间的特定方式,通常是1 /数字格式,这意味着每秒都有"数字"滴答数量。第三种格式与第二种格式类似,只是它是您使用容器的时基。

有些人更喜欢从实际时间开始,其他人更喜欢帧数,而不是"错误"。

从帧数开始,您需要先根据帧速率进行转换。 注意我所说的所有转化都使用av_rescale_q(...)。此转换的目的是将计数器转换为时间,因此您需要使用帧速率(通常为视频流时基)进行重新缩放。然后,您必须在编码之前将其转换为视频编解码器的time_base。

同样,实时,您的第一次转换需要从current_time - start_time缩放到您的视频编解码器时间。

任何只使用帧计数器的人可能正在使用time_base等于其帧速率的编解码器。大多数编解码器不能像这样工作,他们的黑客不可移植。例如:

frame->pts = videoCodecCtx->frame_number;  // BAD

此外,任何在av_rescale_q中使用硬编码的人都在利用他们知道他们的time_base是什么的事实,这应该避免。该代码不能移植到其他视频格式。而是使用video_st-> time_base,video_st-> codec-> time_base和output_ctx-> time_base来解决问题。

我希望从更高层次理解它会帮助你看到哪些是"正确的"这是"不良做法"。没有单一的答案,但也许现在你可以决定哪种方法最适合你。

答案 1 :(得分:3)

还有将其设置为frame->pts = av_frame_get_best_effort_timestamp(frame)的选项,但我不确定这是否也是正确的方法。

我真的希望有一个如何处理这个问题的最佳实践指南。你有没有机会找到自己的解决方案?如果您可以使用解决方案更新帖子,那就太棒了。