TS封裝格式


 ts流最早應用於數字電視領域,其格式非常復雜包含的配置信息表多達十幾個,視頻格式主要是mpeg2。蘋果公司發明的http live stream流媒體是基於ts文件的,不過他大大簡化了傳統的ts流,只需要2個最基本的配置表PAT和PMT,再加上音視頻內容就可以了,hls流媒體視頻編碼的主要格式為h264/mpeg4,音頻為aac/mp3。

ts文件分為三層:ts層(Transport Stream)、pes層(Packet Elemental Stream)、es層(Elementary Stream)。es層就是音視頻數據,pes層是在音視頻數據上加了時間戳等對數據幀的說明信息,ts層是在pes層上加入了數據流識別和傳輸的必要信息。

1.ts層

 ts包大小固定為188字節,ts層分為三個部分:ts header、adaptation field、payload。ts header固定4個字節;adaptation field可能存在也可能不存在,主要作用是給不足188字節的數據做填充;payload是pes數據。

1.1.ts header

sync_byte 8bit 同步字節,固定為0x47
transport_error_indicator 1bit 傳輸錯誤指示符,表明在ts頭的adapt域后由一個無用字節,通常都為0,這個字節算在adapt域長度內
payload_unit_start_indicator 1bit 負載單元起始標示符,一個完整的數據包開始時標記為1
transport_priority 1bit 傳輸優先級,0為低優先級,1為高優先級,通常取0
pid 13bit pid值(Packet ID號碼,唯一的號碼對應不同的包)
transport_scrambling_control 2bit 傳輸加擾控制,00表示未加密
adaptation_field_control 2bit 是否包含自適應區,‘00’保留;‘01’為無自適應域,僅含有效負載;‘10’為僅含自適應域,無有效負載;‘11’為同時帶有自適應域和有效負載。
continuity_counter 4bit 遞增計數器,從0-f,起始值不一定取0,但必須是連續的

ts層的內容是通過PID值來標識的,主要內容包括:PAT表、PMT表、音頻流、視頻流。解析ts流要先找到PAT表,只要找到PAT就可以找到PMT,然后就可以找到音視頻流了。PAT表的PID值固定為0。PAT表和PMT表需要定期插入ts流,因為用戶隨時可能加入ts流,這個間隔比較小,通常每隔幾個視頻幀就要加入PAT和PMT。PAT和PMT表是必須的,還可以加入其它表如SDT(業務描述表)等,不過hls流只要有PAT和PMT就可以播放了。

  • PAT表:他主要的作用就是指明了PMT表的PID值。
  • PMT表:他主要的作用就是指明了音視頻流的PID值。
  • 音頻流/視頻流:承載音視頻內容。
 PID是TS流中唯一識別標志,Packet Data是什么內容就是由PID決定的。如果一個TS流中的一個Packet的Packet Header中的PID是0x0000,那么這個Packet的Packet Data就是DVB的PAT表而非其他類型數據(如Video、Audio或其他業務信息)。下表給出了一些表的PID值,這些值是固定的,不允許用於更改。

PID 值

PAT

0x0000

CAT

0x0001

TSDT

0x0002

EIT,ST

0x0012

RST,ST

0x0013

TDT,TOT,ST

0x0014

下面以一個TS流的其中一個Packet中的Packet Header為例進行說明:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

Packet(十六進制)

4

7

0

7

e

5

1

2

Packet(二進制)

0

1

0

0

0

1

1

1

0

0

0

0

0

1

1

1

1

1

1

0

0

1

0

1

0

0

0

1

0

0

1

0

Packet Header 信息

1 sync_byte=0x47

2

3

4

5 PID=0x07e5

6

7

8

 

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個

1.2.adaption

adaptation_field_length 1B 自適應域長度,后面的字節數
flag 1B 取0x50表示包含PCR或0x40表示不包含PCR
PCR 5B Program Clock Reference,節目時鍾參考,用於恢復出與編碼端一致的系統時序時鍾STC(System Time Clock)。
stuffing_bytes xB 填充字節,取值0xff

自適應區的長度要包含傳輸錯誤指示符標識的一個字節。pcr是節目時鍾參考,pcr、dts、pts都是對同一個系統時鍾的采樣值,pcr是遞增的,因此可以將其設置為dts值,音頻數據不需要pcr。如果沒有字段,ipad是可以播放的,但vlc無法播放。打包ts流時PAT和PMT表是沒有adaptation field的,不夠的長度直接補0xff即可。視頻流和音頻流都需要加adaptation field,通常加在一個幀的第一個ts包和最后一個ts包里,中間的ts包不加。

