HLS協(xié)議及TS封裝

HLS協(xié)議及TS封裝

一莺戒、HLS協(xié)議

HLS協(xié)議由蘋(píng)果公司提出并推廣浸赫,來(lái)自維基百科的定義。

HTTP Live Streaming(縮寫(xiě)是HLS)是一個(gè)由蘋(píng)果公司提出的基于HTTP流媒體網(wǎng)絡(luò)傳輸協(xié)議。是蘋(píng)果公司QuickTime
X
iPhone軟件系統(tǒng)的一部分更胖。它的工作原理是把整個(gè)流分成一個(gè)個(gè)小的基于HTTP的文件來(lái)下載,每次只下載一些隔显。當(dāng)媒體流正在播放時(shí)却妨,客戶端可以選擇從許多不同的備用源中以不同的速率下載同樣的資源,允許流媒體會(huì)話適應(yīng)不同的數(shù)據(jù)速率括眠。在開(kāi)始一個(gè)流媒體會(huì)話時(shí)彪标,客戶端會(huì)下載一個(gè)包含元數(shù)據(jù)的extended
M3U (m3u8)playlist
文件,用于尋找可用的媒體流掷豺。
HLS只請(qǐng)求基本的HTTP報(bào)文捞烟,與實(shí)時(shí)傳輸協(xié)議(RTP)不同,HLS可以穿過(guò)任何允許HTTP數(shù)據(jù)通過(guò)的防火墻或者代理服務(wù)器当船。它也很容易使用內(nèi)容分發(fā)網(wǎng)絡(luò)來(lái)傳輸媒體流题画。
蘋(píng)果公司把HLS協(xié)議作為一個(gè)互聯(lián)網(wǎng)草案(逐步提交),在第一階段中已作為一個(gè)非正式的標(biāo)準(zhǔn)提交到IETF德频。但是苍息,即使蘋(píng)果偶爾地提交一些小的更新,IETF卻沒(méi)有關(guān)于制定此標(biāo)準(zhǔn)的有關(guān)進(jìn)一步的動(dòng)作。[1]

1.1.協(xié)議簡(jiǎn)介

Apple推出的直播協(xié)議竞思,是通過(guò)視頻流切片成文件片段來(lái)直播的表谊。客戶端首先會(huì)請(qǐng)求一個(gè)m3u8文件盖喷,里面會(huì)有不同碼率的流爆办,或者直接是ts文件列表,通過(guò)給出的ts文件地址去依次播放传蹈。在直播的時(shí)候押逼,客戶端會(huì)不斷請(qǐng)求m3u8文件步藕,檢查ts列表是否有新的ts切片惦界。

HLS協(xié)議規(guī)定:

  • 視頻的封裝格式是TS。
  • 視頻的編碼格式為H264咙冗,音頻編碼格式為MP3沾歪、AAC或者AC-3。
  • 除了TS視頻文件本身雾消,還定義了用來(lái)控制播放的m3u8文件(文本文件)灾搏。

獲取音視頻進(jìn)行HLS打包,H264+AAC的流媒體切片立润,提供給WEB服務(wù)器進(jìn)行HLS流媒體發(fā)布狂窑,切片后:一個(gè)M3U8文件 和 多個(gè).ts文件,M3U8是一種可擴(kuò)展的播放列表文件格式桑腮。它是一個(gè)包含UTF-8編碼文字的m3u播放列表泉哈。m3u是包含媒體文件URL的一個(gè)事實(shí)上的播放列表標(biāo)準(zhǔn),編碼還是h264破讨。這種格式被用來(lái)作為HTTP Live 媒體流索引文件的格式丛晦。M3u8是一種視頻列表格式,里面有真正的視頻鏈接提陶,在其中可以再嵌套一層m3u8烫沙。
實(shí)現(xiàn)HLS直播:

  1. 采集視頻源和音頻源數(shù)據(jù)
  2. 對(duì)原始數(shù)據(jù)進(jìn)行H264編碼和AAC編碼
  3. 視頻和音頻數(shù)據(jù)封裝為MPEG-TS包
  4. HLS分段生成策略及m3u8索引文件
  5. HTTP傳輸協(xié)議

1.2.m3u8文件協(xié)議

m3u8文件結(jié)構(gòu):

