TS流分析

来源:互联网 发布:淘宝助理mac官方版 编辑:程序博客网 时间:2024/04/30 07:15

TS流也是由一个或多个PES组合而来的,他们可以具有相同的时间基准,也可以不同。其基本的复用思想是,对具有相同时间基准[color="#000000"]的多个PES现进行节目复用,然后再对相互有独立时间基准的各个PS进行传输复用,最终产生出TS TS包由包头和包数据2部分组成,其中包头还可以包括扩展的自适用区。包头长度占4bytes,自使用区和包数据共占184bytes,整个TS包长度相当于4ATM包长。TS包的包头由如下图摘录所示的同步字节、传输误码指示符、有效载荷单元起始指示符、传输优先、包识别(PID-Packet Identification)、传输加扰控制、自适应区控制和连续计数器8个部分组成。


其中,可用同步字节位串的自动相关特性,检测数据流中的包限制,建立包同步;传输误码指示符,是指有不能消除误码时,采用误码校正解码器可表示1bit的误码,但无法校正;有效载荷单元起始指示符,表示该数据包是否存在确定的起始信息;传输优先,是给TS包分配优先权;PID值是由用户确定的,解码器根据PIDTS上从不同ES来的TS包区别出来,以重建原来的ES;传输加扰控制,可指示数据包内容是否加扰,但包头和自适应区永远不加扰;自适应区控制,用2 bit表示有否自适应区,即(01)表示有有用信息无自适应区,(10)表示无有用信息有自适应区,(11)表示有有用信息有自适应区,(00)无定义;连续计数器可对PID包传送顺序计数,据计数器读数,接收端可判断是否有包丢失及包传送顺序错误。显然,包头对TS包具有同步、识别、检错及加密功能。
    TS包自适应区由自适应区长、各种标志指示符、与插入标志有关的信息和填充数据4部分组成。其中标志部分由间断指示符、随机存取指示符、ES优化指示符、PCR标志、接点标志、传输专用数据标志、原始PCR标志、自适应区扩展标志8个部分组成。重要的是标志部分的PCR字段,可给编解码器的27MHz时钟提供同步资料,进行同步。其过程是,通过PLL,用解码时本地用PCR相位与输入的瞬时PCR相位锁相比较,确定解码过程是否同步,若不同步,则用这个瞬时PCR调整时钟频率。因为,数字图像采用了复杂而不同的压缩编码算法,造成每幅图像的数据各不相同,使直接从压缩编码图像数据的开始部分获取时钟信息成为不可能。为此,选择了某些(而非全部)TS包的自适应区来传送定时信息。于是,被选中的TS包的自适应区,可用于测定包信息的控制bit和重要的控制信息。自适应区无须伴随每个包都发送,发送多少主要由选中的TS包的传输专用时标参数决定。标志中的随机存取指示符和接点标志,在节目变动时,为随机进入I帧压缩的数据流提供随机进入点,也为插入当地节目提供方便。自适应区中的填充数据是由于PES包长不可能正好转为TS包的整数倍,最后的TS包保留一小部分有用容量,通过填充字节加以填补,这样可以防止缓存器下溢,保持总码率恒定不变。

 

根据前一篇中各数据的定义及数据结构,对数据进行分别解析如下:

TS包头定义:

typedef struct TS_packet_header
{
    unsignedsync_byte                       : 8; //
同步字节,固定为0x47,表示后面的是一个TS分组
    unsignedtransport_error_indicator        : 1; //
传输误码指示符
    unsigned payload_unit_start_indicator    : 1;//
有效荷载单元起始指示符
   
    unsigned transport_priority             : 1; //
传输优先, 1表示高优先级,传输机制可能用到,解码用不着
    unsignedPID                           : 13; //PID
    unsigned transport_scrambling_control    : 2;//
传输加扰控制 
    unsignedadaption_field_control           : 2; //
自适应控制 01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载。为00解码器不进行处理
    unsignedcontinuity_counter               : 4; //
连续计数器一个4bit的计数器,范围0-15
} TS_packet_header;

 

TS包头解析代码:

