FFMPEG:av_rescale_q - time_base difference

FFMPEG:av_rescale_q - time_base difference

本文关键字:time base difference rescale av FFMPEG      更新时间:2023-10-16

我想一劳永逸地知道,时间碱核心和重新缩放在ffmpeg中的工作方式。在解决这个问题之前,我进行了一些研究,发现了许多有争议的答案,这使它更加令人困惑。因此,根据官方的ffmpeg示例,必须

Rescale输出数据包时间戳值

与这样的东西:

pkt->pts = av_rescale_q_rnd(pkt->pts, *time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt->dts = av_rescale_q_rnd(pkt->dts, *time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt->duration = av_rescale_q(pkt->duration, *time_base, st->time_base);

但是,在这个问题中,一个人问我类似的问题,他给出了更多的例子,每个人都以不同的方式做。与答案相反,答案说所有这些方法都很好,对我而言,只有以下方法有效:

frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);

在我的应用程序中,我在ffmpeg api外生成60 fps的视频数据包(H264),然后将它们写入MP4容器中。

我明确设置:

video_st->time_base = {1,60};
video_st->r_frame_rate = {60,1};
video_st->codec->time_base = {1 ,60};

我看到的第一个奇怪的事情发生在我为输出格式编写标题上下文之后:

AVDictionary *opts = nullptr;
int ret = avformat_write_header(mOutputFormatContext, &opts);
av_dict_free(&opts);

之后,video_st->time_base填充了:

num = 1;
den = 15360

我不明白为什么。

我希望有人请让我exaplain that.next,在写作框架之前,我计算数据包的PT。在我的情况下,pts = dts,因为我根本不使用b框架。

我必须这样做:

 const int64_t duration = av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
 totalPTS += duration; //totalPTS is global variable
 packet->pts = totalPTS ;
 packet->dts = totalPTS ;
 av_write_frame(mOutputFormatContext, mpacket);

我不明白,为什么编解码器和流具有不同的time_base值,即使我明确将它们设置为相同。而且因为我在所有示例中看到av_rescale_q总是用于计算持续时间,所以我真的希望有人解释这一点。

另外,作为比较,为了实验,我决定尝试为WebM容器编写流。因此,我根本不使用Libav输出流。我只是抓住我用来编码MP4的相同数据包并将其手动写入EBML流。在这种情况下,我计算这样的持续时间:

 const int64_t duration =
 ( video_st->codec->time_base.num / video_st->codec->time_base.den) * 1000;

乘以1000的乘法是WebM所需的,因为该容器中以毫秒为单位显示了时间戳记。那么,为什么在编码MP4流的情况下,必须重新缩放的时间_base有差异?

ffmpeg的这种行为也使我感到困惑。此处用户对此进行了一些讨论-http://ffmpeg.org/pipermail/libav-user/2018-january/010843.html。但是,那里的决议只是处理15360 Time_base而不是对其施加控制。

从该论坛主题中的海报指出的来源(https://github.com/ffmpeg/ffmpeg/ffmpeg/blob/master/master/libavformat/movenc.c.c.c.据我所知,看起来很容易避免。看来您的选择是让time_base更改或选择某些东西= 10000,然后不会更改。