了解视频帧中的 PTS 和 DTS

Posted

技术标签:

【中文标题】了解视频帧中的 PTS 和 DTS【英文标题】:Understanding PTS and DTS in video frames 【发布时间】:2012-11-15 17:26:17 【问题描述】:

从 avi 转码为 mp4(x264) 时出现 fps 问题。最终问题出在 PTS 和 DTS 值中,因此在 av_interleaved_write_frame 函数之前添加了第 12-15 行:

1.  AVFormatContext* outContainer = NULL;
2.  avformat_alloc_output_context2(&outContainer, NULL, "mp4", "c:\\test.mp4";
3.  AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
4.  AVStream *outStream = avformat_new_stream(outContainer, encoder);
5.  // outStream->codec initiation
6.  // ...
7.  avformat_write_header(outContainer, NULL);

8.  // reading and decoding packet
9.  // ...
10. avcodec_encode_video2(outStream->codec, &encodedPacket, decodedFrame, &got_frame)
11. 
12. if (encodedPacket.pts != AV_NOPTS_VALUE)
13.     encodedPacket.pts =  av_rescale_q(encodedPacket.pts, outStream->codec->time_base, outStream->time_base);
14. if (encodedPacket.dts != AV_NOPTS_VALUE)
15.     encodedPacket.dts = av_rescale_q(encodedPacket.dts, outStream->codec->time_base, outStream->time_base);
16. 
17. av_interleaved_write_frame(outContainer, &encodedPacket)

看了很多帖子还是不明白:

    outStream->codec->time_base = 1/25 和 outStream->time_base = 1/12800。第一个是我设置的,但我不知道为什么以及谁设置了 12800?我注意到在第 (7) 行之前 outStream->time_base = 1/90000 并且在它更改为 1/12800 之后,为什么? 当我从 avi 转码为 avi 时,意味着将第 (2) 行更改为 avformat_alloc_output_context2(&outContainer, NULL, "avi", "c:\\test.avi"; ,因此第 (7) 行之前和之后 outStream->time_base 始终保持 1/25,而不像在 mp4 情况下那样,为什么? outStream->codecoutStream的time_base有什么区别? 计算 pts av_rescale_q 的方法是:使用 2 个 time_base,将它们的分数相乘,然后计算 pts。为什么会这样?正如我调试的那样,encodedPacket.pts 的值递增了 1,那么如果它确实有值,为什么要更改它呢? 一开始 dts 的值为 -2,每次重新缩放后仍为负数,但尽管如此,视频仍能正常播放!不应该是积极的吗?

【问题讨论】:

【参考方案1】:

    时基只是一个单位的度量。可以使用不同的单位来表示相同的时间(如果它们不是精确的倍数,则为近似值)。在某些情况下,容器格式需要特定的时基,并且将由复用器设置为该时基。在其他情况下,容器不需要时基,但它具有您可能必须覆盖的默认值。我不确定具体是 1/12800,我知道 1/600 是 mp4 规范中的一个特殊值。

    这两个时基是编解码器和容器的时间测量单位。如果使用恒定 fps,则编解码器的测量单位通常设置为每帧和下一帧之间的间隔(每帧显示的持续时间),因此帧时间是连续的整数。但是,它不必设置为 1/fps,只要 pts 时间在使用的任何单位中都是正确的。

    您所描述的只是从一种单位转换为另一种单位所需要做的事情。 (即:乘以旧单位,除以新单位)。以a/b 为单位的时间t 可以转换为c/d 单位为t*(a*d)/(b*c)

    dts 序列可以从任意值开始,dts 0 没有特殊意义。播放开始时,计算挂钟时间与开始 dts 的差值,并将所有未来的 dts 转换为 wall使用它的时钟。 dts=-10, -9, -8, ... 的视频流完全可以。连续dts之间的区别是使用什么,绝对值无关紧要。

【讨论】:

对不起,我没有看到你的答案。第二段没看懂。 “一帧的持续时间”是什么意思?如果我使用 25 fps,那么 pts 的间隔将是 40 (1/25)? @theateist:一帧的持续时间是 1 秒 / fps(将帧之间的间隔称为可能更清楚,但这也是一帧应该显示多长时间的持续时间)。所以在 25fps 时,它是 0.040 秒。如果时基设置为 1/25 并且您的流是 25fps,那么帧时间(时基单位中的点)将只是 1、2、3、... 我认为时基决定了 fps,我的意思是如果时基是 1/25 那么 fps 是 25,如果时基是 1/40 那么 fps 是 40,不是吗? @theateist:时基和 fps 是独立的,但有些相关。您可以有 fps 25 和时基(例如)1/1000。然后连续帧的时间间隔为 (1/25) / (1/1000) = 40 个时基单位。如果两者不能相互整除,则帧时间必须是近似的/四舍五入的。这就是为什么习惯选择(例如)时基 30/1001 来获得 29.97 fps 的原因。时基是时间测量的单位,习惯上选择一个简单的分数单位,它要么等于 1/fps,要么是 1/fps 的整数部分。 P.S.这也是传输流具有 1/90000 或 1/27000000 时基的原因:这些单位足够小,所有常见的 fps 几乎都可以精确表示,最常见的 fps(25、24、30)是精确的。

以上是关于了解视频帧中的 PTS 和 DTS的主要内容,如果未能解决你的问题,请参考以下文章

解决ffmpeg中的时间戳同步问题_day95

用ffmpeg c连接视频和音频时如何计算pts和dts

理解ffmpeg中的pts,dts,time_base

视频流中的DTSPTS到底是什么

音视频-帧、DTS、PTS

ffmpeg.c pts 和 dts 是啥?这个代码块在 ffmpeg.c 中做了啥?