TS封装格式小白入门分析之抓包码流分析介绍

      首先应当介绍几个基本概念,前面提到TS Header中含有13b的PID,关于PID常见的类型取值如下:

                    PID取值                                                 PID值使用描述
                      X0000                                                节目关联表(PAT)
                      X0001                                                条件访问表(CAT)
                      X0002                                                      程序流描述表
                 X0003-X000F                                                                  保留
                      X1FFF                                                           空包

      可是我们抓取一段视频的PID值,统计一下:

       为什么还有这么多不认识的PID呢?我们看电视时可以自由的切换节目,而不是一股脑的所有节目在一起,这个处理过程机顶盒是怎么做到的呢?这是因为Packet_type不单单是上述类型,还可能包含音频aac,视频h264,PMT表等,并且这些类型占据了一个视频流中的很大部分,解码器寻找音视频是按照PAT-PMT-音视频数据这个过程寻找的(PAT中包含了PMT的PID,我们根据这个PID就可以找到PMT表的位置,同理,PMT中包含了音视频流的PID)。谨记PAT是我们分析TS的起点。

        PAT:

        节目关联表PAT的PID为0x0000,包括该TS流中的所有节目映射表即每个节目的PMT PID,传输流ID等。PAT表的结构分析如下:

typedef struct TS_PAT{
    unsigned table_id                 :8  //固定位0x00,表示该表是PAT
    unsigned section_syntax_indicator :1  //段语法标志,固定为1
    unsigned zero                     :1  //固定为0
    unsigned reserved_1               :2  //第一个保留位
    unsigned section_length           :12 //表示这个字节之后有用的字节数,包括CRC_32
    unsigned transport_stream_id      :16 //传输流的ID,区别于一个网络中其他多路复用的流
    unsigned reserved_2               :2  //第二个保留位
    unsigned version_number           :5  //表示PAT的版本号
    unsigned current_next_indicator   :1  //表示发送的PAT是当前有效还是下一个有效,为1时代表当前有效
    unsigned section_number           :8  //如果PAT分段传输,那么此值每次递增1
    unsigned last_section_number      :8  //最后一个分段的号码
    for(int i=0;i<N;i++){
        unsigned Program_number           :16 //节目号
        unsigned Reversed_3               :3  //保留位
        if(Program_number == 0)
            Network_id                    :13 //网络信息表(NIT)的PID
        else
            Program_MAP_PID               :13 //节目映射表的PID,每个节目都有一个
    }
    unsigned CRC_32                   :32 //CRC32校检码
}TS_PAT

         首先需要说明,一段视频里的PSI信息是相同的,即它们拥有相同的PAT和PMT。 对此,我们抓一段PID为PAT类型的包:

        抓包数据47 40 00 10 00 00 B0 11 00 01 C1 00 00 00 00 E0 1F 00 01 E1 00 24 AC 48 84 。 

        去掉前四个字节的TS Header(具体取值请看图的右上角,也可以自己分析)。因为其PID为0x0,所以这段包的payload是PAT表,又因为payload_uint_start_indicator为1,说明这是一帧的开始,所以TS Header后有一个字节0x00的偏移,所以我们就得到一个完整的PAT表47 40 00 10 00 00 B0 11 00 01 C1 00 00 00 00 E0 1F 00 01 E1 00 24 AC 48 84。

        00 B0 11重新分组得:00000000  1  0  11 000000010001,依次对应了值为0x00的table_id,值为1的段语法标志,以及后面2个固定值,12b的000000010001值为17,代表之后有17个字节,毫无疑问确实是这样:47 40 00 10 00 00 B0 11 00 01 C1 00 00 00 00 E0 1F 00 01 E1 00 24 AC 48 84   

         然后00 01代表当前传输流的编号,即1。C1重新分组:11 00000 1,分别代表保留位,值为0的版号,值为1的表示当前PAT有效。所以:47 40 00 10 00 00 B0 11 00 01 C1 00 00 00 00 E0 1F 00 01 E1 00 24 AC 48 84 

         然后是00 00分别代表8字节的分段传输,和最后分段号码,都为0。得:47 40 00 10 00 00 B0 11 00 01 C1 00 00 00 00 E0 1F 00 01 E1 00 24 AC 48 84 

          然后每四个字节为一个节目信息,最后剩四个字节的CRC_32。所以这个PAT表包含了两个节目信息00 00 E0 1F 00 01 E1 00,我们分析一下。首先对第一个节目重新分组:0000000000000000   111   0000000011111,因为它的节目号为0,所以这是一个NIT,此NIT的PID值为0000000011111,即31;然后对第二个节目重新分组:0000000000000001   111   0000100000000 ,所以这是一个节目1,它的PID值为256. 

          至此,我们对这段视频的PAT信息分析完毕,我们得到它包含了NIT的PID值,和一个节目映射表(就是PMT)的的PID值 。

        PMT:      

        PMT表中包含了我们想要的视音频数据信息,我们从前面的PAT表中得到了PMT表的PID值,现在,我们先对PMT的结构进行分析一下:

