zoukankan      html  css  js  c++  java
  • 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 long pcr = (long long)(tm * 27000000.0);
     9     long long pcr_low = pcr % 300LL;
    10     long long pcr_high = pcr / 300LL;
    11 
    12     unsigned char pcr_val[6];
    13     pcr_val[0] = pcr_high>>25;
    14     pcr_val[1] = pcr_high>>17;
    15     pcr_val[2] = pcr_high>>9;
    16     pcr_val[3] = pcr_high>>1;
    17     pcr_val[4] = pcr_high<<7 | pcr_low>>8 | 0x7e;
    18     pcr_val[5] = pcr_low;
    19     printf("calculate pcr by timeUs!
    ");
    20     printf("    timeUs=%lld us, tm=%f s
    ", timeUs, tm);
    21     printf("    pcr=%llx, pcr_low=%#llx, pcr_high=%#llx
    ", pcr, pcr_low, pcr_high);
    22     printf("    pcr_val[0-5]: %#x, %#x, %#x, %#x, %#x, %#x
    ", pcr_val[0], pcr_val[1], pcr_val[2], pcr_val[3], pcr_val[4], pcr_val[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 long PCR_LOW = (unsigned)pcr_val[5] + (((unsigned)pcr_val[4]&0x1)<<8);
    32     long 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 long)pcr_val[0]<<25);
    33     long long PCR = PCR_HIGH * 300LL + PCR_LOW;
    34     float TMS = PCR / 27000000.0;
    35     printf("revert test by pcr_val[0-5](%#x,%#x,%#x,%#x,%#x,%#x)!
    ", pcr_val[0], pcr_val[1], pcr_val[2], pcr_val[3], pcr_val[4], pcr_val[5]);
    36     printf("    PCR_LOW=%#llx, PCR_HIGH=%#llx, PCR=%#llx, TMS=%f s
    ", PCR_LOW, PCR_HIGH, PCR, TMS);
    37 
    38     printf("---------------------------------------------------------------------------
    ");
    39     printf("calculate pts by timeUs!
    ");
    40     long long pts = timeUs * 9LL / 100LL;
    41     unsigned char pts_val[5];
    42     pts_val[0] = 0x20 | (((pts >> 30) & 7) << 1) | 1;
    43     pts_val[1] = (pts >> 22) & 0xff;
    44     pts_val[2] = (((pts >> 15) & 0x7f) << 1) | 1;
    45     pts_val[3] = (pts >> 7) & 0xff;
    46     pts_val[4] = ((pts & 0x7f) << 1) | 1;
    47     printf("    pts_val[0-4]: %#x, %#x, %#x, %#x, %#x
    ", pts_val[0], pts_val[1], pts_val[2], pts_val[3], pts_val[4]);
    48 
    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,%#x,%#x,%#x,%#x)!
    ", pts_val[0], pts_val[1], pts_val[2], pts_val[3], pts_val[4]);
    56     long long PTS = ((unsigned)pts_val[4]>>1) | ((unsigned)pts_val[3]<<7) | ((unsigned)pts_val[2]>>1)<<15 | (unsigned)pts_val[1]<<22 | ((unsigned long long)(pts_val[0]&0x0E)>>1)<<30;
    57     long long TIMEUS = PTS * 100LL / 9LL;
    58     printf("    PTS=%lld, TIMEUS=%lld us
    ", PTS, TIMEUS);
    59 
    60     long long PTS_VAL = (1LL * pts_val[0]<<32) + (1LL * pts_val[1]<<24) + (1LL * pts_val[2]<<16) + (1LL * pts_val[3]<<8) + (1LL * pts_val[4]);
    61     long long PTS1 = ((PTS_VAL>>1)&0x7f) | ((PTS_VAL>>8)&0xff)<<7 | ((PTS_VAL>>(16+1))&0x7f)<<15 | ((PTS_VAL>>24)&0xff)<<22 | ((PTS_VAL>>(32+1))&7)<<30;
    62     long long TIMEUS1 = PTS1 * 100LL / 9LL;
    63     printf("    PTS1=%lld, TIMEUS1=%lld us
    ", PTS1, TIMEUS1);
    64 
    65     return 0;
    66 }
    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, 0xFF, 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后,就会发生时间戳溢出。

  • 相关阅读:
    delphi中定义了一个过程,是无参的,可是调试中却出现‘too many actual parameters’一般是什么原因
    delphi 实现接口 Unsatisfied forward or external declaration
    安装-[Microsoft] [ODBC驱动程序管理器]找不到数据源名称,未指定默认驱动程序
    delphi中常见错误提示说明
    layui与java后台交互
    delphi中报Left side cannot be assigned to错
    Python快速排序算法
    ubuntu server更改语言为中文
    Ubuntu开启root用户ssh远程密码登录
    错误 Error: electron@13.1.8 postinstall: `node install.js` 的解决
  • 原文地址:https://www.cnblogs.com/Dreaming-in-Gottingen/p/13943202.html
Copyright © 2011-2022 走看看