ts碼流解析工作總結
近段時間,由於工作需要,初步研究學習了TS流的解析,多少有些心得體會,這裡與大家分享一下(大牛可以無視,呵呵)。
已編碼的音視訊資料,按照PES格式進行第一次打包,即PES包。一系列PES包,也有一種叫法叫PES分組。
PES包有幾個比較重要的欄位(摘自13818標準文件):
分組起始碼字首欄位 packet_start_code_prefix
24位程式碼,它和後面的stream_id構成了標識分組開始的分組起始碼。它是一個值為'0000 00000000 0000 0000 0001' (0x000001)的位串。
流標識欄位 stream_id
在節目流中,它規定了基本流的號碼和型別。PES分組長度欄位 PES_packet_length
PTS DTS標誌欄位 PTS_DTS_flags
2位欄位。當值為'10'時,PTS欄位應出現在PES分組標題中;當值為'11'時,PTS欄位和DTS欄位都應出現在PES分組標題中;當值為'00'時,PTS欄位和DTS欄位都不出現在PES分組標題中。值'01'是不允許的。PES標題資料長度欄位 PES_header_data_length
8位欄位。指出包含在PES分組標題中的可選欄位和任何填充位元組所佔用的總位元組數。該欄位之前的位元組指出了有無可選欄位。
(詳細介紹或者其他欄位,大家可以參看13818標準中文版 從第39頁開始)
初步解析時,判斷PES開頭碼,判斷資料型別,根據PES_packet_lengh與PES_header_data_length,計算整個PES的長度與有效荷載資料的長度,以便荷載編碼資料提取。這裡務必注意PES_packet_lengh為0的情況。
當然PES包是不允許直接傳輸的,標準規定,PES包需要進行第二次打包,打包為TS、或者PS格式的資料包,才能進行傳輸。
從應用角度上來說,TS碼流適用於網路情況不太理想的環境,它提供了有效的容錯處理機制;PS碼流適用於基本無錯的環境,比如區域網,DVD之類。
從解析工作流程上來說,TS的解析工作量要比PS多些。
*************************************************************************************************************************************************
先簡單地說說TS碼流。
TS資料長度定位188位元組,也就是說無論一個TS包中有效資料有沒有,有多少,最終打包大小都是188位元組(小日本兒搞了一個192位元組的標準,暫時無視)
每個TS資料包,以0x47作為起始碼,也叫同步位元組。
也就是說,對於一段經典的TS碼流,每隔188位元組,一定能檢測到一個0x47的位元組。如果不能,則說明資料流有異常。
TS資料包荷載的資料基本分為兩類:PSI資訊資料表 和 PES分組資料
PSI表共有一下4種:
節目相關表
節目對映表
條件存取表
網路資訊表
可以比較通俗地理解:TS包為了保證編碼資料的有效傳輸,需要以上各類資訊表作為傳輸控制引數,然後PES分組則是需要被傳輸的有效資料。
這裡也從標準文件中摘錄幾個比較重要的欄位(摘自13818中文版,從第29頁開始):
同步位元組欄位 sync_byte
一個固定的值為 '0100 0111' (0x47)的8位欄位。在選擇其它經常出現的欄位值時,應避免與該欄位發生衝突。
傳輸錯誤指示符欄位 transport_error_indicator
一個1位標誌。置'1'時表示相關傳輸流分組中至少有一個不可糾正的位差錯。該位可能被傳輸層外部的實體置'1'。置'1'後,除非錯誤被糾正,值不會恢復為'0'。
有效負載資料單元起始指示符欄位 pay_load_unit_start_indicator (這個欄位的介紹特別詳細,一定要弄明白)
一個1位標誌位,對於攜帶PES分組(參見2.4.3.6)或PSI資料(參見2.4.4)的傳輸流分組有標準的含義。
在傳輸流分組的有效負載資料包含PES分組資料時,該標誌位有以下意義:'1'表示傳輸流分組的有效負載資料以PES分組的首位元組開始,'0'表示該傳輸流分組不以PES分組開始。若值為'1',則有且僅有1個PES分組在傳輸流分組開始,它也適用於流型別6的專用流(參見表2-29)。
在傳輸流分組的有效負載資料包含PSI資料時,該標識位有以下意義:若傳輸流分組攜帶有PSI段的第一個位元組,則該值應為'1',以表示傳輸流分組中有效負載資料的首位元組帶有point_field。若傳輸流分組不包含PSI段的第一個位元組,則該值應為'0',以表示傳輸流分組中有效負載資料的首位元組無point_field。參見2.4.4.1和2.4.4.2。這也適用於流型別5的專用流(參見表2-29)。
對空的分組而言,該標誌位置'0'。
對於只攜帶專用資料的傳輸流分組,該位的意義在本規範未作規定。
PID欄位 PID
13位欄位,指示分組有效負載資料中儲存的資料型別。PID值0x0000被保留用於節目相關表(參見表2-25)。PID值0x0001被保留用於條件存取表(參見表2-27)。PID值0x0002~0x000F也被保留。PID值0x1FFF被保留用於空的分組(參見PID表)。
PID表
值 |
描 述 |
0x0000 |
PAT |
0x0001 |
CAT |
0x0002~0x000F |
保留 |
0x0010…0x1FFE |
可以賦給network_PID,Program_map_IP,elementary_PID或作其它用途 |
0x1FFF |
空的分組 |
注:PID值為0x0000,0x0001,和0x0010…0x1FFE的傳輸分組允許攜帶PCR |
適應欄位控制欄位 adaption_field_control
2位欄位,指出傳輸流分組標題後面是否有適應欄位及(或)有效負載資料,參看下表。
值 |
描 述 |
00 |
ISO/IEC保留,以供將來使用 |
01 |
沒有適應欄位,僅有有效負載 |
10 |
僅有適應欄位,沒有有效負載 |
11 |
跟有有效負載的適應欄位 |
適應欄位長度欄位 adaption_field_length
8位欄位,指示緊隨其後adaption_field的位元組長度。值為0用於在傳輸流分組中插入單個填充位元組。當適應欄位控制的值為'11'時,該欄位值應在0到182之間。當適應欄位控制的值為'10'時,該欄位值應為183。對於攜帶PES分組的傳輸流分組,在沒有足夠的PES分組資料來完全填滿傳輸流分組有效負載位元組時,需要填充。通過定義一個比其內部包含的資料元素的長度之和還要長的適應欄位來完成填充,這樣適應欄位後所剩的有效負載位元組恰好能容納有用的PES分組資料。適應欄位中多餘的空間被填入填充位元組。
這是對攜帶PES分組的傳輸流分組所允許的唯一的填充方法。對攜帶PSI的傳輸流分組,2.4.4中描述了另一種填充方法。
解析工作:
找到資料流中第一個出現0x47的位元組,判斷是否為TS碼流的起始(往後多查詢 188 * n組位元組,看看是否都是0x47),取從0x47開始的188位元組,進入TS包解析模組。
首先解析PID為0的PAT表,若當前包不是,則丟棄該包,進入下一個ts包,直到完成PAT表解析。
從PAT包中解析出PMT表所在的TS包的PID值,然後逐個解析後續TS包,直接找到對應PID的TS包,然後按照標準解析PMT表。
(一般來說,簡單的TS碼流資料,解析以上兩個表即可,也不會有其他PSI表了,初學者也需要首先了解上述兩個表)
如果有其他PSI表,也需要同樣解析。
在PMT中能解析出編碼傳輸資料所在TS包的PID值,根據這些PID值,逐個解析後續TS包,只要包含對應的PID,則說明該TS包中荷載了PES分組資料。
到這裡,計算出PES包的起始位置,開始PES的解析流程。
後續的TS包,逐個補充該PES包,直到完成一個PES包的提取工作。
以上就是一個比較粗略的TS碼流解析流程。
筆者在學習過程中,在以下方面遇到過困難,寫出來,望各位朋友注意:
一個TS資料段解析後剩餘一部分不足188長度資料,需要與下一個TS資料段前一部分資料,組裝一個TS包
讀取某位元組資料,並轉為int資料時,注意用byte,不要用char,如:
int adaptation_field_length = (byte)_ts_buf[4];
而不要:int adaptation_field_length = (int)_ts_buf[4];
對於PES_packet_lengh為0的情況,採用檢測下一個PES包起始位減去當前起始位的方式獲取包長度。