WebSocket+MSE——HTML5 直播技術解析

来源:http://www.cnblogs.com/upyun/archive/2017/06/05/6944790.html
-Advertisement-
Play Games

作者 | 劉博(又拍雲多媒體開發工程師) 當前為了滿足比較火熱的移動 Web 端直播需求,一系列的 HTML5 直播技術迅速的發展起來。 常見的可用於 HTML5 的直播技術有 HLS、WebSocket 與 WebRTC。今天我向大家介紹WebSocket 與 MSE 相關的技術要點,併在最後通過 ...


作者 | 劉博(又拍雲多媒體開發工程師)

當前為了滿足比較火熱的移動 Web 端直播需求,一系列的 HTML5 直播技術迅速的發展起來。

常見的可用於 HTML5 的直播技術有 HLS、WebSocket 與 WebRTC。今天我向大家介紹WebSocket 與 MSE 相關的技術要點,併在最後通過一個實例來展示具體用法。

文章大綱

  • WebSocket 協議介紹
  • WebSocket Client/Server API介紹
  • MSE 介紹
  • fMP4 介紹
  • Demo 展示

WebSocket

通常的 Web 應用都是圍繞著 HTTP 的請求/響應模型構建的。所有的 HTTP 通信都通過客戶端來控制,由客戶端向伺服器發出一個請求,伺服器接收和處理完畢後再返回結果給客戶端,客戶端將數據展現出來。由於這種模式不能滿足實時應用需求,於是出現了 SSE、Comet 等 "伺服器推" 的長連接技術。

WebSocket 是基於 TCP 連接之上的通信協議,可以在單個 TCP 連接上進行全雙工的通信。WebSocket 在 2011 年被 IETF 定為標準 RFC 6455,並被 RFC 7936 補充規範,WebSocket API 被 W3C 定為標準。

WebSocket 是獨立地創建在 TCP 上的協議,HTTP 協議中的那些概念都和 WebSocket 沒有關聯,唯一關聯的是使用 HTTP 協議的 101 狀態碼進行協議切換時,使用的 TCP 埠是 80,可以繞過大多數防火牆的限制。

WebSocket 握手

為了更方便地部署新協議,HTTP/1.1 引入了 Upgrade 機制,使得客戶端和服務端之間可以藉助已有的HTTP語法升級到其它協議。這個機制在 RFC7230 的 6.7 Upgrade 一節中有詳細描述。

要發起 HTTP/1.1 協議升級,客戶端必須在請求頭部中指定這兩個欄位 ▽

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

如果服務端同意升級,那麼需要這樣響應 ▽

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

可以看到,HTTP Upgrade 響應的狀態碼是 101,並且響應正文可以使用新協議定義的數據格式。

WebSocket 握手就利用了這種 HTTP Upgrade 機制。一旦握手完成,後續數據傳輸直接在 TCP 上完成。

WebSocket JavaScript API

目前主流的瀏覽器提供了 WebSocket 的 API 介面,可以發送消息(文本或者二進位)給伺服器,並且接收事件驅動的響應數據。

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

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

Step2. 建立連接

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

Step3. 註冊回調函數以及收發數據

分別註冊 WebSocket 對象的 onopen、onclose、onerror 以及 onmessage 回調函數。

通過ws.send()來進行發送數據,這裡不僅可以發送字元串,也可以發送 Blob 或 ArrayBuffer 類型的數據。

如果接收的是二進位數據,需要將連接對象的格式設為 blob 或 arraybuffer。

ws.binaryType = 'arraybuffer';

WebSocket Golang API

伺服器端 WebSocket 庫我推薦使用 Google 自己的 ,可以非常方便的與 net/http 一起使用。也可以將 WebSocket 的 handler function 通過 websocket.Handler轉換成 http.Handler,這樣就可以跟 net/http 庫一起使用了。

然後通過 websocket.Message.Receive 來接收數據,通過 websocket.Message.Send 來發送數據。

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

MSE

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

HTML5<audio> 和 <video> 標簽的限制

  • 不支持流
  • 不支持 DRM 和加密
  • 很難自定義控制, 以及保持跨瀏覽器的一致性
  • 編解碼和封裝在不同瀏覽器支持不同

