站長(zhǎng)資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        WebSocket+MSE——HTML5 直播技術(shù)解析

        作者 | 劉博(又拍云多媒體開(kāi)發(fā)工程師)

        當(dāng)前為了滿(mǎn)足比較火熱的移動(dòng) Web 端直播需求,一系列的 HTML5 直播技術(shù)迅速的發(fā)展起來(lái)。

        常見(jiàn)的可用于 HTML5 的直播技術(shù)有 HLS、WebSocket 與 WebRTC。今天我向大家介紹WebSocket 與 MSE 相關(guān)的技術(shù)要點(diǎn),并在最后通過(guò)一個(gè)實(shí)例來(lái)展示具體用法。

        文章大綱

        • WebSocket 協(xié)議介紹

        • WebSocket Client/Server API介紹

        • MSE 介紹

        • fMP4 介紹

        • Demo 展示

        WebSocket

        通常的 Web 應(yīng)用都是圍繞著 HTTP 的請(qǐng)求/響應(yīng)模型構(gòu)建的。所有的 HTTP 通信都通過(guò)客戶(hù)端來(lái)控制,由客戶(hù)端向服務(wù)器發(fā)出一個(gè)請(qǐng)求,服務(wù)器接收和處理完畢后再返回結(jié)果給客戶(hù)端,客戶(hù)端將數(shù)據(jù)展現(xiàn)出來(lái)。由于這種模式不能滿(mǎn)足實(shí)時(shí)應(yīng)用需求,于是出現(xiàn)了 SSE、Comet 等 "服務(wù)器推" 的長(zhǎng)連接技術(shù)。

        WebSocket 是基于 TCP 連接之上的通信協(xié)議,可以在單個(gè) TCP 連接上進(jìn)行全雙工的通信。WebSocket 在 2011 年被 IETF 定為標(biāo)準(zhǔn) RFC 6455,并被 RFC 7936 補(bǔ)充規(guī)范,WebSocket API 被 W3C 定為標(biāo)準(zhǔn)。

        WebSocket 是獨(dú)立地創(chuàng)建在 TCP 上的協(xié)議,HTTP 協(xié)議中的那些概念都和 WebSocket 沒(méi)有關(guān)聯(lián),唯一關(guān)聯(lián)的是使用 HTTP 協(xié)議的 101 狀態(tài)碼進(jìn)行協(xié)議切換時(shí),使用的 TCP 端口是 80,可以繞過(guò)大多數(shù)防火墻的限制。

        WebSocket+MSE——HTML5 直播技術(shù)解析

        WebSocket 握手

        為了更方便地部署新協(xié)議,HTTP/1.1 引入了 Upgrade 機(jī)制,使得客戶(hù)端和服務(wù)端之間可以借助已有的HTTP語(yǔ)法升級(jí)到其它協(xié)議。這個(gè)機(jī)制在 RFC7230 的 6.7 Upgrade 一節(jié)中有詳細(xì)描述。

        要發(fā)起 HTTP/1.1 協(xié)議升級(jí),客戶(hù)端必須在請(qǐng)求頭部中指定這兩個(gè)字段 ▽

        > Connection: Upgrade  Upgrade: protocol-name[/protocol-version]

        如果服務(wù)端同意升級(jí),那么需要這樣響應(yīng) ▽

        > HTTP/1.1 101 Switching Protocols  Connection: upgrade  Upgrade: protocol-name[/protocol-version]  [... data defined by new protocol ...]

        可以看到,HTTP Upgrade 響應(yīng)的狀態(tài)碼是 101,并且響應(yīng)正文可以使用新協(xié)議定義的數(shù)據(jù)格式。

        WebSocket 握手就利用了這種 HTTP Upgrade 機(jī)制。一旦握手完成,后續(xù)數(shù)據(jù)傳輸直接在 TCP 上完成。

        WebSocket JavaScript API

        目前主流的瀏覽器提供了 WebSocket 的 API 接口,可以發(fā)送消息(文本或者二進(jìn)制)給服務(wù)器,并且接收事件驅(qū)動(dòng)的響應(yīng)數(shù)據(jù)。

        Step1. 檢查瀏覽器是否支持 WebSocket

        > if(window.WebSocket) {      // WebSocket代碼  }

        Step2. 建立連接

        > var ws = new WebSocket('ws://localhost:8327');

        Step3. 注冊(cè)回調(diào)函數(shù)以及收發(fā)數(shù)據(jù)

        分別注冊(cè) WebSocket 對(duì)象的 onopen、onclose、onerror 以及 onmessage 回調(diào)函數(shù)。

        通過(guò)ws.send()來(lái)進(jìn)行發(fā)送數(shù)據(jù),這里不僅可以發(fā)送字符串,也可以發(fā)送 Blob 或 ArrayBuffer 類(lèi)型的數(shù)據(jù)。

        如果接收的是二進(jìn)制數(shù)據(jù),需要將連接對(duì)象的格式設(shè)為 blob 或 arraybuffer。

        ws.binaryType = 'arraybuffer';

        WebSocket Golang API

        服務(wù)器端 WebSocket 庫(kù)我推薦使用 Google 自己的 http://golang.org/x/net/websocket,可以非常方便的與 net/http 一起使用。也可以將 WebSocket 的 handler function 通過(guò) websocket.Handler轉(zhuǎn)換成 http.Handler,這樣就可以跟 net/http 庫(kù)一起使用了。

        然后通過(guò) websocket.Message.Receive 來(lái)接收數(shù)據(jù),通過(guò) websocket.Message.Send 來(lái)發(fā)送數(shù)據(jù)。

        具體代碼可以看下面的 Demo 部分。

        MSE

        在介紹 MSE 之前,我們先看看 HTML5<audio>和<video> 有哪些限制。

        HTML5<audio> 和 <video> 標(biāo)簽的限制

        • 不支持流

        • 不支持 DRM 和加密

        • 很難自定義控制, 以及保持跨瀏覽器的一致性

        • 編解碼和封裝在不同瀏覽器支持不同

        MSE 是解決 HTML5 的流問(wèn)題。

        Media Source Extensions(MSE)是 Chrome、Safari、Edge 等主流瀏覽器支持的一個(gè)新的Web API。MSE 是一個(gè) W3C 標(biāo)準(zhǔn),允許 JavaScript 動(dòng)態(tài)構(gòu)建 <video> 和 <audio> 的媒體流。它定義了對(duì)象,允許 JavaScript 傳輸媒體流片段到一個(gè) HTMLMediaElement。

        通過(guò)使用 MSE,你可以動(dòng)態(tài)地修改媒體流而不需要任何插件。這讓前端JavaScript可以做更多的事情—— 在 JavaScript 進(jìn)行轉(zhuǎn)封裝、處理,甚至轉(zhuǎn)碼。

        雖然 MSE 不能讓流直接傳輸?shù)?media tags 上,但是 MSE 提供了構(gòu)建跨瀏覽器播放器的核心技術(shù),讓瀏覽器通過(guò)JavaScript API來(lái)推音視頻到 media tags 上。

        Browser Support

        通過(guò) caniuse 來(lái)檢查是否瀏覽器支持情況。

        WebSocket+MSE——HTML5 直播技術(shù)解析

        通過(guò) MediaSource.isTypeSupported() 可以進(jìn)一步地檢查 codec MIME 類(lèi)型是否支持。

        fMP4

        比較常用的視頻封裝格式有 WebM 和 fMP4。

        WebM 和 WebP 是兩個(gè)姊妹項(xiàng)目,都是由 Google 贊助的。由于 WebM 是基于 Matroska 的容器格式,天生是流式的,很適合用在流媒體領(lǐng)域里。

        下面著重介紹一下 fMP4 格式。

        我們都知道 MP4 是由一系列的 Boxes 組成的。普通的 MP4 的是嵌套結(jié)構(gòu)的,客戶(hù)端必須要從頭加載一個(gè) MP4 文件,才能夠完整播放,不能從中間一段開(kāi)始播放。

        而 fMP4 由一系列的片段組成,如果服務(wù)器支持 byte-range 請(qǐng)求,那么,這些片段可以獨(dú)立的進(jìn)行請(qǐng)求到客戶(hù)端進(jìn)行播放,而不需要加載整個(gè)文件。

        為了更加形象的說(shuō)明這一點(diǎn),下面我介紹幾個(gè)常用的分析 MP4 文件的工具。

        gpac,原名 mp4box,是一個(gè)媒體開(kāi)發(fā)框架,在其源碼下有大量的媒體分析工具,可以使用testapps;

        • mp4box.js,是 mp4box 的 Javascript 版本;

        • bento4,一個(gè)專(zhuān)門(mén)用于 MP4 的分析工具;

        • mp4parser,在線(xiàn) MP4 文件分析工具。

        fragment mp4 VS non-fragment mp4

        下面是一個(gè) fragment mp4 文件通過(guò) mp4parser(Online MPEG4 Parser )分析后的截圖 ▽

        WebSocket+MSE——HTML5 直播技術(shù)解析

        下面是一個(gè) non-fragment mp4 文件通過(guò) mp4parser 分析后的截圖 ▽

        WebSocket+MSE——HTML5 直播技術(shù)解析

        我們可以看到 non-fragment mp4 的最頂層 box 類(lèi)型非常少,而 fragment mp4 是由一段一段的 moof+mdat 組成的,它們已經(jīng)包含了足夠的 metadata 信息與數(shù)據(jù), 可以直接 seek 到這個(gè)位置開(kāi)始播放。也就是說(shuō) fMP4 是一個(gè)流式的封裝格式,這樣更適合在網(wǎng)絡(luò)中進(jìn)行流式傳輸,而不需要依賴(lài)文件頭的metadata。

        Apple在WWDC 2016 大會(huì)上宣布會(huì)在 iOS 10、tvOS、macO S的 HLS 中支持 fMP4,可見(jiàn)fMP4 的前景非常的好。

        值得一提的是,fMP4、CMAF、ISOBMFF 其實(shí)都是類(lèi)似的東西。

        MSE JavaScript API

        從高層次上看,MSE 提供了

        • 一套 JavaScript API 來(lái)構(gòu)建 media streams

        • 一個(gè)拼接和緩存模型

        • 識(shí)別一些 byte 流類(lèi)型

        • WebM

        • ISO Base Media File Format

        • MPEG-2 Transport Streams

        MSE 內(nèi)部結(jié)構(gòu)

        WebSocket+MSE——HTML5 直播技術(shù)解析

        MSE 本身的設(shè)計(jì)是不依賴(lài)任務(wù)特定的編解碼和容器格式的,但是不同的瀏覽器支持程度是不一樣的。

        可以通過(guò)傳遞一個(gè) MIME 類(lèi)型的字符串到靜態(tài)方法:

        > MediaSource.isTypeSupported來(lái)檢查。比如 ▽  MediaSource.isTypeSupported('audio/mp3'); // false  MediaSource.isTypeSupported('video/mp4'); // true  MediaSource.isTypeSupported('video/mp4; codecs="avc1.4D4028, mp4a.40.2"'); // true

        獲取 Codec MIME string 的方法可以通過(guò)在線(xiàn)的 [mp4info](http://nickdesaulniers.github.io/mp4info),或者使用命令行 mp4info test.mp4 | grep Codecs,可以得到類(lèi)似如下結(jié)果 ▽

        > mp4info fmp4.mp4| grep Codec      Codecs String: mp4a.40.2      Codecs String: avc1.42E01E

        當(dāng)前,H.264 + AAC 的 MP4 容器在所有的瀏覽器都支持。

        普通的 MP4 文件是不能和 MSE 一起使用的, 需要將 MP4 進(jìn)行 fragment 化。

        檢查一個(gè) MP4 是否已經(jīng) fragment 的方法 ▽

        > mp4dump test.mp4 | grep "[m"

        如果是non-fragment會(huì)顯示如下信息 ▽

        > mp4dump nfmp4.mp4 | grep "[m"  [mdat] size=8+50873  [moov] size=8+7804    [mvhd] size=12+96      [mdia] size=8+3335        [mdhd] size=12+20        [minf] size=8+3250      [mdia] size=8+3975        [mdhd] size=12+20        [minf] size=8+3890              [mp4a] size=8+82      [meta] size=12+78
        如果已經(jīng) fragment,會(huì)顯示如下的類(lèi)似信息 ▽
        >  mp4dump fmp4.mp4 | grep "[m" | head -n 30  [moov] size=8+1871    [mvhd] size=12+96      [mdia] size=8+312        [mdhd] size=12+20        [minf] size=8+219              [mp4a] size=8+67      [mdia] size=8+371        [mdhd] size=12+20        [minf] size=8+278      [mdia] size=8+248        [mdhd] size=12+20        [minf] size=8+156      [mdia] size=8+248        [mdhd] size=12+20        [minf] size=8+156    [mvex] size=8+144      [mehd] size=12+4  [moof] size=8+600    [mfhd] size=12+4  [mdat] size=8+138679  [moof] size=8+536    [mfhd] size=12+4  [mdat] size=8+24490  [moof] size=8+592    [mfhd] size=12+4  [mdat] size=8+14444  [moof] size=8+312    [mfhd] size=12+4  [mdat] size=8+1840  [moof] size=8+600

        把一個(gè) non-fragment MP4 轉(zhuǎn)換成 fragment MP4。

        可以使用 FFmpeg 的 -movflags 來(lái)轉(zhuǎn)換。

        對(duì)于原始文件為非 MP4 文件 ▽

        > ffmpeg -i trailer_1080p.mov -c:v copy -c:a copy -movflags frag_keyframe+empty_moov bunny_fragmented.mp4

        對(duì)于原始文件已經(jīng)是 MP4 文件 ▽

        > ffmpeg -i non_fragmented.mp4 -movflags frag_keyframe+empty_moov fragmented.mp4

        或者使用 mp4fragment ▽

        > mp4fragment input.mp4 output.mp4

        DEMO TIME

        最后階段,展示兩個(gè)demo,分別是 MSE Vod Demo、MSE Live Demo

        MSE Vod Demo

        展示利用 MSE 和 WebSocket 實(shí)現(xiàn)一個(gè)點(diǎn)播服務(wù)

        后端讀取一個(gè) fMP4 文件,通過(guò) WebSocket 發(fā)送給 MSE,進(jìn)行播放

        WebSocket+MSE——HTML5 直播技術(shù)解析

        展示利用 MSE 和 WebSocket 實(shí)現(xiàn)一個(gè)直播服務(wù)

        后端代理一條 HTTP-FLV 直播流,通過(guò) WebSocket 發(fā)送給 MSE,進(jìn)行播放

        前端 MSE 部分做了很多工作, 包括將 flv 實(shí)時(shí)轉(zhuǎn)封裝成了 fMP4,這里引用了 videojs-flow 的實(shí)現(xiàn)

        Refs

        WebSocket

        • rfc6455

        • HTTP Upgrade

        • WebSocket API

        • MDN WebSocket

        • videojs-flow

        MSE

        • W3C

        • MDN MSE

        • HTML5 Codec MIME

        又拍直播云是基于又拍云內(nèi)容分發(fā)網(wǎng)絡(luò)為直播應(yīng)用提供超低延遲、高碼率、高并發(fā)的整套從推流端到播放端的一站式解決方案。包括實(shí)時(shí)轉(zhuǎn)碼,實(shí)時(shí)錄制,分發(fā)加速,水印,截圖,秒級(jí)禁播,延時(shí)直播等功能。直播源站支持自主源站或又拍云源,為支持用戶(hù)在不同終端播放,支持 RTMP、HLS、HTTP-flv 播放輸出。

        詳情了解:https://www.upyun.com/products/live

        推薦閱讀:

        無(wú)連麥,不直播,都在說(shuō)的直播利器連麥互動(dòng)到底是啥?
        技術(shù)干貨|移動(dòng)直播六大關(guān)鍵技術(shù)詳解
        又拍直播云SDK,自帶美顏、濾鏡、消噪、人聲增益等功能
        又拍直播云功能處理篇:轉(zhuǎn)碼、錄制、視頻水印、視頻截圖
        又拍直播云功能基礎(chǔ)篇:推流和拉流、多協(xié)議輸出、多訪(fǎng)問(wèn)方式、回源端口自定義
        又拍直播云功能高級(jí)篇:防盜鏈、秒級(jí)禁播、自動(dòng)鑒黃、API接口

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
        主站蜘蛛池模板: 国产午夜无码精品免费看| 精品在线免费观看| 国产高清国产精品国产专区| 网友偷拍日韩精品| 国产成人久久久精品二区三区| 国产日韩精品欧美一区| 综合人妻久久一区二区精品| 国产成人无码精品一区在线观看 | 无码日韩精品一区二区免费| 久久亚洲国产精品123区| 国产三级精品三级在线观看| 欧美精品一本久久男人的天堂 | 午夜精品久久久内射近拍高清| 92国产精品午夜福利免费| 99久久婷婷免费国产综合精品| 色一乱一伦一图一区二区精品 | 99精品欧美一区二区三区| 国产一区二区精品久久| 国产女主播精品大秀系列| 久久国产精品无码HDAV| 无码精品黑人一区二区三区 | 99re这里只有精品热久久 | 久久精品国产亚洲77777| 亚洲精品乱码久久久久久中文字幕 | 精品久久久久久国产免费了| 一级香蕉精品视频在线播放| 99re热这里只有精品视频中文字幕| 国语精品一区二区三区| 久久精品国产亚洲av日韩| 精品无码一区在线观看| 人妻少妇精品视频二区 | 久久精品国产99久久久香蕉 | 国产精品最新国产精品第十页 | 午夜DY888国产精品影院| 亚洲精品乱码久久久久久中文字幕| 亚洲国产成人乱码精品女人久久久不卡 | 无码人妻精品中文字幕免费| 亚洲国产精品高清久久久| 无码人妻精品一区二区三区99仓本| 伊人久久综合精品无码AV专区| 最新在线精品国自av|