typedef struct TS_program_map_section{
    unsigned Table_id                    :8  //标志PSI分段的内容,对于PMT,此值为0x02
    unsigned Section_syntax_indicator    :1  //置为1
    unsigned '0'                         :1
    unsigned Reserved                    :2  //保留位
    unsigned Section_length              :12 //指明了自此到最后CRC_32的字节数
    unsigned Program_number              :16 //指出该节目的节目号,与PAT表对应
    unsigned Reserved                    :2  //保留位
    unsigned Version_number              :5  //取值0-31,代表当前PMT的版本号
    unsigned Current_next_indicator      :1  //代表当前PMT是否有效
    unsigned Section_number              :8  //给出了当前所处段的数目
    unsigned Last_section_number         :8  //给出了最后一个分段,即分段的最大数目
    unsigned Reserved                    :3  //保留位
    unsigned PCR_PID                     :13 //指示TS包的PCR值,该TS包含有PCR字段
    unsigned Reserved                    :4  //保留位
    unsigned Program_info_length         :12 //该字段描述跟随其后对节目信息描述的字节数
    

    for(int i = 0; i < N; i++)
        Descriptr()
    for(int i = 0; i < N; i++){
        unsigned Stream_type             :8  //0x00:保留, 0x01:MPEG1视频,0x02:MPEG2视频,0x03:MPEG1音频,0x04:MPEG2音频,0x05:私有字段,0x06:含有私有数据的PES包 ......
        unsigned Reserved                :3  //保留
        unsigned Elementary_PID          :13 //指示TS包的PID,这些TS包含有相同的PID
        unsigned Reserved                :4  //保留
        unsigned ES_info_length          :12 //指示跟随其后描述相关节目元素的字节数
        for(int j = 0; j < N2; j++)
            Descriptr()
    }
    unsigned CRC_32                      :32 //循环校检位
}
        

       现在我们通过PID找到了一个PMT表(我这边的工具可以直接显示):

        前五个字节不用赘述,我们直接取这个PMT表:02 B0 33 00 01 C1 00 00 F0 01 F0 0C 05 04 48 44 4D 56 88 04 0F FF FC FC 1B F0 11 F0 10 28 04 64 00 1F BF 05 08 48 44 4D 56 FF 1B 51 3F 0F F1 00 F0 00 74 06 B4 F1  

        02是PMT表格的table_id,也是起始标志;B0 33 重新分组:1  0  10  000000110011不解释,对应上表,最后的值51代表其后还有51个字节;00 01是节目可用PID;C1重新分组11   00000   1,11代表上述保留位,00000版本号,1代表当前PMT有效;然后是00 00 分别代表当前分段和分段最大数。所以就有02 B0 33 00 01 C1 00 00 F0 01 F0 0C 05 04 48 44 4D 56 88 04 0F FF FC FC 1B F0 11 F0 10 28 04 64 00 1F BF 05 08 48 44 4D 56 FF 1B 51 3F 0F F1 00 F0 00 74 06 B4 F1

        F0 01 F0 0C重新分组为:111   1000000000001    1111    000000001011。第一个是3b保留位,第二个是13b的PCR值4097,第三个是4b的保留位,第四个值是12b的对节目信息描述符大小,为12B。节目信息描述符稍后再讲,总12字节,我们直接跳过。所以:02 B0 33 00 01 C1 00 00 F0 01 F0 0C 05 04 48 44 4D 56 88 04 0F FF FC FC 1B F0 11 F0 10 28 04 64 00 1F BF 05 08 48 44 4D 56 FF 1B 51 3F 0F F1 00 F0 00 74 06 B4 F1

       再然后就是一个循环体,每层循环都代表一个流类型的相关信息,我们现在详细分析一下。1B 代表当前流的类型为MPEG4-h264视频;F0 11分组111  1000011111111,111是保留字段,1000011111111代表当前的基本流信息为4113,这就说明了包含h164视频的包的PID为0x1011(4113);F0 10重新分组:1111  000000010000,1111是保留位,000000010000是节目信息描述所占的字节数,为16个字节,所以我们直接跳过16个字节。所以:02 B0 33 00 01 C1 00 00 F0 01 F0 0C 05 04 48 44 4D 56 88 04 0F FF FC FC 1B F0 11 F0 10 28 04 64 00 1F BF 05 08 48 44 4D 56 FF 1B 51 3F 0F F1 00 F0 00 74 06 B4 F1

        因为剩余的大于4个字节,所以这还是一层循环。0F代表当前的流类型为MEPG2-AAC音频;F1 00重新分组为:111   1000100000000,111是保留字段,1000100000000代表AAC音频流的PID为0x1100(4352);F0 00重新分组为:1111 000000000000,1111是保留字段,000000000000代表之后对音频的描述字节,为0。再然后只剩4个字节的CRC_32校检码了。

        通过这段分析,我们可以判断出PMT表中包含了我们感兴趣的视音频数据,本例中的视频数据是H264编码,PID是0x1011音频是AAC编码,PID是0x1100。那么,我们就可以通过这两个PID找到我们想要的视音频包啦!