1.3.PAT格式(Program Association Table,節目關聯表)

PAT表定義了當前TS流中所有的節目,其PID為0x0000,它是PSI的根節點,要查尋找節目必須從PAT表開始查找。

table_id 8b PAT表固定為0x00
section_syntax_indicator 1b 固定為1
zero 1b 固定為0
reserved 2b 固定為11
section_length 12b 后面數據的長度
transport_stream_id 16b 傳輸流ID,固定為0x0001
reserved 2b 固定為11
version_number 5b 版本號,固定為00000,如果PAT有變化則版本號加1
current_next_indicator 1b 固定為1,表示這個PAT表可以用,如果為0則要等待下一個PAT表
section_number 8b 固定為0x00
last_section_number 8b 固定為0x00
開始循環    
program_number 16b 節目號為0x0000時表示這是NIT,節目號為0x0001時,表示這是PMT
reserved 3b 固定為111
PID 13b 節目號對應內容的PID值
結束循環    
CRC32 32b 前面數據的CRC32校驗碼

通過一段TS流中一個Packet分析PAT表,這里我們分析一段TS流其中一個Packet的Packet Data部分:

首先給出一個數據包,其數據如下:

Packet Header

Packet Data

0x47 0x40 0x00 0x10

0000 b0 11 00 01 c1 00 00 00 00 e0 1f 00 01 e1 00 24 ac48 84 ff ff…… ff ff

分析Packet Header如下表所示:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

Packet(十六進制)

4

7

4

0

0

0

1

0

Packet(二進制)

0

1

0

0

0

1

1

1

0

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

0

0

0

0

Packet Header Bits

1 sync_byte=0x47

2

3

4

5 PID=0x0000

6

7

8

 根據包頭數據格式,我們可以知曉整個數據包的屬性,列表如下:

sync_byte

0x47

固定同步字節

transport_error_indicator

“0”

沒有傳輸錯誤

payload_unit_start_indicator

“1”

在前4個字節后會有一個調整字節。所以實際數據應該為去除第一個字節后的數據。即上面數據中紅色部分不屬於有效數據包。

transport_priority

“0”

傳輸優先級低

PID

0x0000

PID=0x0000說明數據包是PAT表信息

transport_scrambling_control

“00”

未加密

adaptation_field_control

“01”

附加區域控制

continuity_counte

“0000”

包遞增計數器

如上表所示,我們可以知道,首先Packet的Packet Data是PAT信息表,因為其PID為0x0000,並且在包頭后需要除去一個字節才是有效數據(payload_unit_start_indicator="1")。這樣,Packet Data就應該是“00 b0 11 00 01 c1 00 00 00 00 e0 1f 00 01 e1 00 24 ac48 84 ff ff …… ff ff”。

Packet Data分析

第n個字節

  1  

  3  

4

5

6

7

8

9

 10 

 11 

  12 

  13 

14 

15 

16

17

18

19

20

Packet Data(除去開頭的0x00)

00

b0

11

00

01

c1

00

00

00

00

e0

1f

00

01

e1

00

24

ac

48

84

字段名

具體值

次序

說明

table_id

8

0000

第1個字節 0000 0000B(0x00)

PAT的table_id只能是0x00

section_syntax_indicator

1

1

 

第2、3個字節

1011 0000 0001 0001B(0xb0 11)

段語法標志位,固定為1

zero

1

0

 

reserved

2

11

 

section_length

12

0000 0001 0001B=0x011=17

段長度為17字節

transport_stream_id

16

0x0001

第4、5個字節 0x00 0x01

 

reserved

2

11

 

第6個字節 1100 0001B(0xc1)

 

version_number

5

00000

一旦PAT有變化,版本號加1

current_next_indicator

1

1

當前傳送的PAT表可以使用,若為0則要等待下一個表

section_number

8

0x00

第7個字節0x00

 

last_section_number

8

0x00

第8個字節 0x00

 

開始循環

program_number

16

0x0000-第一次

2個字節(0x00 00)

節目號 

reserved

3

111

 

2個字節

1110 0000 0001 1111B(0xe0 1f)

 

network_id(節目號為0時)

program_map_PID(節目號為其他時)

13

0 0000 0001 1111B=31

-第一次

節目號為0x0000時,表示這是NIT,PID=0x001f,即31

