Media Source Extensions,缩写 MSE https://w3c.github.io/media-source/
平时我们开发中加入视频或者音频,都是使用video、audio组件,附加一个src属性
这种形式开发一般的没有问题,但是如果要做到动态改变清晰度、动态增加视频广告、等等的功能,就做不了了
看看b站
是一个blob url
平时在开发的时候,也遇到过blob url的情况
URL.createObjectURL
最终返回的也是一个blob url
1
| const blob = URL.createObjectURL(file.value.files[0]);
|
右键打开,啥也没有
这里就用到MediaSource
了
原理 🔗
具体的内部实现我也不理解,这里给一个官方的原理图
实现 🔗
已知我们有个按钮按一下,需要播放对应音频
用vue3写一个demo
1
2
3
4
5
6
7
8
9
10
| const audioRef = ref(document.createElement("audio"));
const mediaSource = new MediaSource();
onMounted(() => {
audioRef.value.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener("sourceopen", onSourceOpen);
});
function onSourceOpen() {
//
}
|
这里在mounted之后在进行监听回调
sourceBuffer
声明一个全局变量sourceBuffer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| let sourceBuffer
const mimeCodec = 'audio/mpeg'
function onSourceOpen() {
//
sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
sourceBuffer.addEventListener("updateend", function (_) {
// ...
console.log(mediaSource.readyState); // ended
});
sourceBuffer.addEventListener("error", function (error) {
console.log(error);
});
}
|
只有在mediaSource
状态是open
的情况下才能调用addSourceBuffer
方法
mimeCodec这里定义的是audio/mpeg
, 具体依情况来设定
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
模版中声明一个button, 并写出对应的play方法
1
2
3
| <template>
<button @click="play">play</button>
</template>
|
play执行时我们获取远程的音频文件
1
2
3
4
5
6
7
| function play(){
fetch("http://127.0.0.1:8081/1111.mp3", {})
.then((res) => {
console.log("res", res);
});
}
|
在获取到流文件的时候,我们需要加入到sourceBuffer
中,sourceBuffer
有个appendBuffer
方法
需要加入ArrayBuffer
格式的返回
fetch重新写一下
1
2
3
4
5
| fetch("http://127.0.0.1:8081/1111.mp3", {})
.then((res) => res.arrayBuffer())
.then((res) => {
sourceBuffer.appendBuffer(res);
});
|
在sourceBuffer添加完毕的时候播放音频
1
2
3
4
| sourceBuffer.addEventListener("updateend", function (_) {
mediaSource.endOfStream();
audioRef.value.play();
});
|
mediaSource.endOfStream
方法用于结束当前mediaSource
,表示流已经结束,不再添加数据
codecs 🔗
codecs时媒体源的编码格式,视频中mp4和avi肯定不是一个格式,音频中mp3和ogg等也不是一个编码格式
https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter
这里会出现格式不支持的情况,但是直接使用文件url的时候又可以
MSE中支持的格式和直接播放时支持的格式会不一样,可能MSE作为一个扩展,有版权问题吧
全部代码 🔗
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| <template>
<div>
<!-- <audio ref="audioRef"></audio> -->
<button @click="play">play</button>
</div>
</template>
<script>
import { defineComponent, onMounted, ref } from "@vue/composition-api";
export default defineComponent({
name: "DemoInput",
setup() {
const audioRef = ref(document.createElement("audio"));
const mediaSource = new MediaSource();
let mimeCodec = `audio/mpeg`;
onMounted(() => {
audioRef.value.muted = true;
audioRef.value.autoplay = true;
audioRef.value.controls = true;
audioRef.value.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener("sourceopen", onSourceOpen);
});
const getRemoteFile = () => {
const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetch("http://127.0.0.1:8081/1111.mp3", {})
.then((res) => res.arrayBuffer())
.then((res) => {
console.log("res", res);
sourceBuffer.addEventListener("updateend", function (_) {
mediaSource.endOfStream();
audioRef.value.play();
audioRef.value.muted = false;
console.log(mediaSource.readyState); // ended
});
sourceBuffer.addEventListener("error", function (error) {
console.log(error);
});
sourceBuffer.appendBuffer(res);
});
};
function play() {
getRemoteFile();
}
function onSourceOpen() {
//
}
return {
audioRef,
play,
};
},
});
</script>
|
References 🔗
https://w3c.github.io/media-source/
https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
https://joshuatz.com/posts/2020/appending-videos-in-javascript-with-mediasource-buffers/
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#response_objects
Issues 🔗
1. play() failed because the user didn’t interact with the document first 🔗
代码中不能出现加载页面后直接播放的逻辑,浏览器防止开发者打断用户,需要用户进行手动操作播放,除非设置媒体实例为muted = true时,可以播放
https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
2. Failed to execute ‘appendBuffer’ on ‘SourceBuffer’: Overload resolution failed. 🔗
buffer格式不对
https://stackoverflow.com/questions/71488781/uncaught-typeerror-failed-to-execute-appendbuffer-on-sourcebuffer-overload