MSE 是解決 HTML5 的流問題。

Media Source Extensions(MSE)是 Chrome、Safari、Edge 等主流瀏覽器支持的一個新的Web API。MSE 是一個 W3C 標準,允許 JavaScript 動態構建 <video> 和 <audio> 的媒體流。它定義了對象,允許 JavaScript 傳輸媒體流片段到一個 HTMLMediaElement。

通過使用 MSE,你可以動態地修改媒體流而不需要任何插件。這讓前端JavaScript可以做更多的事情—— 在 JavaScript 進行轉封裝、處理,甚至轉碼。

雖然 MSE 不能讓流直接傳輸到 media tags 上,但是 MSE 提供了構建跨瀏覽器播放器的核心技術,讓瀏覽器通過JavaScript API來推音視頻到 media tags 上。

Browser Support

通過 caniuse 來檢查是否瀏覽器支持情況。

通過 MediaSource.isTypeSupported() 可以進一步地檢查 codec MIME 類型是否支持。

fMP4

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

WebM 和 WebP 是兩個姊妹項目,都是由 Google 贊助的。由於 WebM 是基於 Matroska 的容器格式,天生是流式的,很適合用在流媒體領域里。

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

我們都知道 MP4 是由一系列的 Boxes 組成的。普通的 MP4 的是嵌套結構的,客戶端必須要從頭載入一個 MP4 文件,才能夠完整播放,不能從中間一段開始播放。

而 fMP4 由一系列的片段組成,如果伺服器支持 byte-range 請求,那麼,這些片段可以獨立的進行請求到客戶端進行播放,而不需要載入整個文件。

為了更加形象的說明這一點,下麵我介紹幾個常用的分析 MP4 文件的工具。

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

  • mp4box.js,是 mp4box 的 Javascript 版本;
  • bento4,一個專門用於 MP4 的分析工具;
  • mp4parser,線上 MP4 文件分析工具。

fragment mp4 VS non-fragment mp4

下麵是一個 fragment mp4 文件通過 mp4parser(Online MPEG4 Parser )分析後的截圖 ▽

下麵是一個 non-fragment mp4 文件通過 mp4parser 分析後的截圖 ▽

我們可以看到 non-fragment mp4 的最頂層 box 類型非常少,而 fragment mp4 是由一段一段的 moof+mdat 組成的,它們已經包含了足夠的 metadata 信息與數據, 可以直接 seek 到這個位置開始播放。也就是說 fMP4 是一個流式的封裝格式,這樣更適合在網路中進行流式傳輸,而不需要依賴文件頭的metadata。

Apple在WWDC 2016 大會上宣佈會在 iOS 10、tvOS、macO S的 HLS 中支持 fMP4,可見fMP4 的前景非常的好。

值得一提的是,fMP4、CMAF、ISOBMFF 其實都是類似的東西。

MSE JavaScript API

從高層次上看,MSE 提供了

  • 一套 JavaScript API 來構建 media streams
  • 一個拼接和緩存模型
  • 識別一些 byte 流類型
  • WebM
  • ISO Base Media File Format
  • MPEG-2 Transport Streams

MSE 內部結構




MSE 本身的設計是不依賴任務特定的編解碼和容器格式的,但是不同的瀏覽器支持程度是不一樣的。

可以通過傳遞一個 MIME 類型的字元串到靜態方法:

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

獲取 Codec MIME string 的方法可以通過線上的 [mp4info](),或者使用命令行 mp4info test.mp4 | grep Codecs,可以得到類似如下結果 ▽

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

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

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

檢查一個 MP4 是否已經 fragment 的方法 ▽

> mp4dump test.mp4 | grep "\[m"

如果是non-fragment會顯示如下信息 ▽

> 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
如果已經 fragment,會顯示如下的類似信息 ▽
>  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

把一個 non-fragment MP4 轉換成 fragment MP4。

可以使用 FFmpeg 的 -movflags 來轉換。

對於原始文件為非 MP4 文件 ▽

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

對於原始文件已經是 MP4 文件 ▽

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

