1. 程式人生 > >ts packet解析

ts packet解析

head 什麽 等於 light ans io緩沖區 ack 中間 type

(1)TS流是基於Packet的位流格式,每個包是188字節或者204字節(一般是188字節,204字節的格式僅僅是在188字節的Packet後部加上16字節的CRC數據,其他格式是一樣的),整個TS流組成如下所示:

Packet 1 Packet 2 ...... Packet n

在實際使用中,因為TS流已經內部具有很強的錯誤處理能力,所以一般使用較多的是188字節一個包的格式,204字節一個包的格式據說一般在高清節目中使用較多.

所有的Packet格式都是統一的,包括一個Packet header和Packet datas.其中Packet header包含了同步字節(該字節固定是0x47,表示這個包的數據開始是正確的),該Packet的唯一號碼(即PID)和其他一些信息.格式如下(用C格式表示)

typedef struct

{

   unsigned sync_byte:8;/*8 bits的同步字節,固定為0x47*/

   unsigned transport_error_indicator:1;/*1 bit的錯誤指示信息,1表示當前Packet至少有1bit的傳輸錯誤,0表示所有數據都正確*/

   unsigned payload_unit_start_indicator:1;/*負載單元開始標誌。詳細下面介紹*/

   unsigned transport_priority:1;/*1 bit的傳輸優先級標誌,1表示高優先級,0表示低優先級*/

   unsigned PID:13;/*13 bits的Packet ID號碼,唯一的號碼對應不同的包*/

   unsigned transport_scrambling_control:2;/*2 bits的加擾標誌,00表示沒有加擾,其他表示已被加擾*/

   unsigned adaptation_field_control:2;/* 2 bits的附加區域控制,詳細下面介紹*/

   unsigned continuity_counter:4;/*4 bits的包遞增計數器*/

}PACKET_HEADER;
payload_unit_start_indicator
  這是1b長度字段,該字段用來表示ts包的有效凈荷帶有PES包或者PSI數據的情況。
  當ts包帶有PES包數據時,該字段具有以下特點:置為1,表示ts包的有效凈荷以PES包的第一個字節開始;置為0,表示ts包的開始不是PES包。
  當ts包帶有PSI數據時,該字段具有以下特點:置為1,表示ts包帶有PSI部分的第一個字節,即第一個字節帶有指針pointer_field;置為0,表示ts包不帶有一個PSI部分的第一個字節,即有效凈荷中沒有指針pointer_field。
  對於空包該字段應該置為0;
  也就是說,為1時,在前4個字節(包頭)之後會有一個調整字節,它的數值決定了負載內容的具體開始位置。
PID
  這個在頭部的32b的字段十分重要,它是辨別碼流信息性質的關鍵,是節目信息的“身份證”,不同的電視節目和業務信息SI對應有不同的PID值。對於一臺節目解碼接收機而言,為了找到他所要接收的電視節目,他首先通過PID值找到節目專用信息PSI與業務信息SI所對應的不同表,這些表包括PAT、PMT、
CAT、NIT、SDT、EIT和TDT等,通過這些有關節目的信息表,尤其是節目專用信息表,可以查到所要接受節目的PID值和對應的CRC,這樣節目就可以被還原。除了PAT表包的PID永遠為0外,還有兩種包的PID是預留的:一個是空包,它用作碼流填充,其PID是8191,是PID所有允許值0-8191的最後一個,
另一個是條件接收表包CAT,其PID值總是1。
transport_scrambling_control
  如果傳送流包首部包括調整字段,則不應該被加擾。對於空包。該字段的值置為“00”。
adaptation_field_control
  這是一個2b長度的字段,表示傳送流包首部是否跟隨有調整字段和/或有效凈荷。
    00:保留
    01:沒有調整字段,僅含有184B長度的有效凈荷
    10:沒有有效凈荷,僅含有183B長度的調整字段
    11:0~182B的調整字段後為有效凈荷
continuity_counter
  隨著具有相同PID包的增加二增加,當它達到最大時,又恢復為0.如果調整字段控制值 transport_scrambling_control為“00”和“10”,該連續計數器不增加。

以上結構剛好占用32 bits,即4個字節,因此一個TS流的Packet頭部的4字節是header信息,剩下的184個字節的內容由PID決定。分析該header信息就可以知道當前Packet的屬性.剩下的184字節有可能是Video數據,也有可能是Audio數據,也有可能是DVB SI信息,怎 麽區分呢?其實很簡單,就是利用header中的PID信息.上一章說了PAT是節目關聯表,它的PID是0x0000.這個PID就是對應這裏 header的PID.換句話就是說,如果我們發現一個Packet的PID等於0x0000,那麽說明這個Packet是DVB的PAT表格而不是 Video數據或者Audio數據.

  其他184個字節裏面基本都裝的是音頻或者視頻解碼數據。如果給定一個TS文件,怎麽去尋找解碼音視頻解碼數據呢?

每個TS包的前4個字節的包頭裏都有一個PID,首先,一個個遍歷TS包,我們找到PID為0的TS包,這個包叫PAT,這個PAT包裏包含了PMT的PID號,所以我們再遍歷TS包又又可以找到名為PMT的TS包,PMT裏包含了video TS包的PID和它的codec,audio TS包的PID和它的codec 。有了codec我們知道要選擇什麽解碼器,有PID我們就可以獲得解碼數據。

