关于 web 视频播放
1. 视频的格式、编码
格式:视频格式也叫视频的封装格式,通俗地讲,视频格式就是一种规范,定义了在什么地方(位置)放什么内容。常见的格式有 mkv,mp4,mov,flv。
编码:视频是 音频 + 图像 的集合,所以视频编码实际上要分成音频编码和图像编码。编码方式实际上描述的就是数据的压缩方式。常见的编码有 h264 、vp8、vp9,以及还没普及的 h265
2. 浏览器如何解析一个视频?
- video 标签创建一个 DOM 对象,实例化一个 WebMediaPlayer
- player 驱使 Buffer 请求多媒体数据
- FFmpeg 进行解封装和音视频解码
- 把解码后的数据传给相应的渲染器对象进行渲染绘制
- video 标签显示或声卡播放
3. 浏览器对各种格式、编码的支持度
HTML5 Video Converter | Encoding.com
在实际测试过程中,mkv 格式、h264 编码的视频在 Mac Chrome 器中也可以播放,但在 Mac PC Safari 中不能播放
4. 我们如何准确知道一个视频能不能正常播放?
先说结论:我们并不能精确知道视频能否播放。
现代浏览器提供了两个 API 用来检测浏览器对视频的支持度。
- window.MediaSource.isTypeSupported, 这个方法支持传入一个包含视频 mimeType 和 codecs 的字符串,返回一个布尔值。
1 | var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; |
- video.canPlayType, 这个方法接受参数与上一个函数一致, 返回一个不精确的字符串描述
1 | type CanPlayTypeResult = "" | "maybe" | "probably"; |
接下来做一个简单的实验:
样品:
- 一个 mp4 格式、mpeg4 编码的视频 1602656111421.mp4 (video/mp4;codecs=”mpeg4,aac”)
- macOS 10.14.6
- Chrome 89.0.4389.90
在播放前用这 2 个函数检测, 打印结果
1 | console.log('avinfo: ', avinfo); |
结果如下:
结果表明,当前视频不支持,也确实不能正常播放。
于是我做了第二次实验:
一个 mp4 格式、h264编码的视频 bandicam 2021-01-28 11-12-47-568.mp4 (video/mp4;codecs=”h264,aac”)
这次打印的结果表明依然是不支持,然而事实确是:可以正常播放???!!!
对于完全不能播放(视频和音频)的情况,算是一种异常,开发者可以明确知道;
但是对音频或者视频二者之一不能播放的情况,只有依靠这两个函数来处理了,但根据上面的测试结果,这 2 个函数的检测实际上是不准确的,所以如果想要在视频播放异常加提示这件事情就变得困难
基于上述这个浏览器自身检测 API 不可信任的结论,我们似乎只能在用户侧维护一套浏览器普遍支持的视频 格式/编码 集合,如果不在这个集合里面就弹出类似这种提示,想要准确在合适的时机弹出,暂时没有找到比较完美的解决方案
5. 扩展浏览器播放能力:如何在 web 端播放浏览器不支持的视频?
目前主要有 2 个方案:
web 端转码(本地调用类似 FFmpeg、libde265 的 .wasm 版本解码)
淘宝前端做过类似的事情,但在实践中存在视频帧数不稳定、视频播放进度调整出现 bug 的问题,总的来说,截止到这篇文章发表的时候,该方案基本还处于小规模试验阶段(这篇文章提到一点是现代浏览器不能支持众多视频编码可能不是技术问题,而是有些编码解码器使用是要收费的)
花椒直播开发过一个 h265 播放器,但尚未开源,不过在文章评论页下找到一个开源项目:
项目主页给了一个 demo:https://github.com/goldvideo/h265player, 体验下来感觉也不是十分流畅,另外就是拖进度条时会出现页面 video 加载 loading 框不断跳动的问题,不是一个十分完美的版本,但是看起来可用
另外又有国人维护的另一个 EasyPlayer 的项目,看介绍已经投入生产环境使用,最近一次更新在 4 天前,看起来也有一点希望的样子
服务端转码
接云服务商转码服务,返回通用格式/编码的视频流