直播在互聯網中已經成爲一個必不可少的東西,話說各大直播平臺 bilibili,虎牙,鬥魚都準備上市了。javascript
富途證券做爲了一家互聯證券公司直播固然也少不了的。目前直播在富途牛牛軟件(如下簡稱:牛牛)中主要功能是教育跟宣傳做用。css
富途牛牛爲領先的港股美股交易軟件。html
目前牛牛支持狀況:java
移動牛牛(安卓、IOS)主播端只支持攝像頭直播,觀衆端支持展現nginx
PC牛牛主播端支持攝像頭直播、錄屏直播、攝像頭+錄屏直播,觀衆端支持展現git
MAC牛牛跟web端主播端不支持,觀衆端支持展現github
視頻直播能夠分爲採集,前處理,編碼,傳輸,解碼,渲染 這幾個環節。web
通常是由客戶端(IOS、安卓、PC或其它工具,如OBS)完成的,iOS是比較簡單的,Android則要作些機型適配工做,PC最麻煩各類奇葩攝像頭驅動,固然這些問題,騰訊雲已經幫咱們處理好了,呵呵。算法
主要是處理直播美顏,美顏算法須要用到GPU編程,須要懂圖像處理算法的人,沒有好的開源實現,要本身參考論文去研究。難點不在於美顏效果,而在於GPU佔用和美顏效果之間找平衡。chrome
確定要採用硬編碼,軟編碼720p徹底沒但願,勉強能編碼也會致使CPU過熱燙到攝像頭。編碼要在分辨率,幀率,碼率,GOP等參數設計上找到最佳平衡點。
通常交給了CDN服務商。
是對以前編碼的操做,進行解碼,在web裏須要解碼是HLS。
主要用播放器來解決,web中經常使用到的播放器有 video.js ,目前咱們使用是騰訊雲播放器。
其實一個完成直播,遠遠不上面這幾個環節,下面是騰訊雲直播方案的整個流程圖:
目前互聯網上web作直播,主要是展現,主流web展現的話可能涉及到HLS跟RTMP這兩個東西,如今咱們重點講解hls跟RTMP協議。
HLS(HTTP Live Streaming全稱)是一個基於HTTP的視頻流協議,由Apple公司實現,Mac OS上的QuickTime、Safari 以及iOS上的 Safari都能很好的支持 HLS,高版本 Android 也增長了對 HLS 的支持。
一些常見的客戶端如:MPlayerX、VLC 也都支持HLS協議,若是須要在chrome上播放,須要使用 videojs-contrib-hls.js 解析。
HLS工做流程圖
HLS的服務器組件負責獲取的媒體輸入流 , 而後Media編碼後 MPEG-4(H.264 video 和 AAC audio)格式而後用硬件打包到 MPEG-2 (MPEG-2 transport stream)的傳輸流中。圖中顯示,傳輸流會通過stream segmenter, 這裏的工做是MPEG-2傳輸流會被分散爲小片斷而後保存爲一個或多個系列的 .ts 格式的媒體文件。這個過程須要藉助編碼工具來完成,好比 Apple stream segmenter。 (視頻類是.ts文件,純音頻會被編碼爲一些音頻小片斷,一般爲 ADTS頭的AAC、MP三、或者 AC-3格式。) 服務端能夠採用硬件編碼和軟件編碼兩種形式,其功能都是按照上文描述的規則對現有的媒體文件進行切片並使用索引文件進行管理。而軟件切片一般會使用 Apple 公司提供的工具或者第三方的集成工具。
同時上面提到的那個切片器(segmenter)也會建立一個索引文件,一般會包含這些媒體文件的一個列表,也能包含元數據。它通常都是一個個.M38U的列表。列表元素會關聯一個 URL 用於客戶端訪問。而後按序去請求這些 URL。
索引文件結構圖
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=409037,RESOLUTION=416x234,CODECS="mp4a.40.2, avc1.42001e"
Gear1/prog_index.m3u8
複製代碼
第一行:#EXTM3U
每一個M3U文件第一行必須是這個tag,起標示做用
第二行:#EXT-X-STREAM-INF
標籤的屬性列表中直接指明當前流是VIDEO仍是AUDIO
包含屬性 :
#EXTM3U
#EXT-X-TARGETDURATION:11
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10.133333,
fileSequence0.ts
#EXTINF:10.000666,
fileSequence1.ts
#EXTINF:10.667334,
fileSequence2.ts
#EXTINF:9.686001,
fileSequence3.ts
#EXTINF:9.768665,
fileSequence4.ts
#EXTINF:10.000000,
fileSequence5.ts
#EXT-X-ENDLIST
複製代碼
#EXTM3U m3u文件頭,必須放在第一行。
#EXT-X-TARGETDURATION 每一個分片TS的最大的時長。
#EXT-X-VERSION 用以標示協議版本。
#EXT-X-MEDIA-SEQUENCE TS分片的序列號。
#EXT-X-PLAYLIST-TYPE 提供關於PlayList的可變性的信息, 這個對整個PlayList文件有效,是可選的。
#EXTINF extra info,分片TS的信息,如時長,帶寬等。
分配組件由標準的網絡服務器。他們負責接受Client客戶端請求並提供相關聯的資源給客戶端。
videojs-contrib-hls.js解析圖
HLS簡單講就是把整個流分紅一個個小的片斷,基於 HTTP 的文件來下載,每次只下載一小部分。
前面提到了用於 H5 播放直播視頻時引入的一個 .m3u8 的文件,這個文件就是基於 HLS 協議,存放視頻流元數據的文件。
每個 .m3u8 文件,分別對應若干個 ts 文件,這些 ts 文件纔是真正存放視頻的數據,m3u8 文件只是存放了一些 ts 文件的配置信息和相關路徑,當視頻播放時,.m3u8 是動態改變的,再經過解析器(videojs-contrib-hls.js)解析這個文件,並找到對應的 ts 文件來播放,因此通常爲了加快速度,.m3u8 放在 web 服務器上,ts 文件放在 cdn 上。
Real Time Messaging Protocol(簡稱 RTMP)是 Macromedia 開發的一套視頻直播協議,如今屬於 Adobe。這套方案須要搭建專門的 RTMP 流媒體服務如 Adobe Media Server,而且在瀏覽器中只能使用 Flash 實現播放器。它的實時性很是好,延遲很小,但沒法支持移動端 WEB 播放是它的硬傷。
瀏覽器端,HTML5 video標籤沒法播放 RTMP 協議的視頻,能夠經過 video.js
來實現。
<link href="http://vjs.zencdn.net/5.8.8/video-js.css" rel="stylesheet">
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264" loop="loop" webkit-playsinline>
<source src="rtmp://10.14.221.17:1935/rtmplive/home" type='rtmp/flv'>
</video>
<script src="http://vjs.zencdn.net/5.8.8/video.js"></script>
<script> videojs.options.flash.swf = 'video.swf'; videojs('example_video_1').ready(function() { this.play(); }); </script>
複製代碼
協議 | 原理 | 延時 | 優勢 | 缺點 | 使用場景 |
---|---|---|---|---|---|
HLS(http) | 集合一段時間數據生成ts切片文件更m3u8文件 | 10s-30s | 跨平臺 | 延時性高 | 移動端 |
RTMP(TCP) | 每一個時刻的數據收到後當即發送 | 2s | 延時低、實時性好 | 跨平臺差 | PC+直播+實時性要求高+互動性強 |
brew install nginx
複製代碼
brew install nginx-full --with-rtmp-module
複製代碼
而後安裝FFmpeg(是一個集錄制、轉換、音/視頻編碼解碼功能 爲一體的完整的開源工具,咱們下面用它來作推流跟切片)。
brew install ffmpeg
複製代碼
查找到nginx.conf配置文件(/usr/local/etc/nginx/nginx.conf),並配置相應的直播流配置。
rtmp {
server {
#監聽的端口
listen 1935;
# RTMP 直播流配置
application rtmplive {
live on;
#爲 rtmp 引擎設置最大鏈接數。默認爲 off
max_connections 1024;
}
# HLS 直播流配置
application hls{
live on;
hls on;
hls_path /Users/youname/Documents/notes/live/public/hls; #這裏的路徑切片須要保存的路徑
hls_fragment 1s;
}
}
}
複製代碼
在http中添加 HLS 的配置:
location /hls {
# Serve HLS fragments
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /Users/youname/Documents/notes/live/public;#切片的路徑
#add_header Cache-Controll no-cache;
expires -1;
}
複製代碼
sudo nginx -s reload
複製代碼
netstat -an | grep 1935
複製代碼
若是顯示以下,顯示已經啓用。
http端口同理。
到如今咱們已經完成了,服務的搭建。
咱們以推流MP4文件爲例,個人視頻文件地址:/Users/youname/Desktop/w01661pl9vw.p702.1.mp4
RTMP 協議推流命令:
ffmpeg -re -i /Users/youname/Desktop/w01661pl9vw.p702.1.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/rtmplive/home
複製代碼
HLS 協議推流命令:
ffmpeg -re -i /Users/youname/Desktop/w01661pl9vw.p702.1.mp4 -vcodec libx264 -vprofile baseline -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -q 10 rtmp://127.0.0.1:1935/hls/test
複製代碼
參數:
上面的命令操做後,命令行出現了以下圖,表示已經成功了。
關於FFmpeg功能命令可參考:FFmpeg功能命令集合
兩種推流方式播放的話,咱們都使用video.js播放器播放(牛牛裏使用的是騰訊雲播放器)
須要注意的是src中的地址填的是RTMP推流地址。播放時,若是出現「當前系統環境不支持播放該視頻格式」,瀏覽器須要啓用flash,才能正常播放。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="http://vjs.zencdn.net/5.19/video-js.min.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/5.19/video.min.js"></script>
</head>
<body>
<video id="my-player" class="video-js" controls preload="auto" data-setup='{}'>
<source src='rtmp://127.0.0.1/rtmplive/home' type='rtmp/flv'/>
</p>
</video>
<script type="text/javascript"> var player = videojs('my-player'); var options = {}; var player = videojs('my-player', options, function onPlayerReady() { videojs.log('Your player is ready!'); // In this context, `this` is the player that was created by Video.js. this.play(); // How about an event listener? this.on('ended', function() { videojs.log('Awww...over so soon?!'); }); }); </script>
</body>
</html>
複製代碼
下面的src填的是切片地址。
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>videojs-contrib-hls embed</title>
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.js"></script>
<script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script>
</head>
<body>
<video id="my_video_1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="268" data-setup='{}'>
<source src="http://www.tony.com/hls/test.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
複製代碼
咱們來看看真正的效果如何。
RTMP效果圖
HLS效果
ts和m3u8文件
在X5內核瀏覽器裏必須使用觸發touchend、click、doubleclick或keydown事件等標準的事件才能觸發。
安卓下不少瀏覽器把video標籤替換成了原生自帶播放器樣式跟行爲,很難控制其行爲跟樣式。
目前使用的是weinre調試,但weinre調試看不到在native實際效果,好比web調用native,須要native反饋一種效果,weinre是看不到效果。
schema跟jsBridge,schema只能作到web調用native,並且作不到native調用web;jsBridge雖然能夠作native調用web,但在iframe沒加載完的狀況下,也是通知不到web的;
整個直播是一個很是複雜的過程,實現過程當中會遇到不少性能問題,須要在性能跟即時性作一個權衡,ts跟m3u8儘可能作到緩存,瀏覽器裏儘可能使用推流。
歡迎你們關注富途web開發團隊,原文連接