ts流中的pcr与pts计算与逆运算

  mpeg2ts文件格式中有pcr和pts的概念,其代码含义如下:

  PCR(Program Clock Reference)——指示系统时钟本身的瞬时值的时间标签称为节目参考时钟标签(PCR)。

  PTS(Presentation Time Stamp)——指示音视频显示时间的时间戳称为显示时间戳(PTS)。

  二者的更具体含义可以网上查找资料,本博文的重点不再于此。本博文主题为:利用编码帧bitstream所携带的时间戳,如何换算出ts文件中的pcr和pts值。

1. 一段典型的音视频ts数据包:

  AAC: 47 41 E1 3F 07 10 00 F9 F2 B6 FE B3 00 00 01 C0 01 6A 84 80 05 21 07 CF CA DB 。。。(bitstream)。。。

  AVC: 47 41 E2 3D 07 10 00 F9 F2 B6 FE B3 00 00 01 E0 98 65 84 80 05 21 07 CF CA DB 。。。(bitstream)。。。

  红色六个字节为pcr值(188Bytes的TS数据包的第7个字节),粉红色五个字节为pts值(头的尾部,后面直接跟编码数据)。

2. pcr及pts算法介绍(pcr_val(42b)和pts[32..30..0](33b))

  两段典型的示例如下:

  时间戳为00:06:04.013(timsUs=364013000)的一帧数据,其pcr的值:00 F9 F2 A9 7E 0D ,其pts[32...0]值为:21 07 CF CA A5
  时间戳为00:06:04.034(timsUs=364034000)的一帧数据,其pcr的值:00 F9 F6 59 FE CF ,其pts[32...0]值为:21 07 CF D9 69

  其中,编码模块送给封装模块(Android中为MPEG2TSWriter)的编码帧所携带的时间戳并不是“00:06:04.013”形式,而是一个long long型的整数,单位为微秒,例如364013000(代表364.013秒),换算成人容易识别的格式(hh:mm:ss)为:00:06:04.013。

  注意,ts在封装时,标准规定了pcr值和pts各个位如何排布(参考下面的pcr_val和pts_val数组,即符合spec规定)。

3. timeUs和pcr之间转换

  正向运算:timeUs -> pcr (用于封装)

    float tmp = timeUs / 1000000 + (timeUs % 1000000) / 1000 * 0.001; //timeUs以us为单位,tmp以s为单位,即换算成xy.z格式(小数点放在倒数第六个字节前),xy为秒值,z为毫秒值
    long long pcr = (long long)(tmp * 27000000.0);
    long long pcr_low = pcr % 300LL;  //有效位数为9位,即1+8

    long long pcr_high = pcr / 300LL;  //有效位数为33位,即8+8+8+8+1

    unsigned char pcr_val[6];   // 待写到ts文件中pcr位置的6个字节值

    pcr_val[0] = pcr_high>>25;
    pcr_val[1] = pcr_high>>17;
    pcr_val[2] = pcr_high>>9;
    pcr_val[3] = pcr_high>>1;
    pcr_val[4] = pcr_high<<7 | pcr_low>>8 | 0x7e;
    pcr_val[5] = pcr_low;

  逆向运算:pcr -> timeUs (用于解封装时获取时间戳,由已知ts文件算出音视频帧的时间戳)(下式可能发生溢出,demo中有详细的避免溢出处理)

    long long PCR_LOW = pcr_val[5] + ((pcr_val[4]&0x1)<<8);
    long long PCR_HIGH = (pcr_val[4]>>7) + (pcr_val[3]<<1) + (pcr_val[2]<<9) + (pcr_val[1]<<17) + (pcr_val[0]<<25);
    long long PCR = PCR_HIGH * 300 + PCR_LOW;
    float TMS = PCR / 27000000.0;

4. timeUs和pts之间的转换

  正向运算:timeUs -> pts

    long long pts = timeUs * 9LL / 100LL;
    unsigned char pts_val[5];
    pts_val[0] = 0x20 | (((pts >> 30) & 7) << 1) | 1;     // 3bits
    pts_val[1] = (pts >> 22) & 0xff;         // 8bits
    pts_val[2] = (((pts >> 15) & 0x7f) << 1) | 1;      // 7bits
    pts_val[3] = (pts >> 7) & 0xff;           // 8bits
    pts_val[4] = ((pts & 0x7f) << 1) | 1;        // 7bits

  逆向运算:pts -> timeUs

    long long PTS = (pts_val[4]>>1) | (pts_val[3]<<7) | (pts_val[2]>>1)<<15 | pts_val[1]<<22 | (pts_val[0]>>1)<<30;
    long long TIMEUS = PTS * 100LL / 9LL;