我們先來說說video數據和audio數據是怎麽分散在TS包裏的。video和audio其實都是以一種叫PES(Packetized Elementary Stream)的形式組織的。一幀視頻就是一個PES包。我們都知道一個TS包只有188個字節,除掉包頭還剩184個字節,這是不可能放下一幀的。實際上一個PES包是分配在連續的幾個TS包中,所以如果我們要獲得一幀數據,那麽我們需要把連續的幾個TS包裏的數據全部取出來才能組合成一個PES。那我們怎麽知道一個PES的開始和結尾呢?那我們還是一個個遍歷每一個TS包,尋找包頭裏payload_unit_start_indicator為1包,這個標誌位代表著是一個PES的開始,那麽我從這開始,一直到下一個payload_unit_start_indicator為1,這中間的TS包組成起來就是一個PES。

實際上,在信號編碼成TS碼流的時候,不同節目的Video,Audio等數據都分配了不同的PID.例如,一個節目有兩路Video,三路Audio,那 麽分配PID的時候可能是Video 1==0x100,Video 2==0x101,Audio 1==0x102,Audio 2==0x103, Audio 3==0x104,這樣傳輸的TS碼流中的PID就可能有以上的PID.因此,如果我們需要在程序中過濾出第一路Video和第二路 Audio就可以這樣處理了(偽代碼描述):

void Process_Packet(unsigned char*buff)
{ int PID=GETPID(buff);/*從當前的188字節緩沖區中獲取PID信息*/ if(PID==0x100) /*PID等於第一路Video的PID,說明當前數據是Video數據*/ {   SaveToVideoBuffer(buff+4);/*把header後部的數據存到Video緩沖區,待後部處理*/ }   else if(PID==0x103)/*PID等於第二路Audio的PID,說明當前數據是Audio數據*/ {    SaveToAudioBuffer(buff+4);/*把header後部的數據存到Audio緩沖區*/ } else/*其他PID則丟棄,當然如果PID是DVB系統保留的PID如PAT,PMT則必須處理*/ {   printf("unknown PID!\n");   } }

現 在的問題是,編碼的時候分配好的PID,在解碼的時候是怎麽知道什麽PID對應什麽數據呢?

這 裏僅僅截取了3個Packet的信息,請註意圖中用紅色標註的部分,這就是TS流Packet的4個字節的頭信息.這個TS流是采用每個包共188字節的 格式,因為兩個頭信息的間隔是188個字節(第一個0x47到第二個0x47的間隔).以後的所有的Packet都將是188字節的格式,這是 DVB TS標準規定的固定大小.那麽這三個包分別包含的是什麽數據,下面我們可以自己分析一下.

先 看第一個包,頭信息數據是"0x47 0x07 0xe5 0x12",剛才已經知道了,header信息都是按位操作的(這就是為什麽TS碼流也可以叫 做位流的原因),特別要註意的是定義和傳輸的時候都是MSB first,也就是說,先出現的位是數據的最高位.先轉化成2進制格式:

01000111 00000111 11100101 00010010

請對照上面的PACKET_HEADER結構:

typedef struct

{

   unsigned sync_byte:8;

   unsigned transport_error_indicator:1;

   unsigned payload_unit_start_indicator:1;

   unsigned transport_priority:1;

   unsigned PID:13;

   unsigned transport_scrambling_control:2;

   unsigned adaptation_field_control:2;

   unsigned continuity_counter:4;

}PACKET_HEADER;

那麽對照一下,我們可以發現:

  sync_byte=01000111,就是0x47,這是DVB TS規定的同步字節,固定是0x47.

  transport_error_indicator=0,表示當前包沒有發生傳輸錯誤.

   payload_unit_start_indicator=0,含義請參考ISO13818-1標準文檔

  transport_priority=0,表示當前包是低優先級.

  PID=00111 11100101即0x07e5,這代表是什麽呢,暫時還不知道(實際上是Video PID,參考下圖)

   transport_scrambling_control=00,表示節目沒有加密

   adaptation_field_control=01即0x01,具體含義請參考ISO13818-1

   continuity_counte=0010即0x02,表示當前傳送的相同類型的包是第3個

依此類推,再看一下第二個包"0x47 0x07 0xe5 0x13",二進制是:01000111 00000111 11100101 00010011

  sync_byte=01000111,就是0x47,這是DVB TS規定的同步字節,固定是0x47.

   transport_error_indicator=0,表示當前包沒有發生傳輸錯誤.

  payload_unit_start_indicator=0,含義請參考ISO13818-1標準文檔

  transport_priority=0,表示當前包是低優先級.

  PID=00111 11100101即0x07e5,這代表是什麽呢,暫時還不知道(實際上是Video PID,參考下圖)

  transport_scrambling_control=00,表示節目沒有加密

  adaptation_field_control=01即0x01,具體含義請參考ISO13818-1

  continuity_counte=0011即0x03,表示當前傳送的相同類型的包是第4個(註意到了吧,以上兩個包的PID都是0x07e5,所以這裏的continuity_counte就遞增一次)

第三個包是"0x47 0x07 0xf1 0x18",2進制是01000111 00000111 11110001 00011000.

  sync_byte=01000111,就是0x47,這是DVB TS規定的同步字節,固定是0x47.

  transport_error_indicator=0,表示當前包沒有發生傳輸錯誤.

  payload_unit_start_indicator=0,含義請參考ISO13818-1標準文檔

  transport_priority=0,表示當前包是低優先級.

  PID=00111 11100101即0x07f1,這代表是什麽呢,暫時還不知道(實際上是Audio PID,參考下圖)

  transport_scrambling_control=00,表示節目沒有加密

  adaptation_field_control=01即0x01,具體含義請參考ISO13818-1

  continuity_counte=1000即0x08,表示當前傳送的相同類型的包是第9個

參考博客:http://www.360doc.com/content/11/0824/08/7399771_142838446.shtml

ts packet解析