如果检查主流视频网站的视频,就会发现网站的 video 元素的 src 属性都是 blob开头的字符串。
为什么视频链接前面会有 blob 前缀?这是因为视频网站使用了这篇文章要讲的 MSE 来播放视频。
Media Source Extensions
虽然 video 很强大,但是还有很多功能 video 并不支持,比如直播,即时切换视频清晰度,动态更新音频语言等功能。
MSE(Media Source Extensions)就来解决这些问题,它是 W3C 的一种规范,如今大部分浏览器都支持。
它使用 video 标签加 JS 来实现这些复杂的功能。它将 video 的 src 设置为 MediaSource 对象,然后通过 HTTP 请求获取数据,然后传给 MeidaSource 中的 SourceBuffer 来实现视频播放。
如何将 MediaSource 和 video 元素连接呢?这就需要用到 URL.createObjectURL它会创建一个 DOMString 表示指定的 File 对象或 Blob(二进制大对象) 对象。这个 URL 的生命周期和创建它的窗口中的 document 绑定。
const video = document.querySelector('video')
const mediaSource = new MediaSource()
mediaSource.addEventListener('sourceopen', ({ target }) => {
URL.revokeObjectURL(video.src)
const mime = 'video/webm; codecs="vorbis, vp8"'
const sourceBuffer = target.addSourceBuffer(mime) // target 就是 mediaSource
fetch('/static/media/flower.webm')
.then(response => response.arrayBuffer())
.then(arrayBuffer => {
sourceBuffer.addEventListener('updateend', () => {
if (!sourceBuffer.updating && target.readyState === 'open') {
target.endOfStream()
video.play()
}
})
sourceBuffer.appendBuffer(arrayBuffer)
})
})
video.src = URL.createObjectURL(mediaSource)
addSourceBuffer 方法会根据给定的 MIME 类型创建一个新的 SourceBuffer对象,然后会将它追加到 MediaSource 的 SourceBuffers 列表中。
我们需要传入相关具体的编解码器(codecs)字符串,这里第一个是音频(vorbis),第二个是视频(vp8),两个位置也可以互换,知道了具体的编解码器浏览器就无需下载具体数据就知道当前类型是否支持,如果不支持该方法就会抛出 NotSupportedError 错误。更多关于媒体类型 MIME 编解码器可以参考 RFC 4281。
这里还在一开始就调用了 revokeObjectURL。这并不会破坏任何对象,可以在 MediaSource 连接到 video 后随时调用。它允许浏览器在适当的时候进行垃圾回收。
视频并没有直接推送到 MediaSource 中,而是 SourceBuffer,一个 MeidaSource中有一个或多个 SourceBuffer。每个都与一种内容类型关联,可能是视频、音频、视频和音频等。
视频格式
HTML5 标准指定时,想指定一种视频格式作为标准的一部分,所有浏览器都必须实现。但是对于 H.264 视频编码各个厂商产生的争论,主要是 H.264 非常强大(高画质、高压缩比、成熟的编解码器…),但是它也要高昂的授权费。Mozilla 这类免费浏览器,并没有从其开发的浏览器上获得直接收入,但是让 H.264 加入标准,它就要支付相应的授权费,所有认为是不可接受的。于是后来放弃了视频格式指定的统一,浏览器厂商可以自由选择支持的格式。
不过现在所有主流浏览器都支持 H.264 编码格式的视频,所有选择视频编码时优先选择 H.264 编码。