当前为了满足比较火热的移动 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. 建立连接
> 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 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 文件 ▽