節目號為0x0001時,表示這是PMT,PID=0x100,即256

結束循環

CRC_32

32

--

4個字節

 

 

 由以上幾個表可以分析出PAT表和PMT表有着內在的聯系。也就是之前提到的。PAT表描述了當前流的NIT(Network Information Table,網絡信息表)中的PID、當前流中有多少不同類型的PMT表及每個PMT表對應的頻道號。

1.4.PMT格式( Program Map Table,節目映射表 )

table_id 8b PMT表取值隨意,0x02
section_syntax_indicator 1b 固定為1
zero 1b 固定為0
reserved 2b 固定為11
section_length 12b 后面數據的長度
program_number 16b 頻道號碼,表示當前的PMT關聯到的頻道,取值0x0001
reserved 2b 固定為11
version_number 5b 版本號,固定為00000,如果PAT有變化則版本號加1
current_next_indicator 1b 固定為1
section_number 8b 固定為0x00
last_section_number 8b 固定為0x00
reserved 3b 固定為111
PCR_PID 13b PCR(節目參考時鍾)所在TS分組的PID,指定為視頻PID
reserved 4b 固定為1111
program_info_length 12b 節目描述信息,指定為0x000表示沒有
開始循環    
stream_type 8b 流類型,標志是Video還是Audio還是其他數據,h.264編碼對應0x1b,aac編碼對應0x0f,mp3編碼對應0x03
reserved 3b 固定為111
elementary_PID 13b 與stream_type對應的PID
reserved 4b 固定為1111
ES_info_length 12b 描述信息,指定為0x000表示沒有
結束循環    
CRC32 32b 前面數據的CRC32校驗碼

通過一段TS流中一個Packet分析PMT表,通過分析一段TS流的數據包Packet來學習PMT表。下面給出了一段TS流數據中的一個Packet(十六進制數)

Packet Header

Packet Data

0x47 0x43 0xe8 0x12

00 02 b0 12 00 01 c1 00 00 e3 e9 f0 00 1b e3 e9 f0 00 f0 af b4 4f ff ff…… ff ff

 首先解析Packet Header,分析如下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

Packet(十六進制)

4

7

4

3

e

8

1

2

Packet(二進制)

0

1

0

0

0

1

1

1

0

1

0

0

0

0

1

1

1

1

1

0

1

0

0

0

0

0

0

1

0

0

1

0

Packet Header Bits

1 sync_byte=0x47

2

3

4

5 PID=0x03e8

6

7

8

 

Packet Header分析

 

Packet Header:0x47 0x40 0x00 0x10

1

sync_byte

0x47

固定同步字節

2

transport_error_indicator

“0”

沒有傳輸錯誤

3

payload_unit_start_indicator

“1”

在前4個字節后會有一個調整字節。所以實際數據應該為去除第一個字節后的數據。

4

transport_priority

“0”

傳輸優先級低

5

PID

0x03e8

PID=0x03e8說明數據包是PMT表信息

6

transport_scrambling_control

“00”

未加密

7

adaptation_field_control

“01”

附加區域控制

8

continuity_counte

“0010”

包遞增計數器

因為payload_unit_start_indicator=‘1’,在解析數據包的時候需要去除Packet Data的第一個字節。下面是對Packet Data的詳細解析:

PMT表的Packet Data分析

第n個字節

1

2

3

4

5

6

7

8

9

10   

11   

12   

13   

14  

 15  

16

17

18

19

20

Packet Data

02

b0

12

00

01

c1

00

00

e3

e9

f0

00

1b

e3

e9

f0

00

f0

1b

e3

字段名

位數

具體值

次序

說明

table_id

8

0x02

第1個字節

 

section_syntax_indicator

1

1B

 

第2、3個字節

1011 0000 0001 0010B=0xb012

段語法標志

zero

1

0B

 

reserved

2

11B=0x03

 

section_length

12

0000 0001 0010B=0x12

段長度,從program_number開始,到CRC_32(含)的字節總數

program_number

16

0x0001

第4、5個字節 0x00 01

頻道號碼,表示當前的PMT關聯到的頻道

reserved

2

11B=0x03

 

第6個字節

1100 0001B=0xc1

 

version_number

 

5

 

00000B=0x00

版本號碼,如果PMT內容有更新,則它會遞增1通知解復用程序需要重新接收節目信息

current_next_indicator

1

1B=0x01

當前未來標志符

section_number

8

