欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PMT 表分析

程序员文章站 2022-03-22 23:23:04
...

PMT表结构
PMT 表分析
PMT 表实例
在下图中,我们可以看到PMT表携带的基本信息。一共有四个section,是四张PMT表的信息;其中,每个section存储在一个PMT表中,对应了一个节目的信息。 下面,我们以节目号为16398的节目为例进行分析。
PMT 表分析
下图可以看到,一共有3个单元流,每一个单元流都是组成这个节目的一个 元素(或者说是分量)。 可以看到,这个节目包含一个MPEG2的视频(stream_type=0x02)、一个MPEG2的音频(stream_type=0x04)以及一个私有类型(stream_type=0x06)的数据。
PMT 表分析
PMT 表分析
PMT 表分析

table_id 8bits 0x02:对于PMT,该字段置为0x02
section_syntax_indicator 1bits :对于PMT,该字段置为1
0 1bits 0
reserved 2bits
section_length 12bits 0000 0001 0111:前两位置为00,该字段指示分段的字节数,由分段长度字段开始,包括CRC,其值不超过1021。
Program_number 16bits 0x 00 01:对应于PAT中的Program_nmuber。
reserved 2bits
version_number 5bits 00000:该字段指出了TS中program_map_section的版本号。
current_next_indicator 1bits :当该字段置为1时,表示当前传送的program_map_section可用;当该字段置0时,表示当前传送的program_map_section不可用,下一个TS的program_map_section有效。
-section_number 8bits -0x00:section_number:该字段值总是置0x00.
last_section_number 8bits 0x00:该字段值总是置0x00
reserved 3bits
PCR_PID 13bits 0x810:该字段指示TS包的PID值。该TS包含有PCR字段,而PCR值对应于有节目好指定的节目。
reserved 4bits
Program_info_length 12bits 0x000
循环开始
stream_type 8bits 1B:表示这个流时h264格式的,通俗点就是视频
reserved 3bits
Elementary_pid 13bits 0x810:表示PID时810的TS包就是用来装h264数据的
reserved 4bits
es_info_length 12bits 0x000
循环结束
Crc_32 32bits 校验

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;

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; 

PMT 解析代码

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;
}