H264的PES包:

        我们通过0x1011的PID找到了一段TS包,现在我们来分析一下。

        图片不是特别清晰,我将码流贴出来分析一下:47 50 11 11 00 00 01 E0 01 8F 84 C0 0A 31 5A 1F A5 01 11 5A 1F 6A 5B 00 00 00 01 09 10 00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 10 00 00 07 D0 00 01 76 AE 02 00 0F 42 40 01 E8 4E 2C 30 30 10 00 7A 12 00 0F 42 71 61 80 78 C1 8C B0 00 00 00 01 68 EB EC B2 2C 00 00 00 01 06 00 0A A1 7B 00 00 03 02 17 B0 00 00 40 80 00 00 00 01 06 01 03 00 00 48 80 00 00 01 65 88 84 00 1A FF FE F7 D4 B7 CC B2 ED BF D0 B6 0B A8 F7 A2 9E 26 5F 43 75 25 01 9B 96 C4 ED 3A 80 00 00 03 00 00 03 00 00 03 00 00 03 01 53 6C 1E 1A 4B F6 35 B3 4F 09 00 00 03 00 00 03 01 F6 00 01 2E 00 

        总体分析一下,47 50 11 11就是老生常谈的TS Header了,它以0x47作为同步字节开头;50 11 重新分组得:0  1  0  1000000010001,错误标识符0,如果为1那么这个ts包直接摒弃,有效负载起始位1(注意,如果此包含有调整字节,那么之调整字节之前应当含有一个字节“00”),代表这是一帧的开始,一般都包含PES头部,传输优先级0,PID值:1000000010001(0x1011),结合我们找到的PMT表可以断定这是一段有效负载为H264编码的视频流;11重新分组:00  01 0001,00代表传输控制协议的保留值,01代表不含调整字段,仅含有效负载,所以头部之后的码流就是PES Header,0001代表传输顺序。所以:47 50 11 11 00 00 01 E0 01 8F 84 C0 0A 31 5A 1F A5 01 11 5A 1F 6A 5B 00 00 00 01 09 10 00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 10 00 00 07 D0 00 01 76 AE 02 00 0F 42 40 01 E8 4E 2C 30 30 10 00 7A 12 00 0F 42 71 61 80 78 C1 8C B0 00 00 00 01 68 EB EC B2 2C 00 00 00 01 06 00 0A A1 7B 00 00 03 02 17 B0 00 00 40 80 00 00 00 01 06 01 03 00 00 48 80 00 00 01 65 88 84 00 1A FF FE F7 D4 B7 CC B2 ED BF D0 B6 0B A8 F7 A2 9E 26 5F 43 75 25 01 9B 96 C4 ED 3A 80 00 00 03 00 00 03 00 00 03 00 00 03 01 53 6C 1E 1A 4B F6 35 B3 4F 09 00 00 03 00 00 03 01 F6 00 01 2E 00

        再然后的 00 00 01就是PES头部的起始标志了;E0是当前PES包的流id,代表是视频数据;01 8F是包的长度,说明之后还有0x18F(399)个字节,说明接下来的几个TS包应该是和当前包共用一个PES Header;84重新分组10  00  0  1  0  0,其中10保留位,00控制加扰方式,保留,0代表传输优先级,1代表数据对其指示,0代表不确定是否有版权,0代表copy;所以:47 50 11 11 00 00 01 E0 01 8F 84 C0 0A 31 5A 1F A5 01 11 5A 1F 6A 5B 00 00 00 01 09 10 00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 10 00 00 07 D0 00 01 76 AE 02 00 0F 42 40 01 E8 4E 2C 30 30 10 00 7A 12 00 0F 42 71 61 80 78 C1 8C B0 00 00 00 01 68 EB EC B2 2C 00 00 00 01 06 00 0A A1 7B 00 00 03 02 17 B0 00 00 40 80 00 00 00 01 06 01 03 00 00 48 80 00 00 01 65 88 84 00 1A FF FE F7 D4 B7 CC B2 ED BF D0 B6 0B A8 F7 A2 9E 26 5F 43 75 25 01 9B 96 C4 ED 3A 80 00 00 03 00 00 03 00 00 03 00 00 03 01 53 6C 1E 1A 4B F6 35 B3 4F 09 00 00 03 00 00 03 01 F6 00 01 2E 00 

         再然后是一个字节的7个flag,为C0,重新分组:11  0  0  0  0  0  0,对比句法代表此PES含有PTS(显示时间戳)和DTS(解码时间戳);再然后的0A指示了任选字段或者任意填充字段的大小,即PES Header之后数据的大小,为10个字节,结合我们之前所学,应该就是5B的PTS和5B的DTS了。所以:47 50 11 11 00 00 01 E0 01 8F 84 C0 0A 31 5A 1F A5 01 11 5A 1F 6A 5B 00 00 00 01 09 10 00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 10 00 00 07 D0 00 01 76 AE 02 00 0F 42 40 01 E8 4E 2C 30 30 10 00 7A 12 00 0F 42 71 61 80 78 C1 8C B0 00 00 00 01 68 EB EC B2 2C 00 00 00 01 06 00 0A A1 7B 00 00 03 02 17 B0 00 00 40 80 00 00 00 01 06 01 03 00 00 48 80 00 00 01 65 88 84 00 1A FF FE F7 D4 B7 CC B2 ED BF D0 B6 0B A8 F7 A2 9E 26 5F 43 75 25 01 9B 96 C4 ED 3A 80 00 00 03 00 00 03 00 00 03 00 00 03 01 53 6C 1E 1A 4B F6 35 B3 4F 09 00 00 03 00 00 03 01 F6 00 01 2E 00 

          剩下的就是我们想要的H264数据了。

ACC:

          音频数据的分析和H264包大同小异。

空包:

           47 1F FF 17 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF   除了ts头部全部用FF填充

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值