HRESULTCTS_Stream_Parse::adjust_TS_packet_header( TS_packet_header* TS_header )
{
 unsigned char buf[4]; 
 
    memcpy(buf, TS_header, 4);
   TS_header->transport_error_indicator       = buf[1] >> 7;
    TS_header->payload_unit_start_indicator   = buf[1] >> 6 & 0x01;
   TS_header->transport_priority               = buf[1] >> 5 & 0x01;
   TS_header->PID                           = (buf[1] & 0x1F) << 8 | buf[2];
    TS_header->transport_scrambling_control   = buf[3] >> 6;
   TS_header->adaption_field_control           = buf[3] >> 4 & 0x03;
   TS_header->continuity_counter               = buf[3] & 0x0F; //
四位数据,应为0x0F xyy 09.03.18

 return 0;
}

如下为一个TS包数据:

0x47 0x400x00 0x12 0x00 0x00 0xb0 0x0d 0x00 0x00 0xc1 0x00 0x00 0x00 0x01 0xe30xe8 0xf0 0x0b 0xd7 0x79 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

分析知道前四位0x470x40 0x00 0x12TS头部即为TS包头数据,解析如下:

sync_byte   0x47
transport_error_indicator: 0x00
payload_unit_start_indicator: 0x01
transport_priority  : 0x00

  PID                     :0x0000
transport_scrambling_control  :0x00
adaptation_field_control  :0x01                                     

continuity_counter   :0x02

PID = 0x0000,表示此TS包的内容为PSI信息表格的PAT表格数据,在4字节的TS包头之后的第一个字节Point_field= 0x00, 表示偏移量为0,即紧随其后的即为PAT的数据信息。

 

 

TS流解析之PAT表格解析

PAT表格定义如下:

typedef struct TS_PAT_Program
      {
       unsigned program_number    :16; //
节目号
       unsigned program_map_PID   :13;   //
节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
      }TS_PAT_Program;

//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; //表示这个字节后面有用的字节数,包括CRC32

计算节目数 = (section_length      – 9)/4     (4表示每个节目所占字节数)
          unsigned      transport_stream_id                 : 16; //
该传输流的ID,区别于一个网络中其它多路复用的流
          unsigned      reserved_2                             : 2;//
保留位
          unsigned      version_number                         : 5; //
范围0-31,表示PAT的版本号
          unsigned      current_next_indicator                 : 1; //
发送的PAT是当前有效还是下一个PAT有效
          unsigned      section_number                         : 8; //
分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段
          unsigned      last_section_number                 : 8;  //
最后一个分段的号码
       
       std::vector<TS_PAT_Program> program;
          unsigned      reserved_3                             : 3; //
保留位
          unsigned      network_PID                         : 13; //
网络信息表(NIT)的PID,节目号为0时对应的PIDnetwork_PID

    unsigned      CRC_32                                 : 32;  //CRC32校验码
      } TS_PAT;

 

解析代码如下:

HRESULT CTS_Stream_Parse::adjust_PAT_table( TS_PAT      * packet, unsigned char * buffer)
      {
               packet->table_id                         = buffer[0];
          packet->section_syntax_indicator         = buffer[1] >> 7;
               packet->zero                             = buffer[1] >> 6 & 0x1;
               packet->reserved_1                         = buffer[1] >> 4 & 0x3;
               packet->section_length                     = (buffer[1] & 0x0F) << 8 | buffer[2]; 
       
          packet->transport_stream_id                 = 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];

    int len = 0;
          len = 3 + packet->section_length;
               packet->CRC_32                             = (buffer[len-4] & 0x000000FF) << 24
        | (buffer[len-3] & 0x000000FF) << 16
        | (buffer[len-2] & 0x000000FF) << 8 
        | (buffer[len-1] & 0x000000FF); 
       
        
       int n = 0;
          for ( n = 0; n < packet->section_length - 12; n      += 4 )
          {
        unsigned  program_num = buffer[8 + n ] << 8 |      buffer[9 + n ];  
              packet->reserved_3                     = buffer[10 + n ] >> 5; 
        
        packet->network_PID = 0x00;
        if ( program_num == 0x00)
        {  
                       packet->network_PID = (buffer[10 + n ] & 0x1F) << 8 |      buffer[11 + n ];

   TS_network_Pid      = packet->network_PID; //记录该TS流的网络PID

   TRACE("      packet->network_PID %0x \n\n", packet->network_PID );
        }
              else
              {
         TS_PAT_Program PAT_program;
         PAT_program.program_map_PID = (buffer[10 + n] &      0x1F) << 8 | buffer[11 + n];
         PAT_program.program_number = program_num;
         packet->program.push_back( PAT_program );
         
         TS_program.push_back( PAT_program );//
向全局PAT节目数组中添加PAT节目信息     
              }              
          }
       return 0;
      }