5. 完整demo演示

 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5     long long timeUs = 364034000;
 6 
 7     float tm = timeUs / 1000000 + (timeUs % 1000000) / 1000 * 0.001 8     long pcr = (long)(tm * 27000000.0);
 9     long pcr_low = pcr % 300LL;
10     long pcr_high = pcr /11 
12     unsigned char pcr_val[6];
13     pcr_val[0] = pcr_high>>2514     pcr_val[1] = pcr_high>>1715     pcr_val[2] = pcr_high>>916     pcr_val[3] = pcr_high>>117     pcr_val[4] = pcr_high<<7 | pcr_low>>8 | 0x7e18     pcr_val[5] = pcr_low;
19     printf("calculate pcr by timeUs!\n"20     printf(    timeUs=%lld us,tm=%f s\n,timeUs,tm);
21     printf(    pcr=%llx,pcr_low=%#llx,pcr_high=%#llx\n22     printf(    pcr_val[0-5]: %#x,%#x,%#x\n",pcr_val[0],1)">1],1)">2],1)">3],1)">4],1)">5]);
23 
24     /* test max pcr_val */
25     //pcr_val[0] = 0xff;
26     pcr_val[1] = 0xff;
27     pcr_val[2] = 0xff;
28     pcr_val[3] = 0xff;
29     pcr_val[4] = 0xff;
30     pcr_val[5] = 0x2b;
31     long PCR_LOW = (unsigned)pcr_val[5] + (((unsigned)pcr_val[4]&0x1)<<832     long PCR_HIGH = ((unsigned)pcr_val[4]>>7) + ((unsigned)pcr_val[3]<<1) + ((unsigned)pcr_val[2]<<9) + ((unsigned)pcr_val[1]<<17) + ((unsigned long)pcr_val[0]<<33     long PCR = PCR_HIGH * 300LL + PCR_LOW;
34     float TMS = PCR / 35     printf(revert test by pcr_val[0-5](%#x,%#x)!\n36     printf(    PCR_LOW=%#llx,PCR_HIGH=%#llx,PCR=%#llx,TMS=%f s\n37 
38     printf(---------------------------------------------------------------------------\n39     printf(calculate pts by timeUs!\n40     long pts = timeUs * 9LL / 100LL;
41     unsigned char pts_val[42     pts_val[0] = 0x20 | (((pts >> 30) & 7) << 1) | 43     pts_val[1] = (pts >> 22) & 0xff44     pts_val[2] = (((pts >> 15) & 0x7f) << 45     pts_val[3] = (pts >> 7) & 46     pts_val[4] = ((pts & 47     printf(    pts_val[0-4]: %#x,pts_val[448 
49      test max pts_val 50     pts_val[0] = 0x2f;
51     pts_val[1] = 0xff;
52     pts_val[2] = 0xff;
53     pts_val[3] = 0xff;
54     pts_val[4] = 0xff;
55     printf(revert test by pts_val[0-4](%#x,1)">56     long PTS = ((unsigned)pts_val[1) | ((unsigned)pts_val[7) | ((unsigned)pts_val[2]>>1)<<15 | (unsigned)pts_val[22 | ((unsigned long)(pts_val[0]&0x0E)>>3057     long TIMEUS = PTS * 100LL / 9LL;
58     printf(    PTS=%lld,TIMEUS=%lld us\n59 
60     long PTS_VAL = (1LL * pts_val[32) + (1LL * pts_val[24) + (1LL * pts_val[16) + (1LL * pts_val[8) + (1LL * pts_val[61     long PTS1 = ((PTS_VAL>>1)&0x7f) | ((PTS_VAL>>8)&0xff)<<7 | ((PTS_VAL>>(16+1))&0x7f)<<15 | ((PTS_VAL>>24)&22 | ((PTS_VAL>>(32+7)<<62     long TIMEUS1 = PTS1 * 100LL /63     printf(    PTS1=%lld,TIMEUS1=%lld us\n64 
65     return 066 }
View Code

  

 6. 延伸

  6.1 ts文件中音视频帧的最大时间戳是多少?

  当最大时,即意味着文件中pcr_val[0-5]或pts_val[0-4]处的二进制位值都为1。

  方案1.从pcr_val[0-5]侧来计算

    由于pcr_low是被300求余的,则其最大值为299=0x12B,那么pcr_va[0-5]数组的值分别为:0xFF, 0xFF,2B

    由此,可以算得TMS最大值为95443.718750 s = 26.5h

    利用上面demo,逆向计算结果如下:

    

  方案2.从pts_val[0-4]来计算

    由于pts为33bits宽(3+8+7+8+7),则其最大值为:0x1 FF FF FF FF(对应文件中pcr_val[]为:0x2F FF FF FF FF),算得timeUs=pts_max * 100L / 9LL =  95443717666 us = 95443 s = 26.5h

    利用上面demo,逆向计算结果如下:

     

  结论:两个层面,计算结果都一致,即最大的timeUs=95443000000。这意味着,timeUs从0开始,到1天再过2.5h后,就会发生时间戳溢出。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


一年前写了一个demo,用于生成几种标准的波形,如正弦波、方波、三角波。之前写的只有这几个功能:波形/通道/时长/频率的控制选择,这几天抽了些时间又加了增益控制功能。为了避免东西丢失或意外删除,特上传
wav文件格式作为一种常用的多媒体音频文件格式,其由MS在1991年8月在Windows 3.1上推出,文件扩展名为WAV,是WaveFom的简写。通常存储未压缩的pcm数据,也可存储压缩的pcm数据
mpeg2ts文件格式中有pcr和pts的概念,其代码含义如下: PCR(Program Clock Reference)——指示系统时钟本身的瞬时值的时间标签称为节目参考时钟标签(PCR)。 PTS
我的月经贴博客该更新了!!!已经有许多博文需要补了! 去年开始的jpeg解码项目,中间停止更新了大半年时间,上个月想起这事还没完工,就又做了更多兼容性和性能上的改进,目前终于接近尾声了。有需要参考的可
花了两天时间做了个h264裸流nal类型和frame类型检测的工具,已上传至github,有需要的自行下载(其中包含构建出来的可执行文件exe)。 1.NAL类型检测 nal类型检测非常容易,对照下表
随着工作业务的开展,对视频编解码的理解更加深入了一些,记录一些心得体会,以便后面回味。 某天突然有个好的想法略过心头,可以形象的向别人介绍视频编码和解码。 1.编解码像一场考试,编码就像做主观题,解码
承接昨天写的《JPEG软解码实现介绍》,今天介绍其使用方法和一些细节说明。 1.仓库下已经包含了几个jpeg文件,以方便直接校验。 2.使用命令分为两种模式。 一种是直接解码为yuv文件,另外一种是解
x264编码器,提供了两个demo来验证编码功能:一个是大而全的x264.c,另外一个是简洁版的example.c。 其中,前者demo,可以配置很多编码参数,但太冗长繁杂,对初学者不太友好。 后者d
本博文为概览性介绍。后面有空了再分几篇博文分别介绍所用到的技术细节。 1.编解码目标 编码和解码是个逆过程。jpeg编码的目的在于图形去冗余,进行数据压缩,解码的目的在于还原图像,使能够进行预览。 2
今天使用公司开发手机,调研一下当下很火的抖音客户端,其使用的视频编码类型。 在调研前,有个初步判断: 1.从抖音服务器推送到客户端的视频流要么是avc码流,要么是hevc码流(具体要视平台解码硬件支持
最近对抖音有点上瘾,经常看到这样的视频列表: 由于抖音平台的限制,用户最多只能上传60s的视频,因此分段为3个视频。而在视频列表的缩略图模式下,三个视频的封面恰好组合成一张图像。这种方式比较符合审美标
自己在学习h264的路上,欢迎讨论交流。 前段时间研究JM出品的h264编码器,代码实在看不下去,因此换了个角度来研究诸多算法——逆向方式(解码),本系列文章记录一些遇到的东西和思考。 1. JM介绍
h264裸码流,根据nalu_header可以知道类型,例如该帧是I帧,P帧/B帧。 例如,常见的0x65代表I帧,0x41代表非关键帧,即P帧或B帧,但是只根据nalu_header是无法区分P帧和