一、什么是PTS、DTS
1.PTS:即显示时间戳,用来告诉播放器在什么时候显示这一帧数据
2.DTS:即解码时间戳,用来告诉播放器在什么时间来解码这一帧的数据
3.GOP:MPEG使用的一种视频压缩技术
总的来说PTS和DTS用于指导播放器端的行为
二,了解视频采集到编码推流
在视频采集的时候是录制一帧就编码一帧发送一帧,在编码的时候会生成PTS,在通常情况下,编码器在编码一个I帧,然后向前跳过几个帧,用编码I帧作为基准对一个未来帧P帧进行编码,然后跳回到I帧之后的下一个帧。编码的I帧和P帧之间的帧被编码为B帧。之后编码器会再次跳过几个帧,使用第一个P帧作为一个基准帧编码另外一个P帧,然后再次跳回,用B帧填充显示序列的空隙。这个过程不断继续,每12到15个p帧和B帧内插入一个新的I帧。P帧由前一个I帧或P帧图像来预测,而B帧由前后的两个P帧或一个I帧和一个P帧来预测。如下图所示:
假设采集到的帧是这样的:
I B B P B B P
那么它的PTS对应的是1234567
编码顺序是 1423756
推流顺序也是按照编码顺序去推的即
I P B B P B B
那么接受端的视频流也就是
I P B B P B B
这时候去解码,也是按照收到的视频流一帧一帧去解得了,接收一帧解码一帧,所以解码的顺序的这样的
I P B B P B B
DTS:1234567
PTS:1423756
可看到解码出来对应PTS不是顺序的,为了正确显示视频流,这时候我们必须按照PTS调整解码后的帧,即
I B B P B B P
DTS:1342675
PTS: 1234567
其实就是把PTS按照顺序递增的方式排列下
总而言之,在音视频中,PTS通常是按照递增顺序排列的,以保证正确的时间顺序和播放同步。
三、应用实例
在没有B帧的情况下,DTS和 PTS 的输出顺序是一样的,一旦存在 B 帧,则顺序不一样。 这里,我们只需要关心 PTS ,即显示时间戳。通过 MediaCodec.BufferInfo 的 presentationTimeUs 可以拿到当前的 pts 时间戳,单位是微妙,它是相对于0开始播放的时间,所以,我们可以使用系统时间差来模仿两帧的时间差,这样当解码过来的 pts 比这个时间差快,则延时以下再输出到 Surface ,如果不是,则直接显示到 Surface 中
// 用于对准视频的时间戳
private long startMs = -1;
if (outputId >= 0){
if (mStartMs == -1) {
mStartMs = System.currentTimeMillis();
}
//矫正pts
sleepRender(info, startMs);
//释放buffer,并渲染到 Surface 中
mediaCodec.releaseOutputBuffer(outputId, true);
}
#sleepRender
/**
* 数据的时间戳对齐
**/
private void sleepRender(MediaCodec.BufferInfo info, long startMs) {
/**
* 注意这里是以 0 为出事目标的,info.presenttationTimes 的单位为微秒
* 这里用系统时间来模拟两帧的时间差
*/
long ptsTimes = info.presentationTimeUs / 1000;
long systemTimes = System.currentTimeMillis() - startMs;
long timeDifference = ptsTimes - systemTimes;
// 如果当前帧比系统时间差快了,则延时以下
if (timeDifference > 0) {
try {
Thread.sleep(timeDifference);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}文章来源:https://www.toymoban.com/news/detail-792331.html
使用上面的代码示例,可以达到让播放器以正常速度解码视频,不会出现倍速播放的效果文章来源地址https://www.toymoban.com/news/detail-792331.html
到了这里,关于音视频中的DTS和PTS区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!