數字電視節目碼流中的PMT表分析

        PMT(Program Map Table):節目映射表,該表的PID是由PAT提供給出的。通過該表可以得到一路節目中包含的信息,例如,該路節目由哪些流構成和這些流的類型(視頻,音頻,數據),指定節目中各流對應的PID,以及該節目的PCR所對應的PID。

PMT表中包含的數據如下:

        (1) 當前頻道中包含的所有Video數據的PID
        (2) 當前頻道中包含的所有Audio數據的PID
        (3) 和當前頻道關聯在一起的其他數據的PID(如數字廣播,數據通訊等使用的PID)

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; 

解析代碼:

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

下面分析一段TS流的一個pachet:

包頭:47 41 00 10

數據: 00 02 b0 29 00 01 c1 00 00 f001 f0 0c 05 04 48 44 4d 56 88 04 0f ff fc fc 1b f0 11 f0 06 28 04 42 c028 bf 90 f2 00 f0 00 f8 d6 bd 6b

先分析包頭:

第一個的包頭爲47 40 00 10,比較可知只是PID不同

它的PID爲0x100,即爲256

所以第二個包的數據表示的是PMT

再分析具體數據:

同理第一個字節00是調整字節

02 b0 29 00 01 c1 00 00 f001 f0 0c 05 04 48 44 4d 56 88 04 0f ff fc fc 1b f0 11 f0 06 28 04 42 c028 bf 90 f2 00 f0 00 f8 d6 bd 6b

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個字節

02 b0 29 00 01 c1 00 00 f0 01 f0 0c 05 04 48 44 4d 5688 04 0f ff fc fc 1b f0 11 f0 06 28 04 42 c0 28 bf 90 f200 f0 00 f8 d6 bd 6b

table_id爲02,對於PMT必須爲0x02

b0 29二進制爲1011 0000 0010 1001

section_syntax_indicator爲1,對於PMT必須爲1

section_length爲0x029,即爲32+9=41

00 01

program_number爲0x0001

c1二進制爲1100 0001

version_number爲00000

current_next_indicator爲1,表示當前傳送的program_map_section可用

00 00

分別表示section_number和last_section_number

f0 01二進制爲1111 0000 0000 0001

PCR_PID爲0x1001,即爲2的12次方+1=4097,該字段只是TS包的PID值

f0 0c二進制爲11110000 0000 1100

program_info_length爲0x00c,即爲12





 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章