#EXTM3U                         //m3u文件頭,必須放在第一行
#EXT-X-VERSION:3                  
#EXT-X-MEDIA-SEQUENCE:2         //第一個(gè)TS分片的序列號(hào)  
#EXT-X-TARGETDURATION:5         //每個(gè)分片TS的最大的時(shí)長(zhǎng)  
#EXT-X-ALLOW-CACHE:             //是否允許cache  
#EXT-X-ENDLIST                  //m3u8文件結(jié)束符 表示視頻已經(jīng)結(jié)束 有這個(gè)標(biāo)志同時(shí)也說(shuō)明當(dāng)前流是一個(gè)非直播流
#EXT-X-PLAYLIST-TYPE:VOD/Live   //VOD表示當(dāng)前視頻流不是一個(gè)直播流隙笆,而是點(diǎn)播流(也就是視頻的全部ts文件已經(jīng)生成)
#EXTINF:                        //extra info锌蓄,分片TS的信息,如時(shí)長(zhǎng)撑柔,帶寬等

一級(jí)文件:index.m3u8

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1064000
1000kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=564000
500kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=282000
250kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2128000
2000kbps.m3u8

二級(jí)文件:2000kbps.m3u8

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:5
2000kbps-0002.ts
#EXTINF:4.089
2000kbps-0003.ts
#EXTINF:4.989
2000kbps-0004.ts
...

#EXTINF:4.979
2000kbps-0100.ts
#ZEN-TOTAL-DURATION:491.66667
#ZEN-AVERAGE-BANDWIDTH:
#ZEN-MAXIMUM-BANDWIDTH:
#EXT-X-ENDLIST 

1.3.服務(wù)端與客戶端邏輯

服務(wù)端邏輯:

  • 1瘸爽、將媒體源切片成 Media Segment, 應(yīng)該優(yōu)先從可以高效解碼的時(shí)間點(diǎn)來(lái)進(jìn)行切片(如: I-frame).
  • 2、為每一個(gè) Media Segment 生成 URI.
  • 3乏冀、Server 需要支持 “gzip” 方式壓縮文本內(nèi)容.
  • 4蝶糯、創(chuàng)建一個(gè) Media Playlist 索引文件, EXT-X-VERSION 不要高于他需要的版本, 來(lái)提供更好的兼容性.
  • 5、Server 不能隨便修改 Media Playlist, 除了 Append 文本到文件末尾, 按順序移除 Media Segment URIs, 增長(zhǎng) EXT-X-MEDIA-SEQUENCE 和 EXT-X-DISCONTINUITY-SEQUENCE, 添加 EXT-X-ENDLIST 到文件尾.
  • 6辆沦、在最后添加 EXT-X-ENDLIST tag, 來(lái)減少 Client reload Playlist 的次數(shù).
  • 7昼捍、注意點(diǎn)播與直播服務(wù)器不同的地方是, 直播的 m3u8 文件會(huì)不斷更新, 而點(diǎn)播的 m3u8 文件是不會(huì)變的, 只需要客戶端在開(kāi)始時(shí)請(qǐng)求一次即可.

客戶端邏輯:

  • 1识虚、客戶端通過(guò) URI 獲取 Playlist. 如果是 Master Playlist, 客戶端可以選擇一個(gè) Variant Stream 來(lái)播放.
  • 2、客戶端檢查 EXT-X-VERSION 版本是否滿足.
  • 3妒茬、客戶端應(yīng)該忽略不可識(shí)別的 tags, 忽略不可識(shí)別的屬性鍵值對(duì).
  • 4担锤、加載 Media Playlist file.
  • 5、 播放 Media Playlist file.
  • 6乍钻、重加載 Media Playlist file.
  • 7肛循、決定下一次要加載的 Media Segment.

優(yōu)點(diǎn):

  • 客戶端支持簡(jiǎn)單, 只需要支持 HTTP 請(qǐng)求即可, HTTP 協(xié)議無(wú)狀態(tài), 只需要按順序下載媒體片段即可.
  • 使用 HTTP 協(xié)議網(wǎng)絡(luò)兼容性好, HTTP 數(shù)據(jù)包也可以方便地通過(guò)防火墻或者代理服務(wù)器, CDN 支持良好.
  • Apple 的全系列產(chǎn)品支持, 由于 HLS 是蘋(píng)果提出的, 所以在 Apple 的全系列產(chǎn)品包括 iphone, ipad, safari 都不需要安裝任何插件就可以原生支持播放 HLS, 現(xiàn)在, Android 也加入了對(duì) HLS 的支持.
  • 自帶多碼率自適應(yīng), Apple 在提出 HLS 時(shí), 就已經(jīng)考慮了碼流自適應(yīng)的問(wèn)題.

缺點(diǎn):

  • 相比 RTMP 這類長(zhǎng)連接協(xié)議, 延時(shí)較高, 難以用到互動(dòng)直播場(chǎng)景.
  • 對(duì)于點(diǎn)播服務(wù)來(lái)說(shuō), 由于 TS 切片通常較小, 海量碎片在文件分發(fā), 一致性緩存, 存儲(chǔ)等方面都有較大挑戰(zhàn).

