视频头文件解析--ts

数据结构:

typedef struct pmt_es_component_tag

{

   D_UINT8  stream_type;

   D_UINT8  bfree;

   D_UINT16 elementary_PID;

}pmt_component_t;

 

typedef struct pid_tag

{

   PID_STATE   state;

   PID_TYPE     type;

   D_UINT16     pid;

   D_UINT8      ch_idx;

   D_UINT8      bfree;

}ts_pid_t;

 

typedef struct

{

   D_UINT16 prog_number;

   D_UINT16 pcr_pid;

   D_UINT16 video_pid;

   D_UINT16 video_stream_type;

   D_UINT16 audio_pid;

   D_UINT16 audio_pids_cnt;

   D_UINT16 audio_pids[MAX_AUDIO_PER_CHANNEL];

   D_UINT16 audio_stream_type[MAX_AUDIO_PER_CHANNEL];

   D_UINT8  bfree;

}PMTEXT_T;

 

ts分组结构

TS分组前面提到,TS分组由188个字节构成,其结构如下:

transport_packet()

{

    sync_byte                                   8bit

    transport_error_indicator                   1 bit

    payload_unit_start_indicator                1 bit

    transport_priority                          1 bit

    PID                                         13bit

    transport_scrambling_control                2 bit

    adaptation_field_control                    2 bit

    continuity_counter                          4 bit

    if(adaptation_field_control=='10'||daptation_field_control=='11')

    {

        adaptation_field()

    }

    if(adaptation_field_control=='01' ||adaptation_field_control=='11')

    {

        for (i=0;i<N;i++)

        {

            data_byte                           8 bit

        }

    }

}

前面32bit的数据即TS分组首部,它指出了这个分组的属性。

sync_byte 同步字节,固定为0x47 ,表示后面的是一个TS分组,当然,后面包中的数据是不会出现0x47的

transport_error_indicator传输错误标志位,一般传输错误的话就不会处理这个包了.

payload_unit_start_indicator这个位功能有点复杂,字面意思是有效负载的开始标志,根据后面有效负载的内容不同功能也不同,后面用到的时候再说。

transport_priority传输优先级位,1表示高优先级,传输机制可能用到,解码好像用不着。

PID 这个比较重要,指出了这个包的有效负载数据的类型,告诉我们这个包传输的是什么内容。前面已经叙述过。

transport_scrambling_control加密标志位,表示TS分组有效负载的加密模式。TS分组首部(也就是前面这32bit)是不应被加密的,00表示未加密。

adaption_field_control翻译为“调整字段控制”,表示TS分组首部后面是否跟随有调整字段和有效负载。01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载为00的话解码器不进行处理。空分组没有调整字段

continuity_counter一个4bit的计数器,范围0-15,具有相同的PID的TS分组传输时每次加1,到15后清0。不过,有些情况下是不计数的。如下:(1)TS分组无有效负载(2)复制的TS分组和原分组这个值一样(3)后面讲到的一个标志discontinuity_indicator为1时

adaptation_field()调整字段的处理

 

data_byte有效负载的剩余部分,可能为PES分组,PSI,或一些自定义的数据。

 

PAT数据结构如下:

program_association_section()

{

        table_id                                                                                       8

       section_syntax_indicator                                          1

       '0'                                                                          1

       reserved                                                                 2

       section_length                                                        12

       transport_stream_id                                                16

       reserved                                                                 2

       version_number                                                      5

       current_next_indicator                                            1

       section_number                                                      8

       last_section_number                                                8

      for(i=0; i<N;i++)

       {

             program_number                                            16

             reserved                                                         3

             if(program_number== '0')

              {

                     network_PID                                                  13

              } else {

                     program_map_PID                                   13

             }

       }

       CRC_32                                                                32

}

table_id 固定为0x00,标志是该表是PAT

section_syntax_indicator段语法标志位,固定为1

section_length 表示这个字节后面有用的字节数,包括CRC32。假如后面的字节加上前面的字节数少于188,后面会用0XFF填充。假如这个数值比较大,则PAT会分成几部分来传输。

transport_stream_id该传输流的ID,区别于一个网络中其它多路复用的流。

version_number范围0-31,表示PAT的版本号,标注当前节目的版本.这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经变化了,程序必须重新搜索节目.

current_next_indicator表示发送的PAT是当前有效还是下一个PAT有效。

section_number分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段

last_section_number最后一个分段的号码

program_number 节目号

network_PID 网络信息表(NIT)的PID,网络信息表提供了该物理网络的一些信息,和电视台相关的。节目号为0时对应的PIDnetwork_PID

program_map_PID 节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个

CRC_32 CRC32校验码

 

PMT数据结构如下:

TS_program_map_section()

{

       table_id                                                   8

       section_syntax_indicator                           1

       '0'                                                            1

       reserved                                                   2

       section_length                                         12

       program_number                                       16

       reserved                                                   2

       version_number                                       5

       current_next_indicator                             1

       section_number                                       8

       last_section_number                                 8

       reserved                                                   3

       PCR_PID                                                13

       reserved                                                   4

       program_info_length                               12

       for (i=0;i<N; i++)

       {

              descriptor()

       }

       for(i=0;i<N1;i++)

       {

              stream_type                                     8

              reserved                                            3

              elementary_PID                               13

              reserved                                           4

              ES_info_length                                12

              for(i=0; i<N2; i++)

              {

                     descriptor()

             }

      }

      CRC_32                                                  32

 }

