在常见的视频 APP 中,几乎都实现了视频分辨率切换功能。其中有一些会在点击切换分辨率后继续播放当前分辨率视频,稍有延迟后切换到新的分辨率视频,实现了视频分辨率的无缝切换。那么在移动端网页中,我们该如何实现视频分辨率的切换甚至无缝切换功能呢?
视频切换方式
在浏览器环境下,有两种方式可以切换视频:
- 直接修改 video 元素 src。
- 使用 MSE (Media Source Extensions) 播放视频,操作 SourceBuffer。
直接修改 video src 的方式必然会经历视频重新加载的过程,虽然能够实现切换,但无法实现无缝切换。
使用 MSE 的方式,通过操作 SourceBuffer 能够实现无缝切换视频分辨率。遗憾的是 MSE 存在兼容性问题, iOS Safari 不支持 MSE。
因此,在 iOS 中通过 video 元素是无法实现无缝切换的,我们仅在安卓上考虑无缝切换功能。
视频文件格式
mp4 和 m3u8 是最常见的两种视频文件格式,下面分析一下应该采取哪种视频文件格式。
MP4
mp4 文件由多个 box 组成,其中有三个主要的 box:
- ftyp(file type box):包含文件版本、兼容协议等信息。
- moov(movie box):包含所有媒体数据的描述信息。
- mdat(media data box):真正播放的媒体数据。
一个 mp4 视频想要达到可播放的状态,需要加载完整的 moov 和一部分 mdat 。而 moov 的大小和 mdat 的大小成正比。因此视频越长,需要加载的时间也越长。
mp4 视频不是分片的,只能通过修改 video 元素 src 的方式切换分辨率,必然会产生黑屏加载的过程,并且视频越大,加载时间越长。
fMP4
fragmented MP4 是分片化的 mp4,是 MPEG-DASH 协议使用的视频文件格式。(后文会说到 DASH 的兼容性问题,这里就不再分析 fMP4 了)
M3U8
m3u8 是 HLS (Apple HTTP Live Streaming)使用的视频文件格式。m3u8 文件实际上是 多个 ts 媒体片段的索引文件。它支持一层嵌套,在多分辨率的情况下会有多个 m3u8 文件,其中包含一个一级索引文件和多个二级索引文件:
一级索引文件中包含二级索引文件的地址(图中为相对地址)及分辨率、带宽等信息:
二级索引文件中包含片段时长(通常在10 秒左右)、ts 媒体段时长(不大于片段时长)及 ts文件地址:
通过解析一级索引文件可获得各个二级索引文件地址及分辨率信息;
通过解析二级索引文件可获得 ts 媒体片段的时长及文件地址。
流媒体协议选择
DASH 和 HLS 都能通过 MSE 实现无缝切换视频清晰度,我们选哪一个呢?
- DASH 是第一个基于 HTTP 的自适应流视频协议的国际标准。
- HLS 由苹果开发拥有,虽然不是国际标准,但是目前在业界中属于主流。
DASH 的出身更好,而且是国际标准,是未来的趋势。我们再看看兼容情况。
兼容性
MPEG-DASH 在 web 平台几乎无法使用,但可以通过 dash.js + MSE 来支持。
上文说过,MSE 也同样存在兼容性问题,仅在安卓设备及 iPadOS13+ 上能够使用,因此如果使用 DASH 协议,在 iOS 设备上无法播放。
HLS 在 iOS 和 安卓 上均有较好的兼容性,并且在不支持 HLS 的环境下可以通过 hls.js + MSE 来支持。
综上,因为 iOS 端不支持 MSE,MPEG-DASH 无法在 iOS 端使用,所以 HLS 是现阶段更加合适的自适应码率流媒体协议。
最终实现方案
实现视频分辨率切换功能,需要根据终端环境对 MSE 和 HLS 的支持情况采取不同的处理方式,在支持 MSE 的环境下才能够实现无缝切换。
具体的处理方式如下:
① 支持 MSE:
- 使用 hls.js ,传入 m3u8 一级索引文件地址。
- 通过修改 hls 实例上的 nextLevel 实现无缝切换分辨率。
② 不支持 MSE 但支持 HLS:
- 解析 m3u8 一级索引文件,获取多个不同分辨率的二级索引文件地址。
- 通过修改 video 元素 src 为不同的二级索引文件地址,实现切换视频分辨率。
③ 不支持 MSE 也不支持 HLS:
- 这种情况在主流设备中几乎不存在,考虑直接降级为播放 MP4 文件,不支持切换分辨率。
参考
- MSE https://developer.mozilla.org/zh-CN/docs/Web/API/Media_Source_Extensions_API
- MS https://developer.mozilla.org/zh-CN/docs/Web/API/MediaSource
- Adaptive Bitrate Streaming https://zh.wikipedia.org/wiki/基于HTTP的动态自适应流
- HLS协议介绍 https://www.jianshu.com/p/426425cad08a
- hls.js https://github.com/video-dev/hls.js