直播伺服器簡單實現 http_flv和hls 內網直播桌面
直播都不陌生了,如今主流的協議分析的對比圖,個人見解。
協議 |
httpflv |
rtmp |
hls |
dash |
傳輸層 |
http流 |
tcp流 |
http |
http |
視訊格式 |
flv |
flv tag |
Ts檔案 |
Mp4 3gp webm |
延時 |
低 |
低 |
高 |
高 |
資料分段 |
連續流 |
連續流 |
切片檔案 |
切片檔案 |
Html5播放 |
可通過html5解封包播放(flv.js) |
不支援 |
可通過html5解封包播放(hls.js) |
如果dash檔案列表是mp4webm檔案,可直接播放 |
http_flv&rtmp
這兩個協議實際上傳輸資料是一樣的,資料都是flv檔案的tag。http_flv是一個無限大的http流的檔案,相比rtmp就只能直播,而rtmp還可以推流和更多的操作。但是http有個好處,就是是以80http通訊的,穿透性強,而且rtmp是非開放協議。
這兩個協議是如今直播平臺主選的直播方式,主要原因就是延時極低。
hls
hls是Apple推出的直播協議,是通過視訊流切片成檔案片段來直播的。客戶端首先會請求一個m3u8檔案,裡面會有不同位元速率的流,或者直接是ts檔案列表,通過給出的ts檔案地址去依次播放。在直播的時候,客戶端會不斷請求m3u8檔案,檢查ts列表是否有新的ts切片。
這種方式直播的主要弊端就是延遲過大,最小延時為ts單個檔案的時長。
dash
dash實際工作原理和hls一樣的,只不過不是mpegts檔案,dash可以支援多種切片檔案,比如mp4切片。當為mp4切片,客戶端直接可用js控制利用html5直接播放。同樣的,dash有延時。
http-flv到底是怎麼直播?
這裡我們主要研究httpflv和hls。看了主流幾個web直播平臺,發現幾乎都是以httpflv為主來直播的,那麼這麼火httpflv到底是怎麼達到直播的?
首先我們都知道在媒體格式裡,幾乎都以h264視訊編碼。如今httpflv直播的flv資料也都是h264&aac為主的。flv封裝單元是以tag來表示的,一個tag可以是音訊tag或者視訊tag,或者指令碼tag及其其他型別。
值得注意的是flv裡面位元組序是網路位元組序,
flv的格式:
1 |
flvheader+[指令碼tag(metadata)]+[第一個視訊tag(h264_spspps)]+[第一個音訊tag(aac_header)]+[第二個視訊tag(h264第一個關鍵幀)]+
後面就是音訊和視訊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編碼結果dts和pts之間的偏移。
aac視訊tag的body:
1 |
0xaf+0x01+aac
raw
|
以上就是flv格式的詳細說明,可以看出格式簡單,封裝的前後資料關聯很小,當我們得到音訊頭和視訊頭,就可以從後面任意的一個關鍵幀開始播放。
當然想要httpflv正常播放,不能缺少matedata,就是第一個指令碼tag裡面,這裡面指定了解析度,音視訊編碼格式等。
httpflv直播實際上單純就是往客戶端傳送flvtag,當然是先發送flv前面那幾個關鍵的tag,然後第一幀是關鍵幀。
假如客戶端是obs推流軟體,以rtmp方式向伺服器推流,在開始握手及其建立stream完成以及傳送Metadata完成,及其一系列資料傳送完畢,伺服器就向obs傳送publish result指令,此後,obs就開始向伺服器推送flv tag資料,開始直播,而伺服器也得到了flv資料。
當某個客戶端想要來獲取直播資料,比如httpflv的方式來觀看直播,伺服器會怎麼做呢?
伺服器會先發送前面幾個flvtag,header+metadata+spspps+aacheader,當這幾個tag傳送完畢,伺服器會從直播流tag中,找到最新的視訊關鍵幀tag,從這個關鍵幀tag開發資料,為什麼呢?因為視訊流是IBP幀相互存在的,I是完整資料,BP解碼都需要I幀和前面的幀,所以,正常視訊資料,必須是從I幀開始傳送的。這裡就涉及到gop間距了,rtmp低延時秒開就是這個原理。當然傳送的時候,每個連線的tag開始時間戳戳要從0開始遞增的。
至此,httpflv客戶端就可以接受到flv流資料,解碼觀看直播了。
hls到底是怎麼直播?
hls就相對簡單粗暴了,伺服器將直播流資料的h264和aac,封裝切片成一個個的ts檔案。客戶端獲取直播的資料的時候,先請求m3u8檔案,下面就是一個m3u8的檔案,
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
ts最大時常5s
#EXT-X-MEDIA-SEQUENCE:2
第一個ts檔案的標識
#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檔案,當這個列表有新的ts檔案,客戶端會請求新的ts檔案追加到本地播放序列。
關於ts的封包,ts的封裝格式要比flv更復雜,主要的資料單元是ts包,每個包有pid,一個包固定大小普通沒有crc的為188,主要分為三類ts包,pat,pmt,pes,pat就是第一個包,當解析的時候會在ts包列表裡找pid為0x0的包,就是pat包,pat大概作用就是入口的意思,pat裡面有pmt包的pid,pmt裡面儲存的是流的包的pid,比如指定音訊包pid是0x102,視訊包pid是0x101,後面的0x102和0x101的包就是pes包了,將pes包解析併合並出原始流,就能解碼播放了。
小程式
知道了如何玩直播,於是寫了一個小的程式,該程式會錄製本機桌面和輸出音訊以及麥克風,編碼為h264和aac,同時在本機利用IOCP簡易的建立一個伺服器,提供web服務和直播服務,支援httpflv和hls直播。
以下是小程式的架構圖:
執行截圖:
啟動後可選擇,填寫埠號和位元速率,然後選擇直播方式,黑屏換low api。
程式使用的三個庫:
libx264 視訊編碼
libfaac 音訊編碼
swscale brga轉yuv420