1.4.應(yīng)用

HLS目前廣泛應(yīng)用于點(diǎn)播和直播領(lǐng)域。
如果是直播银择,客戶端會(huì)不停的去請(qǐng)求這個(gè)m3u8文件多糠,當(dāng)這個(gè)列表有新的ts文件,客戶端會(huì)請(qǐng)求新的ts文件追加到本地播放序列浩考。
在HTML5頁(yè)面上使用HLS非常簡(jiǎn)單

<video src="index.m3u8" controls></video>
或
<video controls>
    <source src="index.m3u8"></source>
</video>

二夹孔、TS封包

2.1概念

ts流最早應(yīng)用于數(shù)字電視領(lǐng)域,其格式非常復(fù)雜包含的配置信息表多達(dá)十幾個(gè)析孽,視頻格式主要是mpeg2搭伤。蘋(píng)果公司發(fā)明的http live stream流媒體是基于ts文件的,不過(guò)他大大簡(jiǎn)化了傳統(tǒng)的ts流袜瞬,只需要2個(gè)最基本的配置表PAT和PMT怜俐,再加上音視頻內(nèi)容就可以了,hls流媒體視頻編碼的主要格式為h264/mpeg4邓尤,音頻為aac/mp3拍鲤。

關(guān)于ts的封包,ts的封裝格式要比f(wàn)lv更復(fù)雜裁赠,主要的數(shù)據(jù)單元是ts包殿漠,每個(gè)包有pid,一個(gè)包固定大小普通沒(méi)有crc的為188佩捞,主要分為三類ts包绞幌,pat,pmt一忱,pes莲蜘,pat就是第一個(gè)包,當(dāng)解析的時(shí)候會(huì)在ts包列表里找pid為0x0的包帘营,就是pat包票渠,pat大概作用就是入口的意思,pat里面有pmt包的pid芬迄,pmt里面存儲(chǔ)的是流的包的pid问顷,比如指定音頻包pid是0x102,視頻包pid是0x101,后面的0x102和0x101的包就是pes包了杜窄,將pes包解析并合并出原始流送悔,就能解碼播放了芥备。具體封包格式 詳解參考一履婉,參考二

ES(Elementary Stream)流是基本碼流程癌,包含音頻、視頻扫外、數(shù)據(jù)的連續(xù)碼流莉钙。直接從編碼器出來(lái)的數(shù)據(jù)流,可以是編碼過(guò)的視頻數(shù)據(jù)流(H.264,MJPEG等)筛谚,音頻數(shù)據(jù)流(AAC)磁玉,或其他編碼數(shù)據(jù)流的統(tǒng)稱。ES流經(jīng)過(guò)PES打包器之后刻获,被轉(zhuǎn)換成PES包蜀涨。

PES(Packet Elementary Stream 分組的ES)ES形成的分組稱為PES分組瞎嬉,是用來(lái)傳遞ES的一種數(shù)據(jù)結(jié)構(gòu)蝎毡。PES流是ES流經(jīng)過(guò)PES打包器處理后形成的數(shù)據(jù)流,在這個(gè)過(guò)程中完成了將ES流分組氧枣、打包沐兵、加入包頭信息等操作(對(duì)ES流的第一次打包)。PES流的基本單位是PES包便监。PES包由包頭和payload組成扎谎。

TS(Transport Stream)流,也叫傳輸流烧董。是在pes層上加入了數(shù)據(jù)流識(shí)別和傳輸?shù)谋匾畔⒒侔小J怯晒潭ㄩL(zhǎng)度的188字節(jié)的包組成。含有獨(dú)立是一個(gè)或者多個(gè)program,一個(gè)program又可以包含多個(gè)視頻逊移,音頻和文字信息的ES流预吆。每個(gè)ES流會(huì)有不同的PID標(biāo)示。為了分析這些ES流胳泉,TS有些固定的PID來(lái)間隔發(fā)送Program和ES信息表格:PAT表和PMT表拐叉。

2.2.TS文件

ts文件分為三次:ts層(Transport Stream)、pes層(Packet Elemental Stream)扇商、es層(Elementary Stream)凤瘦。es層就是音視頻數(shù)據(jù),pes層是在音視頻數(shù)據(jù)上加了時(shí)間戳等數(shù)據(jù)幀的說(shuō)明信息案铺,ts層是在pes層上加入了數(shù)據(jù)流識(shí)別和傳輸?shù)谋匾畔ⅰ?/p>

