TS协议解析第二部分(PMT)

1. PMT:

PMT(Program Map Table):节目映射表,该表的PID是由PAT提供给出的。通过该表可以得到一路节目中包含的信息,例如,该路节目由哪些流构成和这些流的类型(视频,音频,数据),指定节目中各流对应的PID,以及该节目的PCR所对应的PID。

PMT表中包含的数据如下:

(1) 当前频道中包含的所有Video数据的PID
(2) 当前频道中包含的所有Audio数据的PID
(3) 和当前频道关联在一起的其他数据的PID(如数字广播,数据通讯等使用的PID)

2. 分析MPT包:

2.1 PMT包数据:


2.2 包头:

TS包头只有4个字节(47 60 81 10),除掉第一个字节0x47,剩下就3个,重新分组如下:

0    1    1  0000010000001    00    01    0000

sync_byte

同步字节

0x47:

transport_error_indicator

传输错误标识

0:

payload_unit_start_indicator

负载单元开始标识

1:

transport_priority

传输优先级

1:

pid

PID

0x81:因为在PAT中查找到program_map_PID为0x81,因此就查找到PMT。

transport_scrambling_control

传输扰乱控制

00:

adaptation_field_control

自适应区域控制

01:

00是保留值。
01负载中只有有效载荷。
10负载中只有自适应字段。
11先有自适应字段,再有有效载荷。

continuity_counter

连续计数器

0x0:

2.3 TS包:

1) 在payload_unit_start_indicator为1时,在前4个字节后会有一个调整字节。所以实际数据应该为去除第一个字节00后的数据。(47 60 81 10 00 02 B0 17 00 01 C1 00 00 E8 10 F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D

2) 02 B0 17:0000 0010 1011 0000 0001 0111
section_length:23 47 60 81 10 00 02 B0 17 00 01 C1 00 00 E8 10 F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D

3)
00 01:0000 0000 0000 0001
C1:1100 0001
00 00:0000 0000 0000 0000
E8 10:1110 1000 0001 0000
F0 00:1111 0000 0000 0000
1B E8 10 F0 00:0001 1011 1110 1000 0001 0000 1111 0000 0000 0000
03 E8 14 F0 00:0000 0011 1110 1000 0001 0100 1111 0000 0000 0000

table_id

0x02:对于PMT,该字段置为0x02

section_syntax_indicator

1:对于PMT,该字段置为1

0

0:

reserved

11:

section_length

0000 0001 0111:前两位置为00,该字段指示分段的字节数,由分段长度字段开始,包括CRC,其值不超过1021。

Program_number

0x 00 01:对应于PAT中的Program_nmuber。

reserved

11:

version_number

00000:该字段指出了TS中program_map_section的版本号。

current_next_indicator

1:当该字段置为1时,表示当前传送的program_map_section可用;当该字段置0时,表示当前传送的program_map_section不可用,下一个TS的program_map_section有效。

section_number

0x00:section_number:该字段值总是置0x00

last_section_number

0x00:该字段值总是置0x00

reserved

111:

PCR_PID

0x810:该字段指示TS包的PID值。该TS包含有PCR字段,而PCR值对应于有节目好指定的节目。

reserved

1111:

Program_info_length

0x000:

stream_type

1B:表示这个流时h264格式的,通俗点就是视频

reserved

111:

Elementary_pid

0x810:表示PID时810的TS包就是用来装h264数据的

reserved

1111:

es_info_length

0x000:

Stream_type:

0x03:

reserved:

111:

Elementary_pid

0x814

reserved

1111:

Es_info_lenth

0x000:

Crc_32

0x 03 E8 14 F0 00:


PMT

table_id

8

1个字节

section_syntax_indicator

1

 

2个字节

‘0’

1

reserved

2

section_length

12

program_number

16

2个字节

reserved

2

 

1个字节

version_number

5

current_next_indicator

1

section_number

8

1个字节

last_section_number

8

1个字节

reserved

3

 

2个字节

PCR_PID

13

reserved

4

2个字节

program_info_length

12

循环:descriptor()(0-N)

循环开始(0-N1)

stream_type

8

1个字节

reserved

3

2个字节

elementary_PID

13

reserved

4

2个字节

ES_info_length

12

循环:descriptor()(0-N2)

循环结束

CRC_32

32

4个字节


3. 实现:

3.1 PMT表格定义如下:

typedef struct TS_PMT_Stream
{
 unsigned stream_type     : 8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
 unsigned elementary_PID  : 13; //该域指示TS包的PID值。这些TS包含有相关的节目元素
 unsigned ES_info_length  : 12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
 unsigned descriptor;
}TS_PMT_Stream;


