如何在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;
哪一个是正确的?我认为这个问题的答案不仅对我有帮助。
答案 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)
的选项,但我不确定这是否也是正确的方法。
我真的希望有一个如何处理这个问题的最佳实践指南。你有没有机会找到自己的解决方案?如果您可以使用解决方案更新帖子,那就太棒了。