一、共享桌面原理
-
共享桌面在直播系統中是一個必備功能
-
共享者:每秒鐘抓取多次螢幕,每次抓取的螢幕都與上一次抓取的螢幕做比較,取它們的差值,然後對差值進行壓縮;如果是第一次抓屏或切幕的情況,即本次抓取的螢幕與上一次抓取螢幕的變化率超過 80% 時,就做全屏的幀內壓縮。最後再將壓縮後的資料通過傳輸模組傳送到觀看端;資料到達觀看端後,再進行解碼,這樣即可還原出整幅圖片並顯示出來
-
遠端控制端:當使用者通過滑鼠點選共享桌面的某個位置時,會首先計算出滑鼠實際點選的位置,然後將其作為引數,通過信令傳送給共享端。共享端收到信令後,會模擬本地滑鼠,即呼叫相關的 API,完成最終的操作
-
共享桌面的過程:抓屏、壓縮編碼、傳輸、解碼、顯示、控制
二、抓取桌面
-
瀏覽器 WebRTC 中提供了方法
var promise = navigator.mediaDevices.getDisplayMedia(constraints)
進行桌面的抓取 -
共享桌面,大多數人知道的可能是RDP(Remote Desktop Protocal)協議,它是 Windows 系統下的共享桌面協議;還有一種更通用的遠端桌面控制協議 VNC(Virtual Network Console),它可以實現在不同的作業系統上共享遠端桌面,而 TeamViewer、Todesk 都是使用的該協議
-
遠端桌面協議一般分為桌面資料處理與信令控制兩部分
-
桌面資料:包括了桌面的抓取、編碼、壓縮、傳輸、解碼和渲染
-
信令控制:包括鍵盤事件、滑鼠事件以及接收到這些事件訊息後的相關處理等
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>share desktop by WebRTC</title>
</head>
<body>
<button onclick="shareDesktop()">抓取桌面</button>
</body>
<script>
// 抓取桌面
function shareDesktop() {
// 只有在 PC 下才能抓取桌面
if (IsPC()) {
// 開始捕獲桌面資料
navigator.mediaDevices.getDisplayMedia({ video: true })
.then(getDeskStream)
.catch(handleError);
return true;
}
return false;
}
// 得到桌面資料流
function getDeskStream(stream) {
localStream = stream;
}
// 判斷是否是PC
function IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
</script>
</html>
三、桌面展示
-
桌面採集後,就可以通過 HTML 中的
<video>
標籤將採集到的桌面展示出來 -
當桌面資料被抓到之後,會觸發
getDeskStream
函式 -
在該函式中將獲取到的 stream 與 video 標籤聯絡起來,這樣就可以顯示桌面了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>share desktop by WebRTC</title>
</head>
<body>
<video autoplay playsinline id="deskVideo"></video>
<button onclick="shareDesktop()">抓取桌面</button>
</body>
<script>
var deskVideo = document.querySelect("video/deskVideo");
// 抓取桌面
function shareDesktop() {
// 只有在 PC 下才能抓取桌面
if (IsPC()) {
// 開始捕獲桌面資料
navigator.mediaDevices.getDisplayMedia({ video: true })
.then(getDeskStream)
.catch(handleError);
return true;
}
return false;
}
// 得到桌面資料流並播放
function getDeskStream(stream) {
localStream = stream;
deskVideo.srcObject = stream;
}
// 判斷是否是PC
function IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
</script>
</html>
四、錄製桌面視訊
-
錄製視訊其實在上一章中詳細說過,這裡就不再重複了,這裡只貼一下大概的邏輯程式碼
-
首先通過
getDisplayMedia
方法獲取到本地桌面資料 -
然後將該流當作引數傳給
MediaRecorder
物件 -
並實現
ondataavailable
事件,最終將音視訊流錄製下來 -
具體實現請參考上一篇文章自己進行完善
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>share desktop by WebRTC</title>
</head>
<body>
<button onclick="startRecord()">開始錄製</button>
</body>
<script>
var buffer;
function startRecord() {
// 定義一個陣列,用於快取桌面資料,最終將資料儲存到檔案中
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(localStream, options);
} catch (e) {
console.error('Failed to create MediaRecorder:', e);
return;
}
// 當捕獲到桌面資料後,該事件觸發
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(10);
}
function handleDataAvailable(e) {
if (e && e.data && e.data.size > 0) {
buffer.push(e.data);
}
}
</script>
</html>