3.2 PMT表结构体:
typedef struct TS_PMT
{
    unsigned table_id                   : 8; //固定为0x02, 表示PMT表
    unsigned section_syntax_indicator    : 1; //固定为0x01
   unsigned zero                       : 1; //0x01
   unsigned reserved_1                 : 2; //0x03
   unsigned section_length : 12;//首先两位bit置为00,它指示段的byte数,由段长度域开始,包含CRC
   unsigned program_number             : 16;// 指出该节目对应于可应用的Program map PID
   unsigned reserved_2                 : 2; //0x03
   unsigned version_number             : 5; //指出TS流中Program map section的版本号
    unsigned current_next_indicator  : 1; //当该位置1时,当前传送的Program map section可用
     //当该位置0时,指示当前传送的Program map section不可用,下一个TS流的Program map section有效
   unsigned section_number            : 8; //固定为0x00
   unsigned last_section_number      : 8; //固定为0x00
   unsigned reserved_3               : 3; //0x07
   nsigned PCR_PID                   : 13; //指明TS包的PID值,该TS包含有PCR域,
      //该PCR值对应于由节目号指定的对应节目,如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF。
   unsigned reserved_4            : 4;  //预留为0x0F
   unsigned program_info_length  : 12; //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。
    
 std::vector<TS_PMT_Stream> PMT_Stream;  //每个元素包含8位, 指示特定PID的节目元素包的类型。该处PID由elementary PID指定
    unsigned reserved_5                : 3; //0x07
   unsigned reserved_6                : 4; //0x0F
   unsigned CRC_32                    : 32; 
} TS_PMT; 


3.3 解析代码:

HRESULT CTS_Stream_Parse::adjust_PMT_table ( TS_PMT * packet, unsigned char * buffer )
{ 
    packet->table_id                         = buffer[0];
    packet->section_syntax_indicator         = buffer[1] >> 7;
    packet->zero                             = buffer[1] >> 6 & 0x01; 
    packet->reserved_1                       = buffer[1] >> 4 & 0x03;
    packet->section_length                   = (buffer[1] & 0x0F) << 8 | buffer[2];    
    packet->program_number                   = buffer[3] << 8 | buffer[4];
    packet->reserved_2                       = buffer[5] >> 6;
    packet->version_number                   = buffer[5] >> 1 & 0x1F;
    packet->current_next_indicator           = (buffer[5] << 7) >> 7;
    packet->section_number                   = buffer[6];
    packet->last_section_number              = buffer[7];
    packet->reserved_3                       = buffer[8] >> 5;
    packet->PCR_PID                          = ((buffer[8] << 8) | buffer[9]) & 0x1FFF;

    PCRID = packet->PCR_PID;

    packet->reserved_4                       = buffer[10] >> 4;
    packet->program_info_length              = (buffer[10] & 0x0F) << 8 | buffer[11]; 
    // Get CRC_32
    int len = 0;
    len = packet->section_length + 3;    
    packet->CRC_32                = (buffer[len-4] & 0x000000FF) << 24
      | (buffer[len-3] & 0x000000FF) << 16
      | (buffer[len-2] & 0x000000FF) << 8
      | (buffer[len-1] & 0x000000FF); 

  int pos = 12;
  // program info descriptor
  if ( packet->program_info_length != 0 )
        pos += packet->program_info_length;    
  // Get stream type and PID    
  for ( ; pos <= (packet->section_length + 2 ) -  4; )
  {
    TS_PMT_Stream pmt_stream;
    pmt_stream.stream_type =  buffer[pos];
    packet->reserved_5  =  buffer[pos+1] >> 5;
    pmt_stream.elementary_PID = ((buffer[pos+1] << 8) | buffer[pos+2]) & 0x1FFF;
    packet->reserved_6    =  buffer[pos+3] >> 4;
    pmt_stream.ES_info_length =  (buffer[pos+3] & 0x0F) << 8 | buffer[pos+4];
  
    pmt_stream.descriptor = 0x00;
    if (pmt_stream.ES_info_length != 0)
    {
       pmt_stream.descriptor = buffer[pos + 5];
   
       for( int len = 2; len <= pmt_stream.ES_info_length; len ++ )
       {
         pmt_stream.descriptor = pmt_stream.descriptor<< 8 | buffer[pos + 4 + len];
       }
       pos += pmt_stream.ES_info_length;
    }
    pos += 5;
    packet->PMT_Stream.push_back( pmt_stream );
    TS_Stream_type.push_back( pmt_stream );
   }
   return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值