FFMPEG:av_rescale_q - time_base 差异

Posted

技术标签:

【中文标题】FFMPEG:av_rescale_q - time_base 差异【英文标题】:FFMPEG:av_rescale_q - time_base difference 【发布时间】:2018-03-12 10:39:39 【问题描述】:

我想一劳永逸地了解时基计算和重新缩放在 FFMPEG 中的工作原理。 在回答这个问题之前,我做了一些研究,发现了许多有争议的答案,这使得它更加混乱。 所以基于官方FFMPEGexamples一个必须

将输出数据包时间戳值从编解码器重新缩放到流时基

类似这样的:

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);

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

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

我不明白为什么。

我想请人解释一下。接下来,在写框架之前,我会计算 数据包的 PTS。就我而言,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 stream。在这种情况下,我这样计算持续时间:

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

WEBM 需要乘以 1000,因为时间戳在该容器中以毫秒为单位显示。这很有效。那么为什么在 MP4 流编码的情况下,time_base 存在差异,必须重新调整?

【问题讨论】:

【参考方案1】:

ffmpeg 的这种行为也让我感到困惑。用户在这里进行了一些讨论 - http://ffmpeg.org/pipermail/libav-user/2018-January/010843.html。但解决方案是只处理 15360 时基,而不是对其施加控制。

根据该论坛主题中的发帖人指出的来源(https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/movenc.c,搜索“*= 2”),据我所知,它看起来不容易避免。看来您的选择是让 time_base 改变,或者选择 >= 10000 的东西,然后它就不会改变。

【讨论】:

以上是关于FFMPEG:av_rescale_q - time_base 差异的主要内容,如果未能解决你的问题,请参考以下文章

四个通用定时器(TIM2 TIM3 TIM4 TIM5)的四通道调用

STM32G0学习手册——使用定时器中断(HAL库)

如何在 C 中使用 nanosleep()?啥是`tim.tv_sec`和`tim.tv_nsec`?

stm32定时器的问题

高级定时器TIM1&TIM8

STM32 高速定时器配置为PWM使用细节