https://codepen.io/vicksiyi/pen/oKGJzL
动作 | 备注 |
---|---|
抓取(采集) | 桌面数据 |
编码(压缩) | 桌面数据 |
传输 | 桌面数据 |
解码 | 桌面数据 |
渲染 | 桌面数据 |
键盘、鼠标事件、处理事件 等 | 信令控制 |
WebRTC 对于桌面的采集与 RDP/VNC 使用的技术是相同的,都是利用各平台所提供的相关 API 进行桌面的抓取。以 Windows 为例,可以使用下列 API 进行桌面的抓取。
WebRTC 对桌面的编码使用的是视频编码技术,即 H264/VP8 等;但 RDP/VNC 则不一样,它们使用的是图像压缩技术。使用视频编码技术的好处是压缩率高,而坏处是在网络不好的情况下会有模糊等问题。
编码后的桌面数据会通过流媒体传输协议发送到观看端。对于 WebRTC 来说,当网络有问题时,数据是可以丢失的。但对于 RDP/VNC 来说,桌面数据一定不能丢失。
WebRTC 对收到的桌面数据通过视频解码技术解码,而 RDP/VNC 使用的是图像解码技术(可对比第二个环节)。
一般会通过 OpenGL/D3D 等 GPU 进行渲染,这个 WebRTC 与 RDP/VNC 都是类似的。
1、抓取桌面
var promise = navigator.mediaDevices.getDisplayMedia(constraints);
注意:navigator.mediaDevices.getUserMedia(constraints)与上面的区别,getUserMedia()音频和视频都可以同时采集,但是getDisplayMedia()不能在采集桌面的同时采集音频
抓取桌面关键代码
; (
() => {
// 只有在 PC 下才能抓取桌面
if (ifMachine.isChrome && ifMachine.isPc) {
// 开始捕获桌面数据
navigator.mediaDevices.getDisplayMedia({
video: {
width: 640,
height: 480,
frameRate: 15,
facingMode: 'enviroment'
},
audio: false
})
.then((stream) => {
window.stream = stream;
videoplay.srcObject = stream
})
.catch((err) => {
console.log('getDisplayMedia error:', err);
});
return true;
}
return false;
}
)();
录制关键代码
需参考:《音视频直播系统构建(四) | 音视频数据录制》
完整代码:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
</head>
<style>
.rowShow {
display: flex;
flex-direction: row;
}
</style>
<body>
<div class="rowShow">
<div>
<video autoplay playsinline id="player"></video>
</div>
<div>
<video autoplay playsinline id="recvideo"></video>
</div>
</div>
<button id="record">start Record</button>
<button id="recplay" disabled>Play</button>
<button id="download" disabled>Download</button>
</body>
<script>
'use strict';
let buffer;
let mediaRecorder;
let videoplay = document.querySelector("video#player")
let record = document.querySelector("button#record")
let recplay = document.querySelector('button#recplay');
let btnDownload = document.querySelector('button#download');
let recvideo = document.querySelector('video#recvideo')
// 判断是否为PC端的Chrome
let ifMachine = (() => {
var ua = navigator.userAgent,
isWindowsPhone = /(?:Windows Phone)/.test(ua),
isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
isAndroid = /(?:Android)/.test(ua),
isFireFox = /(?:Firefox)/.test(ua),
isChrome = /(?:Chrome|CriOS)/.test(ua),
isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
isPhone = /(?:iPhone)/.test(ua) && !isTablet,
isPc = !isPhone && !isAndroid && !isSymbian;
return {
isChrome: isChrome,
isPc: isPc
};
})();
let handleDataAvailable = (e) => {
if (e && e.data && e.data.size > 0) {
buffer.push(e.data);
}
}
record.onclick = () => {
buffer = [];
// 设置录制下来的多媒体格式
var options = {
mimeType: 'video/webm;codecs=vp8'
}
// 判断浏览器是否支持录制
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not supported!`);
return;
}
try {
// 创建录制对象
mediaRecorder = new MediaRecorder(window.stream, options);
} catch (e) {
console.error('Failed to create MediaRecorder:', e);
return;
}
// 当有音视频数据来了之后触发该事件
mediaRecorder.ondataavailable = handleDataAvailable;
// 开始录制
mediaRecorder.start(10);
record.disabled = true;
recplay.disabled = false;
}
recplay.onclick = () => {
mediaRecorder.stop(10);
recplay.disabled = true;
btnDownload.disabled = false;
let blob = new Blob(buffer, { type: 'video/webm' });
recvideo.src = window.URL.createObjectURL(blob);
recvideo.srcObject = null;
recvideo.controls = true;
recvideo.play();
}
btnDownload.onclick = () => {
var blob = new Blob(buffer, { type: 'video/webm' });
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.style.display = 'none';
a.download = new Date();
a.click();
}
; (
() => {
// 只有在 PC 下才能抓取桌面
if (ifMachine.isChrome && ifMachine.isPc) {
// 开始捕获桌面数据
navigator.mediaDevices.getDisplayMedia({
video: {
width: 640,
height: 480,
frameRate: 15,
facingMode: 'enviroment'
},
audio: false
})
.then((stream) => {
window.stream = stream;
videoplay.srcObject = stream
})
.catch((err) => {
console.log('getDisplayMedia error:', err);
});
return true;
}
return false;
}
)();
</script>
</html>
注意:录制桌面的 API,目前很多浏览器支持得还不够好,只有 Chrome 浏览器相对比较完善。