因此,PAT数据解析结果如下:

PAT数据

table_id    0x00                            //8  
     
section_syntax_indicator   0x01           //      1
     
'0'              0x00                            // 1
     
reserved             0x03                //      2
     
section_length      0x00d                    //      12
     
transport_stream_id    0x0000                      // 16
     
reserved                        0x03        //      2
     
version_number            0x00              //      5
     
current_next_indicator   0x01               //      1
     
section_number              0x00            //      8
     
last_section_number         0x00                 // 8
     
program_number     0x0001                         // 16
     
  reserved                0x07                    // 3
     
program_map_PID      0x03e8                  // 13
     
CRC         0x f0 0b d7 79
     
     
由解析结构可知,该PAT表格中没有网络信息包信息,只包含一个节目,其PID0x03e8

 0x00 0xb0 0x0d 0x00 0x00 0xc1 0x00 0x00 0x000x01 0xe3 0xe8 0xf0 0x0b 0xd70x790xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x

 

 

TS流解析之PMT表格解析

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

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
          unsigned      PCR_PID                             : 13; //
指明TS包的PID值,该TS包含有PCR域,
                  //
PCR值对应于由节目号指定的对应节目。
                  //
如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF
          unsigned      reserved_4                             : 4; //
预留为0x0F
          unsigned      program_info_length                 : 12; //
前两位bit00。该域指出跟随其后对节目信息的描述的byte数。
          
       std::vector<TS_PMT_Stream> PMT_Stream;  //
每个元素包含8,指示特定PID的节目元素包的类型。该处PIDelementary PID指定
          unsigned      reserved_5                             : 3; //0x07
          unsigned      reserved_6                             : 4; //0x0F
          unsigned      CRC_32                                 : 32; 
      } TS_PMT;

 

  0x0 2 0xb 0 0x1 2 0x00 0x01 0xc1 0x00 0x00      0xe3 0xe9 0xf0 0x00  0x1b 0xe3 0xe9

解析代码为:

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

举例如下:

0x47 0x43 0xe8 0x12 0x00 0x02 0xb0 0x12 0x00 0x01 0xc1 0x00      0x00 0xe3 0xe9 0xf0 0x00  0x1b 0xe3 0xe9 0xf0 0x00 0xf0 0xaf      0xb4 0x4f 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff      0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

TS头部

sync_byte   0x47
     
transport_error_indicator: 0x00
     
payload_unit_start_indicator: 0x01
     
transport_priority  : 0x00

  PID                     :0x03e8
     
transport_scrambling_control  :0x00
     
adaptation_field_control  :0x01                                     

continuity_counter   :0x02

 

PMT数据         

table_id     :0x02                               // 8
     
section_syntax_indicator  :0x01            //  1
     
'0'                :0x00                        //  1
     
reserved       :0x03                       //  2
     
section_length :      0x012                 //  12
     
program_number    :0x00      01                    //  16
     
reserved               :0x03               //  2
     
version_number    :0x00                    //  5
     
current_next_indicator   0x01             //  1
     
section_number      :0x00                  //  8
     
last_section_number    :0x00                    //  8 
     
reserved                   0x07           //  3
     
PCR_PID           :0x03      e9   // PCR(节目参考时钟)所在TS分组的PID               //  13
     
reserved       :0x0f                 //4
     
program_info_length     :0x000                   //  12
     
stream_type       :0x1b                         //  8
     
reserved            0x07                  //  3
     
elementary_PID        :0x03      e9    //  13//该节目中包括的视频流,音频流等对应的TS分组的PID
     
reserved                    :0x0f          //  4
     
ES_info_length         :0x000               //  12
     
CRC        :      0xf0 af b4 4f

 

原创粉丝点击