作者 | 劉博(又拍雲多媒體開發工程師)
目前為了滿足比較火熱的行動 Web 端直播需求,一系列的 HTML5 直播技術迅速的發展起來。
常見的可用於 HTML5 的直播技術有 HLS、WebSocket 與 WebRTC。今天我向大家介紹WebSocket 與 MSE 相關的技術要點,並在最後透過一個實例來展示具體用法。
WebSocket 協定介紹
WebSocket Client/Server API介紹
#MSE 介紹
fMP4 介紹
Demo 展示
> 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 ...]
> if(window.WebSocket) { // WebSocket代码 }
> var ws = new WebSocket('ws://localhost:8327');
ws.binaryType = 'arraybuffer';
WebSocket Golang API
#伺服器端WebSocket 函式庫我推薦使用Google 自己的 #http://golang.org/x/net/websocket,可以很方便的與net/http 一起使用。也可以將 WebSocket 的 handler function 透過 websocket.Handler轉換成 http.Handler,這樣就可以跟 net/http 函式庫一起使用了。
然後透過 websocket.Message.Receive 來接收數據,透過 websocket.Message.Send 來發送數據。
具體程式碼可以看下面的 Demo 部分。
在介紹 MSE 之前,我們先來看看 HTML5
HTML5
不支援流
不支援DRM 和加密
很難自訂控制, 以及保持跨瀏覽器的一致性
#編解碼和封裝在不同瀏覽器支援不同
MSE 是解決HTML5 的流程問題。
Media Source Extensions(MSE)是 Chrome、Safari、Edge 等主流瀏覽器支援的一個新的Web API。 MSE 是一個 W3C 標準,允許 JavaScript 動態建構
透過使用 MSE,你可以動態地修改媒體串流而不需要任何外掛程式。這讓前端JavaScript可以做更多的事情—— 在 JavaScript 進行轉封裝、處理,甚至轉碼。
雖然 MSE 不能讓串流直接傳輸到 media tags 上,但是 MSE 提供了建立跨瀏覽器播放器的核心技術,讓瀏覽器透過JavaScript API來推音影片到 media tags 上。
透過 caniuse 來檢查是否瀏覽器支援情況。
透過 MediaSource.isTypeSupported() 可以進一步檢查 codec MIME 類型是否支援。
比較常用的影片封裝格式有 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 檔案透過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 流類型
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](http://nickdesaulniers.github.io/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 播放输出。
详情了解:https://www.upyun.com/products/live
推荐阅读:
无连麦,不直播,都在说的直播利器连麦互动到底是啥?
技术干货|移动直播六大关键技术详解
又拍直播云SDK,自带美颜、滤镜、消噪、人声增益等功能
又拍直播云功能处理篇:转码、录制、视频水印、视频截图
又拍直播云功能基础篇:推流和拉流、多协议输出、多访问方式、回源端口自定义
又拍直播云功能高级篇:防盗链、秒级禁播、自动鉴黄、API接口
以上是WebSocket+MSE——HTML5 直播技術解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!