MediaSource 是 HTML5 中的一个实验性特性,用于给 HTMLMediaElement
对象提供数据源。这里的数据源通常是使用 XMLHttpRequest
获得的数据。在 XHR 取得数据后,我们可以使用 JavaScript 对数据进行一些操作,比如提取 ID3、修改封装类型等等。 某 bilibili 开源的 Flv.js 就是使用这个特性实现的在 HTML5 环境下播放 H264 + AAC 格式的 FLV 视频。
最近在写 Nano Player
的时候遇到了两个比较尴尬的问题:1、ID3 信息必须手动指定;2、网易云音乐上下载的 MP3 由于某些原因必须缓冲 2MB 才能播放(详见 MP3 缓冲 2MB 才开始播放的解决方法)。于是想到是不是可以用这个 MediaSource 来暴改 MP3 呢?我也不知道
不管怎样,要用这个 MSE 来解决问题,首先就是要用它来播放文件(如果获得的数据直接喂给 MSE 都不能播放那还讨论个什么鬼)
创建若干变量并初始化:
1
2
3
4
5
6
|
let mediaSource = new MediaSource();
let audio = new Audio();
let media = "audio.mp3";
audio.src = URL.createObjectURL(mediaSource);
audio.controls = "controls";
|
然后是对 sourceopen
事件添加监听。当 sourceopen
事件触发后,我们需要创建一个 sourceBuffer
,随后使用 XMLHttpRequest
获得媒体文件的内容,并附加到这个 sourceBuffer
内。当以上工作完成后,调用 play
方法播放音频:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mediaSource.addEventListener("sourceopen", () => {
let sourceBuffer = mediaSource.addSourceBuffer("audio/mpeg");
let xhr = new XMLHttpRequest();
xhr.open("GET", media);
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = () => {
if (xhr.readyState === xhr.DONE && xhr.status === 200) {
sourceBuffer.addEventListener("updateend", () => {
mediaSource.endOfStream();
audio.play();
});
sourceBuffer.appendBuffer(xhr.response);
}
};
xhr.send();
});
|
最后,为了方便检查,将 audio
添加到 body
中:
1
|
document.querySelector("body").appendChild(audio);
|
嗯,以上的这些代码就能实现一个本来只要三行代码就完成的工作了。 具体效果可以看这里:MSE Playground 01。
下面需要解决的问题是,为什么刚开始尝试使用的 M4A 格式无法正常播放 ,这个坑死人了我哪知道只能 MP3 啊浪费了两个多小时……。
由于目前来看,MediaSource 的表现在各个浏览器中并不一致,同时支持的格式就目前而言还是十分有限,这个系列估计就这一篇了吧 23333(逃
参考链接:
- Media Source Extensions
- MediaSource - Web APIs | MDN
- Media Source Extensions for Audio
- HTML5 Media - types and codecs examples + canPlayType(type) test
- html5 video tag codecs attribute
- nickdesaulniers/netfix: Let’s build a Netflix