TS流:                      
  +-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  TS   |  =  |  Packet 1 |  Packet 2 |  Packet 3 |    ...    | Packet n-1|  Packet n |
  +-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  
一個(gè)Packet:             4bytes             184bytes         
  +-+-+-+-+-+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  Packet | =  | Packet header |       Packet data       |
  +-+-+-+-+-+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.ts層

ts包(Packet)大小固定為188字節(jié)蔬芥,ts層分為三個(gè)部分:ts header、adaptation field、payload笔诵。ts header固定4個(gè)字節(jié)涤姊;adaptation field可能存在也可能不存在,主要作用是給不足188字節(jié)的數(shù)據(jù)做填充嗤放;payload是pes數(shù)據(jù)思喊。

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |  adaptation field |          payload(pes)       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.1.ts header

大小 說(shuō)明
sync_byte 8bit 同步字節(jié),固定為0x47
transport_error_indicator 1bit 傳輸錯(cuò)誤指示符次酌,表明在ts頭的adapt域后由一個(gè)無(wú)用字節(jié)恨课,通常都為0,這個(gè)字節(jié)算在adapt域長(zhǎng)度內(nèi)
payload_unit_start_indicator 1bit 負(fù)載單元起始標(biāo)示符岳服,一個(gè)完整的數(shù)據(jù)包開(kāi)始時(shí)標(biāo)記為1
transport_priority 1bit 傳輸優(yōu)先級(jí)剂公,0為低優(yōu)先級(jí),1為高優(yōu)先級(jí)吊宋,通常取0
pid 13bit pid值
transport_scrambling_control 2bit 傳輸加擾控制纲辽,00表示未加密
adaptation_field_control 2bit 是否包含自適應(yīng)區(qū),‘00’保留璃搜;‘01’為無(wú)自適應(yīng)域拖吼,僅含有效負(fù)載;‘10’為僅含自適應(yīng)域这吻,無(wú)有效負(fù)載吊档;‘11’為同時(shí)帶有自適應(yīng)域和有效負(fù)載。
continuity_counter 4bit 遞增計(jì)數(shù)器唾糯,從0-f怠硼,起始值不一定取0,但必須是連續(xù)的

??????ts層的內(nèi)容是通過(guò)PID值來(lái)標(biāo)識(shí)的移怯,主要內(nèi)容包括:PAT表香璃、PMT表、音頻流舟误、視頻流葡秒。解析ts流要先找到PAT表,只要找到PAT就可以找到PMT脐帝,然后就可以找到音視頻流了同云。PAT表的PID值固定為0。PAT表和PMT表需要定期插入ts流堵腹,因?yàn)橛脩綦S時(shí)可能加入ts流炸站,這個(gè)間隔比較小,通常每隔幾個(gè)視頻幀就要加入PAT和PMT疚顷。PAT和PMT表是必須的旱易,還可以加入其它表如SDT(業(yè)務(wù)描述表)等禁偎,不過(guò)hls流只要有PAT和PMT就可以播放了。

  • PAT表:他主要的作用就是指明了PMT表的PID值阀坏。
  • PMT表:他主要的作用就是指明了音視頻流的PID值如暖。
  • 音頻流/視頻流:承載音視頻內(nèi)容。

2.2.1.2.adaptation field

大小 說(shuō)明
adaptation_field_length 1Byte 自適應(yīng)域長(zhǎng)度忌堂,后面的字節(jié)數(shù)
flag 1Byte 取0x50表示包含PCR或0x40表示不包含PCR
pcr 5Byte Program Clock Reference盒至,節(jié)目時(shí)鐘參考,用于恢復(fù)出與編碼端一致的系統(tǒng)時(shí)序時(shí)鐘STC(System Time Clock)士修。
stuffing_bytes xByte 填充字節(jié)枷遂,取值0xff

??????自適應(yīng)區(qū)的長(zhǎng)度要包含傳輸錯(cuò)誤指示符標(biāo)識(shí)的一個(gè)字節(jié)。pcr是節(jié)目時(shí)鐘參考棋嘲,pcr酒唉、dts、pts都是對(duì)同一個(gè)系統(tǒng)時(shí)鐘的采樣值沸移,pcr是遞增的痪伦,因此可以將其設(shè)置為dts值,音頻數(shù)據(jù)不需要pcr雹锣。如果沒(méi)有字段网沾,ipad是可以播放的,但vlc無(wú)法播放笆制。打包ts流時(shí)PAT和PMT表是沒(méi)有adaptation field的绅这,不夠的長(zhǎng)度直接補(bǔ)0xff即可。視頻流和音頻流都需要加adaptation field在辆,通常加在一個(gè)幀的第一個(gè)ts包和最后一個(gè)ts包里,中間的ts包不加度苔。

