TS格式解析


1.TS格式介紹

   TS:全稱為MPEG2-TS。TS即"Transport Stream"的縮寫。它是分包發送的,每一個包長為188字節(還有192和204個字節的包)。包的結構為,包頭為4個字節(第一個字節為0x47),負載為184個字節。在TS流里可以填入很多類型的數據,如視頻、音頻、自定義信息等。MPEG2-TS主要應用於實時傳送的節目,比如實時廣播的電視節目。MPEG2-TS格式的特點就是要求從視頻流的任一片段開始都是可以獨立解碼的。簡單地說,將DVD上的VOB文件的前面一截cut掉(或者是數據損壞數據)就會導致整個文件無法解碼,而電視節目是任何時候打開電視機都能解碼(收看)的。

   TS解析需要參考:ISO/IEC 13818-1的2.4 Transport Stream bitstream requirements

2.TS流包含的內容

    一段TS流,必須包含PAT包、PMT包、多個音頻包、多個視頻包、多個PCR包、以及其他信息包。

    解析TS流數據的流程:查找PID為0x0的包,解析PAT,PAT包中的program_map_PID表示PMT的PID;查找PMT,PMT包中的elementary_PID表示音視頻包的PID,PMT包中的PCR_PID表示PCR的PID,有的時候PCR的PID跟音頻或者視頻的PID相同,說明PCR會融進音視頻的包,注意解析,有的時候PCR是自己單獨的包;CAT、NIT、SDT、EIT的PID分別為: 0x01、0x10、0x11、0x12。

3.TS包頭解析

    TS包頭有4個字節

//Transport Stream header
typedef  struct  TS_header
{
          unsigned sync_byte                    :8;      //同步字節,固定為0x47 ,表示后面的是一個TS分組,當然,后面包中的數據是不會出現0x47的
          unsigned transport_error_indicator       :1;      //傳輸錯誤標志位,一般傳輸錯誤的話就不會處理這個包了
          unsigned payload_unit_start_indicator    :1;      //有效負載的開始標志,根據后面有效負載的內容不同功能也不同
          // payload_unit_start_indicator為1時,在前4個字節之后會有一個調整字節,它的數值決定了負載內容的具體開始位置。
          unsigned transport_priority              :1;      //傳輸優先級位,1表示高優先級
          unsigned PID                          :13;     //有效負載數據的類型
          unsigned transport_scrambling_control     :2;      //加密標志位,00表示未加密
          unsigned adaption_field_control          :2;      //調整字段控制,。01僅含有效負載,10僅含調整字段,11含有調整字段和有效負載。為00的話解碼器不進行處理。
          unsigned continuity_counter              :4;      //一個4bit的計數器,范圍0-15
} TS_header;
     //特殊參數說明:
    //sync_byte:0x47
    //payload_unit_start_indicator:0x01表示含有PSI或者PES頭
    //PID:0x0表示后面負載內容為PAT,不同的PID表示不同的負載
    //adaption_field_control:
         // 0x0: // reserved for future use by ISO/IEC
         // 0x1: // 無調整字段,僅含有效負載  
         // 0x2: // 僅含調整字段,無有效負載
         // 0x3: // 調整字段后含有效負載
 
// Parse TS header
int  Parse_TS_header(unsigned char  *pTSBuf, TS_header *pheader)
{
     pheader->sync_byte                                     = pTSBuf[0];
     if  (pheader->sync_byte != 0x47)
         return  -1;
     pheader->transport_error_indicator       = pTSBuf[1] >> 7;
     pheader->payload_unit_start_indicator    = pTSBuf[1] >> 6 & 0x01;
     pheader->transport_priority             = pTSBuf[1] >> 5 & 0x01;
     pheader->PID                         = (pTSBuf[1] & 0x1F) << 8 | pTSBuf[2];
     pheader->transport_scrambling_control   = pTSBuf[3] >> 6;
     pheader->adaption_field_control         = pTSBuf[3] >> 4 & 0x03;
     pheader->continuity_counter            = pTSBuf[3] & 0x0F;
     return  0;
}

      TS包頭解析需要參考:ISO/IEC 13818-1的2.4.3.2 Transport Stream packet layer

4.TS負載格式解析

