前一章节了解了屏幕分享的API,感觉跟我们常用的“屏幕共享”好像。
那么可不可以用此进行一个屏幕录制呢?
“纸上得来终觉浅,觉知此事要躬行。”看着挺简单的一个东西,没有落实都算说大话。
首先画上三个按钮:
<button @click="start" :disabled="disabled.start">开始录制button>
<button @click="stop" :disabled="disabled.stop">结束录制button>
<button @click="download" :disabled="disabled.download">下载文件button>
添加上简单的样式:
button {
margin: 0 1em 1em 0;
padding: 0.5em 1.2em 0.6em 1.2em;
border: none;
border-radius: 4px;
background-color: #d84a38;
font-family: 'Roboto', sans-serif;
font-size: 0.8em;
color: white;
cursor: pointer;
}
button:hover {
background-color: #c03434;
}
button[disabled] {
background-color: #c03434;
pointer-events: none;
}
初始化数据:
data() {
return {
// 本地流
stream: null,
// 媒体录制
mediaRecorder: null,
// 数据块
chunks: [],
// 录制结果
recording: null,
// 按钮禁用
disabled: {
start: false,
stop: true,
download: true
}
}
},
需要的方法:
methods: {
// 获取屏幕分享的权限
openScreenCapture() {
...
},
// 开始屏幕分享录制
async start() {
....
},
// 停止屏幕分享录制
stop() {
...
},
// 下载录制的视频内容
download() {
...
}
}
ok~ 下面进入每个方法内部看看都需要些什么操作。
首先我们要获取屏幕分享的权限,
由于每个浏览器的实现不同,所以这里需要做个兼容处理。
// 获取屏幕分享的权限
openScreenCapture() {
if (navigator.getDisplayMedia) {
return navigator.getDisplayMedia({
video: true });
} else if (navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia({
video: true });
} else {
return navigator.mediaDevices.getUserMedia({
video: {
mediaSource: 'screen' },
});
}
},
当点击“开始录制”按钮后,依次设置三个按钮的禁用状态,
如果之前录制的内容没有清空,那么就用revokeObjectURL方法移除。
获取屏幕分享权限后,实例化一个MediaRecorder对象进行录制存储。
监听dataavailable,当有可用数据时,将其push进数据块中进行存储。
// 开始屏幕分享录制
async start() {
this.disabled.start = true;
this.disabled.stop = false;
this.disabled.download = true;
if (this.recording) {
window.URL.revokeObjectURL(this.recording);
}
// 获取屏幕分享权限
this.stream = await this.$options.methods.openScreenCapture();
// 实例化一个MediaRecorder对象
this.mediaRecorder = new MediaRecorder(this.stream, {
mimeType: 'video/webm'});
// 监听可用数据
this.mediaRecorder.addEventListener('dataavailable', event => {
if (event.data && event.data.size > 0) {
this.chunks.push(event.data);
}
});
// 开始录制
this.mediaRecorder.start(10);
},
当点击“停止录制”按钮后,需要将数据块保存到一个内存URL中方便后续下载使用。
// 停止屏幕分享录制
stop() {
this.disabled.start = true;
this.disabled.stop = true;
this.disabled.download = false;
// 停止录制
this.mediaRecorder.stop();
// 释放MediaRecorder
this.mediaRecorder = null;
// 停止所有流式视频轨道
this.stream.getTracks().forEach(track => track.stop());
// 释放getDisplayMedia或getUserMedia
this.stream = null;
// 获取当前文件的一个内存URL
this.recording = window.URL.createObjectURL(new Blob(this.chunks, {
type: 'video/webm'}));
},
当点击“下载文件”按钮时,更新下载元素的链接href,并自动触发点击事件进行弹窗提示下载。
// 下载录制的视频内容
download() {
this.disabled.start = false;
this.disabled.stop = true;
this.disabled.download = true;
const downloadLink = document.querySelector('a#download');
downloadLink.href = this.recording;
// download 规定作为文件名来使用的文本
downloadLink.download = 'screen-recording.webm';
downloadLink.click();
}
当进行完以上操作后,发现确实将屏幕分享的导出一段视频了。
但是…
这个视频是没有声音的,音量按钮处为一个“静音”标识,且不能调节音量大小。
getDisplayMedia 默认只支持视频轨道,不支持音频轨道,
反正我试了几个浏览器均不支持音频轨道,没能验证有的博客写的如下开启音频轨道:
navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
})
不过,在经过上一章节的学习,我们知道MediaStream是由多个MediaStreamTrack组成的,
那么应该就可以给当前getDisplayMedia获取的视频轨道,再加上一个音频轨道,组成一个MediaStream。
其他部分不用更改,只用在MediaRecorder录制这个MediaStream之前,将其进行改造即可。
...
// 获取麦克风权限
const audioTrack = await navigator.mediaDevices.getUserMedia({
audio: true });
// 获取屏幕分享权限
this.stream = await this.$options.methods.openScreenCapture();
// 给MediaStream添加音频轨道
this.stream.addTrack(audioTrack.getAudioTracks()[0]);
// 实例化一个MediaRecorder对象
this.mediaRecorder = new MediaRecorder(this.stream, {
mimeType: 'video/webm'});
...