了解视频帧中的PTS和DTS

29

在从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)

阅读了很多帖子后,我仍然不理解:

  1. outStream->codec->time_base = 1/25 而 outStream->time_base = 1/12800。第一个是我设置的,但我无法弄清楚为什么以及谁设置了12800?我注意到在第七行之前,outStream->time_base = 1/90000,在它之后它改变为1/12800,为什么? 当我从avi转码到avi时,也就是将第2行更改为avformat_alloc_output_context2(&outContainer, NULL, "avi", "c:\\test.avi"; ,因此在第七行之前和之后,outStream->time_base 始终保持为1/25,而不像mp4的情况,为什么?
  2. outStream->codecoutStream 的time_base有什么区别?
  3. 为了计算pts,av_rescale_q会:取两个time_base,将它们的分数交叉相乘,然后计算pts。为什么要这样做?当我进行调试时,encodedPacket.pts 的值递增1,所以如果它有值,为什么要更改它?
  4. 在开始时,dts值为-2,每次重新缩放后仍然有负数,但尽管如此视频播放正常!它不应该是正数吗?
1个回答

45
  1. time_base是一个计量单位。不同的单位可以用来表示相同的时间(如果它们不是精确的倍数,那么可能会有近似)。在某些情况下,容器格式需要特定的时间基,而混合器将设置为该时间基。在其他情况下,容器不需要时间基,但它有一个默认值,您可能需要覆盖。我不确定1/12800具体是什么意思,但我知道1/600是mp4规范中的一个特殊值。

  2. 两个时间基是编解码器和容器的时间计量单位。如果使用恒定帧速率,则编解码器的时间计量单位通常设置为每个帧之间的时间间隔(每个帧显示的持续时间),以便帧时间是连续的整数。但是,它不必被设置为1 / fps,只要pts时间在使用的任何单位中正确即可。

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

  4. dts序列可以从任何值开始,dts 0没有特殊意义。在播放开始时,计算出墙上时钟时间和起始dts之间的差异,并使用它将所有未来的dts转换为墙上时钟。具有dts=-10、-9、-8等的视频流是完全可以的。使用连续的dts之间的差异,绝对值并不重要。


抱歉,我没有看到你的回答。我不理解第二段是什么意思。"duration of one frame" 是什么意思?如果我使用 25 fps,那么 pts 将在 40 的间隔(1/25)内吗? - theateist
4
时间基准和 fps 是独立但有些相关的。例如,你可以有 fps 25 和时间基准为 1/1000。此时连续的帧将会相隔 (1/25) / (1/1000) = 40 个时间基准单位。如果两者不是互相整除的,则帧时间必须是近似/四舍五入的。这就是为什么惯常选择时间基准为 30/1001 用于 29.97 fps 的原因。时间基准是时间测量的单位,通常选择一个简单分数单位,它等于或是 fps 的倒数的整数分数。 - Alex I
4
这也是运输流使用时间基准为1/90000或1/27000000的原因:这些单位足够小,以至于所有常见的帧率都可以几乎精确地表示,并且最常见的帧率(25、24、30)都是精确的。 - Alex I
我有一个视频,其PTS开始于0,然后在之后以30 FPS的速率达到900ms。这个想法是第一帧被呈现出来,然后停留900毫秒(它是电影预告片的介绍片段,所以屏幕静止了很长时间)。因此你不能依赖于1/FPS。 - ajs410
@ajs410:当然,你是正确的,1/FPS只在假设FPS不变的情况下成立。我会在回答中添加澄清说明。你可能会发现,并非所有播放器都能处理你所描述的视频;特别地,很多机顶盒都会出现问题。 - Alex I
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接