PAT/PMT類型包(Packet)
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |    PAT/PMT    |   Stuffing Bytss  |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

視頻/音頻類型包(Packet),一幀視頻/音頻數(shù)據(jù)被拆分成N個(gè)Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |   adaptation field    |      payload(pes 1)     |-->第1個(gè)Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |              payload(pes 2)                     |-->第2個(gè)Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |                   ...                           |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |             payload(pes n-1)                    |-->第n-1個(gè)Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |   adaptation field    |      payload(pes n)     |-->第n個(gè)Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.3.PAT(Program Associate Table)格式 節(jié)目關(guān)聯(lián)表

大小 說(shuō)明
table_id 8bit PAT表固定為0x00
section_syntax_indicator 1bit 固定為二進(jìn)制1
zero 1bit 固定為二進(jìn)制0
reserved 2bit 固定為二進(jìn)制11(3)
section_length 12bit 后面數(shù)據(jù)的長(zhǎng)度
transport_stream_id 16bit 傳輸流ID匆篓,固定為0x0001
reserved 2bit 固定為二進(jìn)制11(3)
version_number 5bit 版本號(hào),固定為二進(jìn)制00000寇窑,如果PAT有變化則版本號(hào)加1
current_next_indicator 1bit 固定為二進(jìn)制1鸦概,表示這個(gè)PAT表可以用,如果為0則要等待下一個(gè)PAT表
section_number 8bit 固定為0x00
last_section_number 8bit 固定為0x00
開(kāi)始循環(huán)
program_number 16bit 節(jié)目號(hào)為0x0000時(shí)表示這是NIT甩骏,節(jié)目號(hào)為0x0001時(shí),表示這是PMT
reserved 3bit 固定為二進(jìn)制111(7)
PID 13bit 節(jié)目號(hào)對(duì)應(yīng)內(nèi)容的PID值
結(jié)束循環(huán)
CRC32 32bit 前面數(shù)據(jù)的CRC32校驗(yàn)碼

2.2.1.4.PMT(Program Map Table)格式 節(jié)目映射表

大小 說(shuō)明
table_id 8bit PMT表取值隨意窗市,0x02
section_syntax_indicator 1bit 固定為二進(jìn)制1
zero 1bit 固定為二進(jìn)制0
reserved 2bit 固定為二進(jìn)制11(3)
section_length 12bit 后面數(shù)據(jù)的長(zhǎng)度
program_number 16bit 頻道號(hào)碼,表示當(dāng)前的PMT關(guān)聯(lián)到的頻道饮笛,取值0x0001
reserved 2bit 固定為二進(jìn)制11(3)
version_number 5bit 版本號(hào)咨察,固定為00000,如果PAT有變化則版本號(hào)加1
current_next_indicator 1bit 固定為二進(jìn)制1
section_number 8bit 固定為0x00
last_section_number 8bit 固定為0x00
reserved 3bit 固定為二進(jìn)制111(7)
PCR_PID 13bit PCR(節(jié)目參考時(shí)鐘)所在TS分組的PID福青,指定為視頻PID
reserved 4bit 固定為二進(jìn)制1111(15)
program_info_length 12bit 節(jié)目描述信息摄狱,指定為0x000表示沒(méi)有
開(kāi)始循環(huán)
stream_type 8bit 流類型脓诡,標(biāo)志是Video還是Audio還是其他數(shù)據(jù),h.264編碼對(duì)應(yīng)0x1b媒役,aac編碼對(duì)應(yīng)0x0f祝谚,mp3編碼對(duì)應(yīng)0x03
reserved 3bit 固定為二進(jìn)制111(7)
elementary_PID 13bit 與stream_type對(duì)應(yīng)的PID
reserved 4bit 固定為二進(jìn)制1111(15)
ES_info_length 12bit 描述信息,指定為0x000表示沒(méi)有
結(jié)束循環(huán)
CRC32 32bit 前面數(shù)據(jù)的CRC32校驗(yàn)碼

2.2.2.pes層