4.1 PAT解析

   TS_header包頭中的PID值為0x0,表示當前負載為PAT(Program Association Table)。PAT數據的信息可以理解為整個TS流包含的節目信息。

// Program Association Table
typedef  struct  PAT_Packet_tag
{
     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
     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; //最后一個分段的號碼
     // for(i=0; i<N; i++)
     // {
     unsigned program_number                  : 16;
     unsigned reserved_3                      : 3;
     unsigned network_PID                     : 16;  // 或者program_map_PID
  // }
     unsigned CRC_32                          : 32;
} PAT_Packet;
 
// Parse PAT
int  Parse_PAT(unsigned char  *pTSBuf, PAT_Packet *packet)
{
     TS_header TSheader;
     if  (Parse_TS_packet_header(pTSBuf, &TSheader) != 0)
         return  -1;
     if  (TSheader.payload_unit_start_indicator == 0x01) // 表示含有PSI或者PES頭
     {
         if  (TSheader.PID == 0x0)  // 表示PAT
         {
              int  iBeginlen = 4;
              int  adaptation_field_length = pTSBuf[4];
              switch (TSheader.adaption_field_control)
              {
              case  0x0:                                    // reserved for future use by ISO/IEC
                   return  -1;
              case  0x1:                                    // 無調整字段,僅含有效負載      
                   iBeginlen += pTSBuf[iBeginlen] + 1;  // + pointer_field
                   break ;
              case  0x2:                                     // 僅含調整字段,無有效負載
                   return  -1;
              case  0x3: // 調整字段后含有效負載
                  if  (adaptation_field_length > 0)
                  {
                       iBeginlen += 1;                   // adaptation_field_length占8位
                       iBeginlen += adaptation_field_length; // + adaptation_field_length
                  }
                  else
                  {
                       iBeginlen += 1;                       // adaptation_field_length占8位
                  }
                  iBeginlen += pTSBuf[iBeginlen] + 1;           // + pointer_field
                  break ;
             default :
                  break ;
             }
             unsigned char  *pPAT = pTSBuf + iBeginlen;
             packet->table_id                    = pPAT[0];
             packet->section_syntax_indicator    = pPAT[1] >> 7;
             packet->zero                        = pPAT[1] >> 6 & 0x1;
             packet->reserved_1                  = pPAT[1] >> 4 & 0x3;
             packet->section_length              = (pPAT[1] & 0x0F) << 8 |pPAT[2];
             packet->transport_stream_id         = pPAT[3] << 8 | pPAT[4];
             packet->reserved_2                  = pPAT[5] >> 6;
             packet->version_number              = pPAT[5] >> 1 &  0x1F;
             packet->current_next_indicator      = (pPAT[5] << 7) >> 7;
             packet->section_number              = pPAT[6];
             packet->last_section_number         = pPAT[7];
             int  len = 0;
             len = 3 + packet->section_length;
             packet->CRC_32                      = (pPAT[len-4] & 0x000000FF) << 24
                                                 | (pPAT[len-3] & 0x000000FF) << 16
                                                 | (pPAT[len-2] & 0x000000FF) << 8
                                                 | (pPAT[len-1] & 0x000000FF);
 
             int  n = 0;
             for  ( n = 0; n < (packet->section_length - 12); n += 4 )
             {
                  packet->program_number = pPAT[8 + n ] << 8 | pPAT[9 + n ];
                  packet->reserved_3                = pPAT[10 + n ] >> 5;
                  if  ( packet->program_number == 0x00)
                  {
                      packet->network_PID = (pPAT[10 + n ] & 0x1F) << 8 |pPAT[11 + n ];
                  }
                  else
                  {
                      // 有效的PMT的PID,然后通過這個PID值去查找PMT包
                      program_map_PID = (pPAT[10 + n] & 0x1F) << 8 |pPAT[11 + n];
                  }
             }
             return  0;
          }
     }
     return  -1;
}

  PAT數據解析需要參考:ISO/IEC 13818-1的2.4.4.3 Program Association Table

4.2 PMT解析

    由PAT包中的program_map_PID可以確定PMT(Program Map Table)的PID。PMT數據的信息可以理解為這個節目包含的音頻和視頻信息。 

   