table_id 固定为0x02,标志是该表是PMT

section_syntax_indicatorsection_length version_number current_next_indicator 以上四个字段意思和PAT相同,可参考上面解释

section_numberlast_section_number 以上两个字段意思和PAT相同,不过值都固定为0x00,我觉得这样的原因可能是因为PMT不需要有先后顺序,因为先定义哪个节目都是无所谓。

program_number 节目号,表示该PMT对应的节目

PCR_PID PCR(节目时钟参考)所在TS分组的PID,根据PID可以去搜索相应的TS分组,解出PCR信息。

program_info_length该节目的信息长度,在此字段之后可能会有一些字节描述该节目的信息

解析步骤:

1、D_UINT32 ts_stream_verify(char *pathfile,D_UINT8 *buffer)

1)此函数功能是,首先打开文件,从文件中读取前128个包(一个包188字节大)

2)查找前面的500个字节,从找到的第一个0X47开始,如果紧接着的两个包里(每个包按188字节来算)的第一个字节都是0X47,那么就断定此文件为TS文件

 

2、D_UINT32 pmt_check_pids(char *pathfile)

1)此函数功能是,首先打开文件,从文件中读取前128个包(一个包188字节大)

2)查找前面的500个字节,从找到的第一个0X47开始,如果紧接着的两个包里(每个包按188字节来算)的第一个字节都是0X47

3)从此字节开始往后读取128个包到内存里,然后从这个内存里读取4字节作为包头packet_header进行解析。packet_header与上0XFFC00000如果为0X47000000表明这个头是ts188字节的包的包头,之所以与上0XFFC00000是因为在包头的4字节中,第一字节是同步字节0X47

4)包头右移8位再与上0X1fff,可以获得包头中的PID(包识别)

5) 包头右移4位再与上0X03,可以获得包头中的自适应区控制位adaption_field,如果adaption_field为0X01表示有有用信息无自适应区,为0X03表示有有用信息有自适应区,为0X00无定义,为0X02表示无有用信息有自适应区,如果adaption_field为0X01或者是0X03此包不在解析。跳到下一个188字节的包。

6)判断现在获得的pid是不是在pid列表里面,如果pid列表里面已经有了,那么跳出,做下一个188字节的解析

7)如果找到的是一个不存在于列表中的新的pid,把这个pid存入列表

8)此时把位置指针后移4个字节,跳过包头数据,然后判断如果此包里面有自适应区,跳过自适应区,解析后面的数据

9)跳过头数据和自适应区之后,到包数据,取得前4个字节,其中包含pat数据结构的部分参数. second_u32 = (ts_packets[pos]<<24) | (ts_packets[pos +1]<<16) | (ts_packets[pos + 2]<<8) | (ts_packets[pos + 3]);此时的pos已经是跳过包头和自适应区的指针位置

10)通过second_u32与上不同的值得到的结果可以判断这个内容里面到底是哪种类型的pid

eg:if( (second_u32& 0xFFFFFFF0) == 0x000001E0) //Video PES

if( (second_u32 & 0xFFFFFFE0) ==0x000001C0)//Audio PES

if( (second_u32 & 0xFFFFFFE0) ==0x000001A0) //Audio PES

if( (second_u32 & 0xFFFFFF00) ==0x00000100 )// Other PES

if( (second_u32 & 0xFF00F000) ==0x0000B000) //Sections PMT表

11)通过second_u32右移16位,与上0XFF可以得到table_id,如果table_id为0X20表明为pmt表

12)通过second_u32与上0XFFF可以得到section_length

13)pos指针后移一个字节进行解析1、PCR(节目时钟参考)所在TS分组的PID 2、频道号3、频道描述信息。具体参考parser_pmt_section函数。接续出来的信息有很多组。因为同一个ts流里面可能有很多组频道信息等,parser_pmt_section返回值就是解析出来的频道数

14)把解析出来的信息赋值给pmt_infor结构体列表,具体参考assign_pmt_info函数

15)如果此包解析完了之后(pos <188 && ts_packets[pos] != 0xFF),继续解析次pmt表里面的其他组信息

16)之后做pmt表信息的检查,如果此pmt表信息里面包含多个audiopid信息,那么为此频道找到一个幼小的audio pid

17)如果这个pmt表中没有发现有效的video和audio pid,那么这个pmt的pid将被从pmt信息列表中删除。

18)如果之后pmt表中的pid个数大于0.表明有频道信息,返回pids_chan_cnt频道个数。

19)如果pmt表中的pid个数小于0.表明没有pmt表,解析之前解出来的pid,比较pid的type参数,按不同类型完成pmt表

 

3、ts_get_channel_info(DG_MEDIA_FILE_INFO *file_info)

把pmt_infor结构的信息赋值给file_info。供解码器调用

你可能感兴趣的:(ts,ts,视频封装)