pes層(ts層中payload)是在每一個(gè)視頻/音頻幀上加入了時(shí)間戳等信息酣衷,pes包內(nèi)容很多交惯,我們只留下最常用的。

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header|  optional pes header    |      pes payload      |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      6Byte         3~259Byte                  max 65526Byte
大小 說(shuō)明
pes start code 3Byte 開(kāi)始碼穿仪,固定為0x000001
stream id 1Byte 音頻取值(0xc0-0xdf)商玫,通常為0xc0 視頻取值(0xe0-0xef),通常為0xe0
pes packet length 2Byte 后面pes數(shù)據(jù)的長(zhǎng)度牡借,0表示長(zhǎng)度不限制拳昌,只有視頻數(shù)據(jù)長(zhǎng)度會(huì)超過(guò)0xffff
flag 1Byte 通常取值0x80,表示數(shù)據(jù)不加密钠龙、無(wú)優(yōu)先級(jí)炬藤、備份的數(shù)據(jù)
flag 1Byte 取值0x80表示只含有pts,取值0xc0表示含有pts和dts
pes data length 1Byte 后面數(shù)據(jù)的長(zhǎng)度碴里,取值5或10
pts 5Byte 33bit值
dts 5Byte 33bit值

??????pts是顯示時(shí)間戳沈矿、dts是解碼時(shí)間戳,視頻數(shù)據(jù)兩種時(shí)間戳都需要咬腋,音頻數(shù)據(jù)的pts和dts相同羹膳,所以只需要pts。有pts和dts兩種時(shí)間戳是B幀引起的根竿,I幀和P幀的pts等于dts陵像。如果一個(gè)視頻沒(méi)有B幀,則pts永遠(yuǎn)和dts相同寇壳。從文件中順序讀取視頻幀醒颖,取出的幀順序和dts順序相同。dts算法比較簡(jiǎn)單壳炎,初始值 + 增量即可泞歉,pts計(jì)算比較復(fù)雜,需要在dts的基礎(chǔ)上加偏移量匿辩。
??????音頻的pes中只有pts(同dts)腰耙,視頻的I、P幀兩種時(shí)間戳都要有铲球,視頻B幀只要pts(同dts)挺庞。打包pts和dts就需要知道視頻幀類型,但是通過(guò)容器格式我們是無(wú)法判斷幀類型的睬辐,必須解析h.264內(nèi)容才可以獲取幀類型挠阁。

舉例說(shuō)明:
    ------------------------------>
    I     P     B     B     B     P
    1     2     3     4     5     6   讀取順序
    1     2     3     4     5     6   dts順序
    1     5     3     2     4     6   pts順序
    
點(diǎn)播視頻dts算法:
dts = 初始值 + 90000 / video_frame_rate宾肺,初始值可以隨便指定,但是最好不要取0侵俗,video_frame_rate就是幀率锨用,比如23、30隘谣。
pts和dts是以timescale為單位的榛瓮,1s = 90000 time scale , 一幀就應(yīng)該是90000/video_frame_rate 個(gè)timescale童谒。
用一幀的timescale除以采樣頻率就可以轉(zhuǎn)換為一幀的播放時(shí)長(zhǎng)

點(diǎn)播音頻dts算法:
dts = 初始值 + (90000 * audio_samples_per_frame) / audio_sample_rate,audio_samples_per_frame這個(gè)值與編解碼相關(guān),aac取值1024啊送,mp3取值1158隔披,audio_sample_rate是采樣率收津,比如24000裳扯、41000。AAC一幀解碼出來(lái)是每聲道1024個(gè)sample噪珊,也就是說(shuō)一幀的時(shí)長(zhǎng)為1024/sample_rate秒晌缘。所以每一幀時(shí)間戳依次0,1024/sample_rate痢站,...磷箕,1024*n/sample_rate秒。

直播視頻的dts和pts應(yīng)該直接用直播數(shù)據(jù)流中的時(shí)間阵难,不應(yīng)該按公式計(jì)算岳枷。

2.2.3.es層

es層(pes payload)指的就是音視頻數(shù)據(jù)。

video:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | start code(4 byte)| nalu header(1 byte) |      h264 data(x byte)        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

audio:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | adts header(7 byte) |      aac data(x byte)       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.3.1.h.264視頻

??????打包h.264數(shù)據(jù)我們必須給視頻數(shù)據(jù)加上一個(gè)nalu(Network Abstraction Layer unit)呜叫,nalu包括start code和nalu header空繁,start code固定為0x00000001(幀開(kāi)始)或0x000001(幀中)。h.264的數(shù)據(jù)是由slice組成的怀偷,slice的內(nèi)容包括:視頻家厌、sps、pps等椎工。nalu type決定了后面的h.264數(shù)據(jù)內(nèi)容。

nalu header:
   0 1 2 3 4 5 6 7
  +-+-+-+-+-+-+-+-+
  |F|NRI|   Type  |          
  +-+-+-+-+-+-+-+-+
 
  F:   占1bit,forbidden_zero_bit蜀踏,h.264規(guī)定必須取0维蒙,禁止位,當(dāng)網(wǎng)絡(luò)發(fā)現(xiàn)NAL單元有比特錯(cuò)誤時(shí)可設(shè)置該比特為1果覆,以便接收方糾錯(cuò)或丟掉該單元颅痊。
  NRI: 占2bit,nal_ref_idc,取值0~3局待,指示這個(gè)nalu的重要性斑响,I幀菱属、sps、pps通常取3舰罚,P幀通常取2纽门,B幀通常取0,nal重要性指示营罢,標(biāo)志該NAL單元的重要性赏陵,值越大,越重要饲漾,解碼器在解碼處理不過(guò)來(lái)的時(shí)候蝙搔,可以丟掉重要性為0的NALU。
  Type:占5bit, nal_unit_type:0=未使用 1=非IDR圖像片考传,IDR指關(guān)鍵幀
                             2=片分區(qū)A 3=片分區(qū)B
                             4=片分區(qū)C 5=IDR圖像片吃型,即關(guān)鍵幀
                             6=補(bǔ)充增強(qiáng)信息單元(SEI) 7=SPS序列參數(shù)集
                             8=PPS圖像參數(shù)集 9=分解符
                             10=序列結(jié)束 11=碼流結(jié)束
                             12=填充
                             13~23=保留 24~31=未使用
             
  打包es層數(shù)據(jù)時(shí)pes頭和es數(shù)據(jù)之間要加入一個(gè)type=9的nalu,關(guān)鍵幀slice前必須要加入type=7和type=8的nalu僚楞,而且是緊鄰                             
  
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header| nalu(0x09)| 1byte |  nalu |     | nalu(0x67)|     | nalu(0x68)|     | nalu(0x65)|     |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             隨意     其他   內(nèi)容       SPS     內(nèi)容     PPS       內(nèi)容      I幀      內(nèi)容
                             
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header| nalu(0x09)| 1byte |  nalu |     | nalu(0x41)|     |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             隨意     其他   內(nèi)容       P幀     內(nèi)容

2.2.3.1.aac音頻

??????打包aac音頻必須加上一個(gè)adts(Audio Data Transport Stream)頭勤晚,共7Byte,adts包括fixed_header和variable_header兩部分镜硕,各28bit运翼。
fixed_header

大小 說(shuō)明
syncword 12bit 固定為0xfff
id 1bit 0表示MPEG-4,1表示MPEG-2
layer 2bit 固定為00
protection_absent 1bit 固定為1
profile 2bit 取值0~3,1表示aac
sampling_frequency_index 4bit 表示采樣率兴枯,0: 96000 Hz血淌,1: 88200 Hz,2: 64000 Hz财剖,3:48000 Hz悠夯,4: 44100 Hz,5: 32000 Hz躺坟,6: 24000 Hz沦补,7: 22050 Hz,8: 16000 Hz咪橙,9: 12000 Hz夕膀,10: 11025 Hz,11: 8000 Hz美侦,12: 7350 Hz
private_bit 1bit 固定為0
channel_configuration 3bit 取值0~7产舞,1: 1 channel: front-center,2: 2 channels: front-left, front-right菠剩,3: 3 channels: front-center, front-left, front-right易猫,4: 4 channels: front-center, front-left, front-right, back-center
original_copy 1bit 固定為0
home 1bit 固定為0

variable_header

大小 說(shuō)明
copyright_identification_bit 1bit 固定為0
copyright_identification_start 1bit 固定為0
aac_frame_length 13bit 包括adts頭在內(nèi)的音頻數(shù)據(jù)總長(zhǎng)度
adts_buffer_fullness 11bit 固定為0x7ff
number_of_raw_data_blocks_in_frame 2bit 固定為00

2.2.4.ts打包流程圖

    一個(gè)PAT包含整個(gè)TS流的信息,其中里面有一張表具壮,比較重要的兩個(gè)屬性 program_number和program_map_PID准颓,可能出現(xiàn)多對(duì)哈蝇,
每一對(duì)program_number表示一個(gè)節(jié)目,而與該program_number對(duì)應(yīng)的program_map_PID則表示該節(jié)目對(duì)應(yīng)的流信息應(yīng)該放在一個(gè)PMT表中攘已,
而該P(yáng)MT表的PID應(yīng)該與這里的program_map_PID相等炮赦。
    一個(gè)PMT中描述了流的類型,其中0x0f表示AAC音頻贯被,而0x1b表示H264視頻眼五,除這兩種之外還有其他流,例如字幕彤灶。
elementay_PID表示該流的數(shù)據(jù)應(yīng)該存放在以該P(yáng)ID為表示的TS包中看幼。

  +-+-+-+-+-+-+-+-+-+-+-+
  | PAT                 | 
  |                     |
  | program_number  5   |___
  | program_map_PID 10  |   |
  |                     |   |
  | program_number  6   |___|__  
  | program_map_PID 11  |   |  |
  |                     |   |  |  
  | program_number  7   |   |  |   
  | program_map_PID 12  |   |  |
  |                     |   |  |
  |         ...         |   |  |
  |                     |   |  |
  +-+-+-+-+-+-+-+-+-+-+-+   |  |
                            |  |
  +-+-+-+-+-+-+-+-+-+-+-+   |  |
  | PMT                 |   |  |
  | TS Header PID = 10  |<——   |
  |                     |      |
  | stream_type    0x0f |______|__________________0x0f表示AAC音頻,下方AAC數(shù)據(jù)打包PID=20,   
  | elementary_PID 20   |      |
  | stream_type    0x1b |______|__________________0x1b表示H264視頻幌陕,下方H264數(shù)據(jù)打包PID=22 
  | elementary_PID 22   |      |
  |                     |      |  
  +-+-+-+-+-+-+-+-+-+-+-+      |
                               |
  +-+-+-+-+-+-+-+-+-+-+-+      |
  | PMT                 |      | 
  | TS Header PID = 6   |<————— 
  |                     |
  | stream_type    0x0f |   
  | elementary_PID 23   |
  | stream_type    0x1b |
  | elementary_PID 24   |
  |                     |  
  +-+-+-+-+-+-+-+-+-+-+-+



裸ACC數(shù)據(jù):
  +-+-+-+-+-+-+-+-+-+-+-+
  |         AAC         |          
  +-+-+-+-+-+-+-+-+-+-+-+
添加PES頭的ACC數(shù)據(jù):
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | AAC PES |         AAC         |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
添加TS頭將PES分割之后的TS包诵姜,假設(shè)正好分割成2個(gè)TS包,包大小固定188字節(jié)搏熄,不夠用adaptation域填充一般填充0xFF:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |TS | AAC PES |  AAC 1  |TS | adaptation|    AAC 2    |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |- - - - Packet 1 - - - |- - - - - Packet 2 - - - - - |
  <假設(shè) PID = 20 的TS包>            
  

裸H264數(shù)據(jù)棚唆,一幀:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |              H264             |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
添加PES頭之后的H264數(shù)據(jù),一幀表示一個(gè)PES包:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | H264 PES|           H264                |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
將一個(gè)PES包分割之后心例,分別添加TS頭之后的TS包宵凌,這里假設(shè)分割成3個(gè)TS包,每個(gè)包固定大小188字節(jié)(包含TS包頭在內(nèi))止后,
最后一個(gè)包不夠188字節(jié)使用adaptaion域填充0xFF:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |TS | H264 PES| H264 1|TS |  H264 2     |TS | adaptation|  H264 3 |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |- - - Packet 1 - - - |- - Packet 2 - - | - - - - Packet 3 - - - -|
  <假設(shè) PID = 22 的TS包>
  
  
  


參考

蘋(píng)果官方文檔
HLS標(biāo)準(zhǔn)協(xié)議
維基百科
https://blog.csdn.net/yuan1125/article/details/51540918
https://blog.csdn.net/max_min_go/article/details/39463675

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞎惫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子译株,更是在濱河造成了極大的恐慌瓜喇,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歉糜,死亡現(xiàn)場(chǎng)離奇詭異乘寒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)匪补,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)伞辛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人夯缺,你說(shuō)我怎么就攤上這事始锚。” “怎么了喳逛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棵里。 經(jīng)常有香客問(wèn)我润文,道長(zhǎng)姐呐,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任典蝌,我火速辦了婚禮曙砂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骏掀。我一直安慰自己鸠澈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布截驮。 她就那樣靜靜地躺著笑陈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葵袭。 梳的紋絲不亂的頭發(fā)上涵妥,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音坡锡,去河邊找鬼蓬网。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鹉勒,可吹牛的內(nèi)容都是我干的帆锋。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼禽额,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锯厢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起绵疲,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哲鸳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后盔憨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體徙菠,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年郁岩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婿奔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡问慎,死狀恐怖萍摊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情如叼,我是刑警寧澤冰木,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響踊沸,放射性物質(zhì)發(fā)生泄漏歇终。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一逼龟、第九天 我趴在偏房一處隱蔽的房頂上張望评凝。 院中可真熱鬧,春花似錦腺律、人聲如沸奕短。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翎碑。三九已至,卻和暖如春榴捡,著一層夾襖步出監(jiān)牢的瞬間杈女,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工吊圾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留达椰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓项乒,卻偏偏與公主長(zhǎng)得像啰劲,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子檀何,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容