或者使用 mp4fragment ▽

> mp4fragment input.mp4 output.mp4

DEMO TIME

最後階段,展示兩個demo,分別是 MSE Vod Demo、MSE Live Demo

MSE Vod Demo

展示利用 MSE 和 WebSocket 實現一個點播服務

後端讀取一個 fMP4 文件,通過 WebSocket 發送給 MSE,進行播放

展示利用 MSE 和 WebSocket 實現一個直播服務

後端代理一條 HTTP-FLV 直播流,通過 WebSocket 發送給 MSE,進行播放

前端 MSE 部分做了很多工作, 包括將 flv 實時轉封裝成了 fMP4,這裡引用了 videojs-flow 的實現

Refs

WebSocket

  • rfc6455
  • HTTP Upgrade
  • WebSocket API
  • MDN WebSocket
  • videojs-flow

MSE

  • W3C
  • MDN MSE
  • HTML5 Codec MIME

又拍直播雲是基於又拍雲內容分髮網絡為直播應用提供超低延遲、高碼率、高併發的整套從推流端到播放端的一站式解決方案。包括實時轉碼,實時錄製,分發加速,水印,截圖,秒級禁播,延時直播等功能。直播源站支持自主源站或又拍雲源,為支持用戶在不同終端播放,支持 RTMP、HLS、HTTP-flv 播放輸出。

詳情瞭解:

推薦閱讀:

無連麥,不直播,都在說的直播利器連麥互動到底是啥?
技術乾貨|移動直播六大關鍵技術詳解
又拍直播雲SDK,自帶美顏、濾鏡、消噪、人聲增益等功能
又拍直播雲功能處理篇:轉碼、錄製、視頻水印、視頻截圖
又拍直播雲功能基礎篇:推流和拉流、多協議輸出、多訪問方式、回源埠自定義
又拍直播雲功能高級篇:防盜鏈、秒級禁播、自動鑒黃、API介面


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • html代碼 < > css代碼 { margin: 0; padding:0; } li{ list style: none; } .boss{ position:relative; width: 350px; } .bigimg{ width: 350px; border: 1px ...
  • Promise done用於捕獲任何時候可能出現的錯誤,並全局拋出;finally用於不管Promise對象狀態如何,都會執行的操作,接受一個普通的回調函數作為參數(必執行); ...
  • /** * @overview A minimalistic wrapper around React Native's AsyncStorage. * @license MIT */import { AsyncStorage } from 'react-native';import merge f ...
  • jquery仿京東商品頁面 京東頁面大家都很熟悉,進入商品頁面把滑鼠放在圖片上旁邊會出現一個放大的效果,接下來就帶大家看看怎麼實現的!!!! 仿京東商品頁面css的代碼!!! 仿京東商品頁面html的代碼!!! 仿京東商品頁面jquery的代碼!!! 仿京東商品頁面的效果!!! 怎麼樣,當我做出來的 ...
  • 1,下載安裝node 訪問 http://nodejs.org ,然後點擊大大的綠色的 install 按鈕,下載完成後直接運行程式,就一切準備就緒。 npm 會隨著安裝包一起安裝, 2,打開代碼行 node -v //查看node版本,如果顯示版本號,則安裝成功。 npm -v //查看npm版本 ...
  • 之前學習中做的筆記,放在有道雲筆記裡面了,分享出來,一起學習啦。 gulp入門篇: http://note.youdao.com/noteshare?id=f0fae7bae57c9deaaa10d2b51c431d75 gulp進階篇: http://note.youdao.com/notesha ...
  • <ul class="ddd"> <li class="solid active">啦啦啦啦</li> <li class="solid">我哦我我</li> <li class="solid">哦哦哦哦</li> <li class="solid">噢噢噢噢</li> <li class="sol ...
  • 1. 2.雙向數據綁定 3.v-if 4.v-show:也是條件渲染指令,和v-if指令不同的是,使用v-show指令的元素始終會被渲染到HTML(但是使用v-if指令的元素如果表達式為假,則不會被渲染到HTML頁面,這裡要註意v-if和v-show的這個區別),它只是簡單地為元素設置CSS的sty ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...