直播主流的协议
直播都不陌生了,如今主流的協(xié)議分析的對比圖,個人見解。
| 協(xié)議 | httpflv | rtmp | hls | dash |
| 傳輸方式 | http流 | tcp流 | http | http |
| 視頻封裝格式 | flv | flv tag | Ts文件 | Mp4 3gp webm |
| 延時 | 低 | 低 | 高 | 高 |
| 數(shù)據(jù)分段 | 連續(xù)流 | 連續(xù)流 | 切片文件 | 切片文件 |
| Html5播放 | 可通過html5解封包播放(flv.js) | 不支持 | 可通過html5解封包播放(hls.js) | 如果dash文件列表是mp4webm文件,可直接播放 |
http_flv&rtmp
這兩個協(xié)議實(shí)際上傳輸數(shù)據(jù)是一樣的,數(shù)據(jù)都是flv文件的tag。http_flv是一個無限大的http流的文件,相比rtmp就只能直播,而rtmp還可以推流和更多的操作。但是http有個好處,就是是以80http通信的,穿透性強(qiáng),而且rtmp是非開放協(xié)議。
這兩個協(xié)議是如今直播平臺主選的直播方式,主要原因就是延時極低。
hls
hls是Apple推出的直播協(xié)議,是通過視頻流切片成文件片段來直播的。客戶端首先會請求一個m3u8文件,里面會有不同碼率的流,或者直接是ts文件列表,通過給出的ts文件地址去依次播放。在直播的時候,客戶端會不斷請求m3u8文件,檢查ts列表是否有新的ts切片。
這種方式直播的主要弊端就是延遲過大,最小延時為ts單個文件的時長。
dash
dash實(shí)際工作原理和hls一樣的,只不過不是mpegts文件,dash可以支持多種切片文件,比如mp4切片。當(dāng)為mp4切片,客戶端直接可用js控制利用html5直接播放。同樣的,dash有延時。
?
http-flv到底是怎么直播?
這里我們主要研究httpflv和hls。看了主流幾個web直播平臺,發(fā)現(xiàn)幾乎都是以httpflv為主來直播的,那么這么火httpflv到底是怎么達(dá)到直播的?
首先我們都知道在媒體格式里,幾乎都以h264視頻編碼。如今httpflv直播的flv數(shù)據(jù)也都是h264&aac為主的。flv封裝單元是以tag來表示的,一個tag可以是音頻tag或者視頻tag,或者腳本tag及其其他類型。
值得注意的是flv里面字節(jié)序是網(wǎng)絡(luò)字節(jié)序,
flv的格式:
| 1 | flvheader+[腳本tag(metadata)]+[第一個視頻tag(h264_spspps)]+[第一個音頻tag(aac_header)]+[第二個視頻tag(h264第一個關(guān)鍵幀)]+ 后面就是音頻和視頻tag交互存在 |
tag的格式:
| 1 | TYPE[1byte] + body size[3byte] + timestamp [4byte] +streamID [3byte] +[body data]+[previousTagSize 4byte] |
這里的timestamp是這樣存在的[?time tamp 3b,time tamp ex 1b]
h264視頻tagbody:
這里存儲的h264是沒有nal分割符的,在t的body里面是這樣存儲的,
| 1 | [isKeyFrame(1byte)]+0x01+[compositionTime 3byte]+[h264 size 4byte] |
compositionTime是h264編碼結(jié)果dts和pts之間的偏移。
aac視頻tag的body:
| 1 | 0xaf+0x01+aac raw |
以上就是flv格式的詳細(xì)說明,可以看出格式簡單,封裝的前后數(shù)據(jù)關(guān)聯(lián)很小,當(dāng)我們得到音頻頭和視頻頭,就可以從后面任意的一個關(guān)鍵幀開始播放。
當(dāng)然想要httpflv正常播放,不能缺少matedata,就是第一個腳本tag里面,這里面指定了分辨率,音視頻編碼格式等。
?httpflv直播實(shí)際上單純就是往客戶端發(fā)送flvtag,當(dāng)然是先發(fā)送flv前面那幾個關(guān)鍵的tag,然后第一幀是關(guān)鍵幀。
假如客戶端是obs推流軟件,以rtmp方式向服務(wù)器推流,在開始握手及其創(chuàng)建stream完成以及發(fā)送Metadata完成,及其一系列數(shù)據(jù)發(fā)送完畢,服務(wù)器就向obs發(fā)送publish result指令,此后,obs就開始向服務(wù)器推送flv tag數(shù)據(jù),開始直播,而服務(wù)器也得到了flv數(shù)據(jù)。
當(dāng)某個客戶端想要來獲取直播數(shù)據(jù),比如httpflv的方式來觀看直播,服務(wù)器會怎么做呢?
服務(wù)器會先發(fā)送前面幾個flvtag,header+metadata+spspps+aacheader,當(dāng)這幾個tag發(fā)送完畢,服務(wù)器會從直播流tag中,找到最新的視頻關(guān)鍵幀tag,從這個關(guān)鍵幀tag開發(fā)數(shù)據(jù),為什么呢?因為視頻流是IBP幀相互存在的,I是完整數(shù)據(jù),BP解碼都需要I幀和前面的幀,所以,正常視頻數(shù)據(jù),必須是從I幀開始發(fā)送的。這里就涉及到gop間距了,rtmp低延時秒開就是這個原理。當(dāng)然發(fā)送的時候,每個連接的tag開始時間戳戳要從0開始遞增的。
至此,httpflv客戶端就可以接受到flv流數(shù)據(jù),解碼觀看直播了。
?
hls到底是怎么直播?
hls就相對簡單粗暴了,服務(wù)器將直播流數(shù)據(jù)的h264和aac,封裝切片成一個個的ts文件。客戶端獲取直播的數(shù)據(jù)的時候,先請求m3u8文件,下面就是一個m3u8的文件,
| #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:5 ts最大時常5s #EXT-X-MEDIA-SEQUENCE:2 第一個ts文件的標(biāo)識 #EXTINF:4.993,//第一個ts文件,時長4.993,url地址/hls/2.ts /hls/2.ts #EXTINF:4.034, /hls/3.ts #EXTINF:4.980, /hls/4.ts |
如果是直播,客戶端會不停的去請求這個m3u8文件,當(dāng)這個列表有新的ts文件,客戶端會請求新的ts文件追加到本地播放序列。
關(guān)于ts的封包,ts的封裝格式要比flv更復(fù)雜,主要的數(shù)據(jù)單元是ts包,每個包有pid,一個包固定大小普通沒有crc的為188,主要分為三類ts包,pat,pmt,pes,pat就是第一個包,當(dāng)解析的時候會在ts包列表里找pid為0x0的包,就是pat包,pat大概作用就是入口的意思,pat里面有pmt包的pid,pmt里面存儲的是流的包的pid,比如指定音頻包pid是0x102,視頻包pid是0x101,后面的0x102和0x101的包就是pes包了,將pes包解析并合并出原始流,就能解碼播放了。
總結(jié)
- 上一篇: nginx 心得
- 下一篇: http 状态码 504 502