// Program Map Table
typedef  struct  PMT_Packet_tag
{
      unsigned table_id                        : 8;
      unsigned section_syntax_indicator        : 1;
      unsigned zero                            : 1;
      unsigned reserved_1                      : 2;
      unsigned section_length                  : 12;
      unsigned program_number                  : 16;
      unsigned reserved_2                      : 2;
      unsigned version_number                  : 5;
      unsigned current_next_indicator          : 1;
      unsigned section_number                  : 8;
      unsigned last_section_number             : 8;
      unsigned reserved_3                      : 3;
      unsigned PCR_PID                         : 13;
      unsigned reserved_4                      : 4;
      unsigned program_info_length             : 12;
      // for(i=0; i<N; i++)
      // {
      unsigned stream_type                     : 8;
      unsigned reserved_5                      : 3;
      unsigned elementary_PID                  : 13;
      unsigned reserved_6                      : 4;
      unsigned ES_info_length                  : 12;
      // }
      unsigned CRC_32                          : 32;
} PMT_Packet;
    // Parse PMT
int  Parse_PMT(unsigned char  *pTSBuf, PMT_Packet *packet)
{
     // 參考Parse_PAT()來做就行了
     // ...
     
     return  0;
}

  PMT數據解析需要參考:ISO/IEC 13818-1的2.4.4.8 Program Map Table

4.3 PES解析

    根據文檔參考PAT、PMT的解析流程就能完成PES的解析了。

    需要注意的是PES中PTS的解析,一般來說在90 kHz 中,PTS/9000的值為秒單位。

    

unsigned long  long  Parse_PTS(unsigned *pBuf)
{
      unsigned long  long  llpts = (((unsigned long  long )(pBuf[0] & 0x0E)) << 29)
          | (unsigned long  long )(pBuf[1] << 22)
          | (((unsigned long  long )(pBuf[2] & 0xFE)) << 14)
          | (unsigned long  long )(pBuf[3] << 7)
          | (unsigned long  long )(pBuf[4] >> 1);
      return  llpts;
}
PES結構詳解
2013年08月05日 ⁄ 編程 ⁄ 共 1100字 ⁄ 評論數 2 ⁄ 被圍觀 3,562+

PES是Packetized Elementary Stream的簡稱,是將原始ES流打包后形成的,再將PES經過不同的打包方式可以組成MPEG program stream 和 MPEG transport stream,即PS流和TS流。

PES的組成結構如圖,包括6個字節的包頭字段,加上3個字節基本流信息字段,根據信息字段的設置可在之后附加其他字段。

<a href="http://www.yunlipiao.com/wp-content/uploads/2013/08/pes.jpg" class="cboxElement" rel="example4" 208"="" style="text-decoration: none; color: rgb(1, 150, 227);"> PES結構

PES結構

前三字節是包頭起始標識字段,內容為0x000001

第四個字節是流ID字段,不同的流ID有不用的意義,如圖,音頻流ID范圍從0xC0到0xDF,視頻流ID范圍從0xE0到0xEF。

PES流ID字段

PES流ID字段

第五六個字節是PES包長度,表示PES包頭部在該字段之后的長度,單位是字節

接下來的第七八九字節是PES的擴展頭部字段,用於設置流的基本信息,結構如圖

PES可選擴展

PES可選擴展

第六字節的高兩位是標識位,值為10b

第七字節的高兩位是PTS和DTS指示位,00表示無PTS無DTS,01禁止使用,10表示PES頭部字段會附加PTS結構

pts結構

pts結構

11表示PES頭部字段會附加PTS和DTS結構

pts和dts結構

pts和dts結構

其中PTS和DTS使用的是90KHZ時鍾單位,即1PTS表示1/90000秒,PTS和DTS雖然是33位,但占用了5個字節

ESCR FLAG字段設為1,會在頭部附加6個字節的ESCR結構,ES RATE FLAG字段設置為1,會在頭部附加3個字節ES rate結構,其他標識位如果設置為1也會相應的在頭部附加對應字段。

ES rate結構

ES rate結構

ESCR結構

ESCR結構

 

 
本文地址: http://www.yunlipiao.com/208.html,出自 雲里飄博客,轉載請保留鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM