当前位置: 首页 > news >正文

音视频中的DTS和PTS区别

一、什么是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();
            }

        }
    }

使用上面的代码示例,可以达到让播放器以正常速度解码视频,不会出现倍速播放的效果

相关文章:

  • 【数据库和表的管理】
  • 人大金仓 KingBase 表添加自增主键
  • Hadoop分布式文件系统(三)
  • Java复习
  • 学习笔记:在华为昇腾NPU上进行深度学习项目【未完待续】
  • 【Linux】各目录说明
  • Microsoft Remote Desktop for Mac 中文正式版下载 微软远程连接软件
  • 【linux驱动开发】在linux内核中注册一个杂项设备与字符设备以及内核传参的详细教程
  • 阿里云高性能云服务器_云主机_云服务器详解
  • 初识 Elasticsearch 应用知识,一文读懂 Elasticsearch 知识文集(4)
  • 59道SpringCloud面试题详解含答案(值得珍藏)
  • 多线程——定时器
  • mac 使用brew卸载node
  • Oracle AWR报告的生成和解读
  • 【全】OpenSSL创建生成CA证书、服务器、客户端证书及密钥说明
  • [译]前端离线指南(上)
  • 2019.2.20 c++ 知识梳理
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • mysql 数据库四种事务隔离级别
  • Mysql数据库的条件查询语句
  • python_bomb----数据类型总结
  • Spring核心 Bean的高级装配
  • Vue.js 移动端适配之 vw 解决方案
  • Vue2.0 实现互斥
  • Vue实战(四)登录/注册页的实现
  • windows下如何用phpstorm同步测试服务器
  • 后端_MYSQL
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 微信开源mars源码分析1—上层samples分析
  • 移动端唤起键盘时取消position:fixed定位
  • 【干货分享】dos命令大全
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 数据库巡检项
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • # C++之functional库用法整理
  • #pragma pack(1)
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • $.ajax()参数及用法
  • $.proxy和$.extend
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (三分钟)速览传统边缘检测算子
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .Net IE10 _doPostBack 未定义
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET 中 GetProcess 相关方法的性能
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • @Conditional注解详解
  • @Valid和@NotNull字段校验使用
  • @软考考生,这份软考高分攻略你须知道
  • [ABC294Ex] K-Coloring
  • [Android]使用Git将项目提交到GitHub
  • [Android]一个简单使用Handler做Timer的例子