0x00

第7個字節0x00

當前段號碼

last_section_number

8

0x00

第8個字節 0x00

最后段號碼,含義和PAT中的對應字段相同

reserved

3

111B=0x07

第9、10個字節

1110 0011 1110 1001B=0xe3e9

 

PCR_PID

13

000111110B=0x3e9

PCR(節目參考時鍾)所在TS分組的PID

reserved

4

1111B=0x0f

 

 

 

第11、12個字節

1111 0000 0000 0000=0xf000

 

 

program_info_length

 

12

 

 

 

000000000000B=0x000

節目信息長度(之后的是N個描述符結構,一般可以忽略掉,這個字段就代表描述符總的長度,單位是Bytes)緊接着就是頻道內部包含的節目類型和對應的PID號碼了

stream_type

8

0x1b

第13個字節 0x1b

流類型,標志是Video還是Audio還是其他數據

reserved

3

111B=0x07

第14、15個字節

1110 0011 1110 1001B=0xe3e9

 

elementary_PID

13

000111110 1001=0x3e9

該節目中包括的視頻流,音頻流等對應的TS分組的PID

reserved

4

1111B=0x0f

第16、17個字節

1111 0000 0000 0000B=0xf000

 

ES_info_length

12

0000 0000 0000=0x000

 

CRC

32

——

——

 

 

1.4.pes層

pes層是在每一個視頻/音頻幀上加入了時間戳等信息,pes包內容很多,我們只留下最常用的。 

pes start code 3B 開始碼,固定為0x000001
stream id 1B 音頻取值(0xc0-0xdf),通常為0xc0
視頻取值(0xe0-0xef),通常為0xe0
pes packet length 2B 后面pes數據的長度,0表示長度不限制,
只有視頻數據長度會超過0xffff
flag 1B 通常取值0x80,表示數據不加密、無優先級、備份的數據
flag 1B 取值0x80表示只含有pts,取值0xc0表示含有pts和dts
pes data length 1B 后面數據的長度,取值5或10
pts 5B 33bit值
dts 5B 33bit值
pts是顯示時間戳、dts是解碼時間戳,視頻數據兩種時間戳都需要,音頻數據的pts和dts相同,所以只需要pts。有pts和dts兩種時間戳是B幀引起的,I幀和P幀的pts等於dts。如果一個視頻沒有B幀,則pts永遠和dts相同。從文件中順序讀取視頻幀,取出的幀順序和dts順序相同。dts算法比較簡單,初始值 + 增量即可,pts計算比較復雜,需要在dts的基礎上加偏移量。
     音頻的pes中只有pts(同dts),視頻的I、P幀兩種時間戳都要有,視頻B幀只要pts(同dts)。打包pts和dts就需要知道視頻幀類型,但是通過容器格式我們是無法判斷幀類型的,必須解析h.264內容才可以獲取幀類型。

1.5.es層

es層就是音視頻裸數據了,常用的音頻編碼格式為AAC,視頻編碼格式為H.264

2.打包H.264和AAC為TS

對於H.264視頻而言,每一幀的時間長度為

 frame_duration = 1000/fps

當fps為25時,一幀時間為40ms

對於AAC音頻而言,每一幀的時間長度為

音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率(單位為s)
一幀 1024個 sample。采樣率 Samplerate 44100KHz,每秒44100個sample, 所以根據公式   音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率
當前AAC一幀的播放時間是= 1024*1000000/44100= 22.32ms(單位為ms)

理論上的音視頻(播放)同步是這樣的:
由此得到了每一幀數據的持續時間,音視頻交叉存儲在容器中:一個時間軸:
時間軸:0   22.32   40     44.62    66.96    80     89.16      111.48    120       ................
音   頻 :0   22.32            44.62    66.96             89.16      111.48                ................
視   頻 :0              40                              80                                   120       ................
即視頻的持續時間相加 和音頻的持續時間相加作比較,誰小寫入哪個。
(自己的方法)
音頻數據(AAC 48k)        21.33     42.44  63.99          85.32
視頻數據(H264 25fps)              40                       80
時間軸                           ------------------------------------------->
(ts容器)循環做(寫一幀視頻,然后寫一幀音頻,然后視頻的時間減去音頻的時間,如果大於一幀音頻的時間,就多寫一幀音頻,知道視頻多出來的時間小於一幀音頻)
 
使用 Elecard Stream Analyzer 可以分析TS流

 


免責聲明!

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



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