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 都不能播放那还讨论个什么鬼)
创建若干变量并初始化:
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` 方法播放音频:
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` 中:
document.querySelector('body').appendChild(audio);
嗯,以上的这些代码就能实现一个本来只要三行代码就完成的工作了。具体效果可以看这里:MSE Playground 01。
下面需要解决的问题是,为什么刚开始尝试使用的 M4A 格式无法正常播放,这个坑死人了我哪知道只能 MP3 啊浪费了两个多小时……。
由于目前来看,MediaSource 的表现在各个浏览器中并不一致,同时支持的格式就目前而言还是十分有限,这个系列估计就这一篇了吧 23333(逃