淺析 Web 錄屏技術(shù)方案與實(shí)現(xiàn)
錄屏技術(shù)方案與實(shí)現(xiàn)
https://www.zoo.team/article/webrtc-screen

前言
隨著互聯(lián)網(wǎng)技術(shù)飛速發(fā)展,網(wǎng)頁(yè)錄屏技術(shù)已趨于成熟。例如可將錄屏技術(shù)運(yùn)用到在線考試中,實(shí)現(xiàn)遠(yuǎn)程監(jiān)考、屏幕共享以及錄屏等;而在我們開(kāi)發(fā)人員研發(fā)過(guò)程中,對(duì)于部分偶發(fā)事件,異常監(jiān)控系統(tǒng)僅僅只能告知程序出錯(cuò),而不能清晰的告知錯(cuò)誤的復(fù)現(xiàn)路徑,而錄屏技術(shù)或許能幫我們定位并復(fù)現(xiàn)問(wèn)題。那么本文將從有感錄屏和無(wú)感錄屏兩方面給讀者分享一下錄屏這項(xiàng)技術(shù),希望可以幫助你對(duì)網(wǎng)頁(yè)錄屏有一個(gè)初步認(rèn)識(shí)。
什么是有感錄屏?
有感錄屏一般指通過(guò)獲得用戶的授權(quán)或者通知用戶接下來(lái)的操作將會(huì)被錄制成視頻,并且在錄制過(guò)程中,用戶有權(quán)關(guān)閉中斷錄屏。即無(wú)論在錄屏前還是錄屏的過(guò)程中,用戶都始終能夠決定錄屏能否進(jìn)行。
基于 WebRTC 的有感錄屏
常見(jiàn)的有感錄屏方案主要是通過(guò)?WebRTC?(https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API) 錄制。WebRTC?是一套基于音視軌的實(shí)時(shí)數(shù)據(jù)流傳播的技術(shù)方案。由瀏覽器提供的原生 API navigator.mediaDevices.getDisplayMedia?方法實(shí)現(xiàn)提示用戶選擇和授權(quán)捕獲展示的內(nèi)容或窗口,進(jìn)而將獲取 stream (錄制的屏幕音視流)。我們可以對(duì) stream 進(jìn)行轉(zhuǎn)化處理,轉(zhuǎn)成相對(duì)應(yīng)的媒體數(shù)據(jù),并將其數(shù)據(jù)存儲(chǔ)。后續(xù)需要回溯該次錄制內(nèi)容時(shí),則取出媒體數(shù)據(jù)進(jìn)行播放。
具體的有感錄屏流程如下:

實(shí)現(xiàn)初始化錄屏和數(shù)據(jù)存儲(chǔ)
使用?navigator.mediaDevices.getDisplayMedia?初始化錄屏,觸發(fā)彈窗獲取用戶授權(quán),效果圖如下所示:

實(shí)現(xiàn) WebRTC 初始化錄屏核心代碼如下:
const?tracks?=?[];?//?媒體數(shù)據(jù)
const?options?=?{
??mimeType?:?"video/webm;?codecs?=?vp8",?//?媒體格式
};
let?mediaRecorder;
//?初始化請(qǐng)求用戶授權(quán)監(jiān)控
navigator.mediaDevices.getDisplayMedia(constraints).then((stream)?=>?{
??//?對(duì)音視流進(jìn)行操作
??startFunc(stream);
});
//?開(kāi)始錄制方法
function?start(stream)?{
??//?創(chuàng)建?MediaRecorder?的實(shí)例對(duì)象,對(duì)指定的媒體流進(jìn)行錄制
??mediaRecorder?=?new?MediaRecorder(stream,?options);
??//?當(dāng)生成媒體流數(shù)據(jù)時(shí)觸發(fā)該事件,回調(diào)傳參?event?指本次生成處理的媒體數(shù)據(jù)
??mediaRecorder.ondataavailable?=?event?=>?{
?????if(event?.data?.size?>?0){
??????tracks.push(event.data);?//?存儲(chǔ)媒體數(shù)據(jù)
????}
??};
??mediaRecorder.start();
??console.log("************開(kāi)始錄制************")
};
//?結(jié)束錄制方法
function?stop()?{
??mediaRecorder.stop();
??console.log("************錄制結(jié)束************")
}
//?定義constraints數(shù)據(jù)類型
interface?constraints?{
??audio:?boolean?|?MediaTrackConstraints,?//?指定是否請(qǐng)求音軌或者約束軌道屬性值的對(duì)象
??video:?boolean?|?MediaTrackConstraints,?//?指定是否請(qǐng)求視頻軌道或者約束軌道屬性值的對(duì)象
}
實(shí)現(xiàn)錄屏回溯
獲取該次錄屏的媒體數(shù)據(jù),可以將其轉(zhuǎn)成 blob 對(duì)象,并且生成 blob對(duì)象的 url 字符串,再賦值 video.src 中,便可以回放到錄制結(jié)果,回溯的視頻效果如下:

錄屏回溯方法的核心代碼如下所示:
//?回放錄制內(nèi)容
function?replay()?{
??const?video?=?document.getElementById("video");
??const?blob?=?new?Blob(tracks,?{type?:?"video/webm"});
??video.src?=?window.URL.createObjectURL(blob);
??video.srcObject?=?null;
??video.controls?=?true;
??video.play();
}
實(shí)現(xiàn)實(shí)時(shí)直播功能
由于存儲(chǔ)的媒體數(shù)據(jù)是實(shí)時(shí)的,因此可以利用該數(shù)據(jù)實(shí)現(xiàn)直播功能。通過(guò)給 video.srcObject 賦值媒體流可以實(shí)現(xiàn)直播功能。
實(shí)現(xiàn)實(shí)時(shí)直播核心代碼如下:
//?直播
function?live()?{
??const?video?=?document.getElementById("video");
??video.srcObject?=?window.stream;
??video.controls?=?true;
??video.play();
}
瀏覽器兼容性

什么是無(wú)感錄屏?
無(wú)感錄屏指在用戶無(wú)感知的情況,對(duì)用戶在頁(yè)面上的操作進(jìn)行錄制。實(shí)現(xiàn)上與有感錄制區(qū)別在于,無(wú)感錄制通常是利用記錄頁(yè)面的 DOM 來(lái)進(jìn)行錄制。常見(jiàn)的有 canvas 截圖繪制視頻和 rrweb 錄制等方案。
canvas 截圖繪制視頻
用戶在瀏覽頁(yè)面時(shí),可以通過(guò) canvas 繪制多個(gè) DOM 快照截圖,再將多個(gè)截圖合并成一段錄屏視頻。但是考慮到假設(shè)視頻幀數(shù)為 30 幀,幀數(shù)代表著每秒所需的截圖數(shù)量,為了視頻的流暢和清晰,每張截圖為 400 KB ,那么當(dāng)視頻長(zhǎng)度為 1 分鐘,則需要上傳 703.125 MB 的資源,這么大的帶寬浪費(fèi)無(wú)疑會(huì)造成性能,甚至影響用戶體驗(yàn),不推薦使用,也不在此詳細(xì)介紹本方案實(shí)現(xiàn)。
rrweb 錄制
rrweb?(record and replay the web) 是一個(gè)對(duì)于 DOM 錄制的支持性非常好,利用現(xiàn)代瀏覽器所提供的強(qiáng)大 API 錄制并回放任意 web 界面中的用戶操作,能夠?qū)㈨?yè)面 DOM 結(jié)構(gòu)通過(guò)相應(yīng)算法高效轉(zhuǎn)換 JSON 數(shù)據(jù)的開(kāi)源庫(kù)。相比較于使用 canvas 繪制錄屏,rrweb 在保證錄制不掉幀的基礎(chǔ)上,讓網(wǎng)絡(luò)傳輸數(shù)據(jù)更加快速和輕量化,極大地優(yōu)化了網(wǎng)絡(luò)性能。
rrweb?開(kāi)源庫(kù)主要由?rrweb-snapshot、rrweb?和?rrweb-play?三部分組成,并且提供了動(dòng)作篩選,數(shù)據(jù)加密、數(shù)據(jù)壓縮、數(shù)據(jù)切片、屏蔽元素等功能。

rrweb-snapshot
rrweb-snapshot?提供?snapshot?和?rebuild?兩個(gè) API,分別實(shí)現(xiàn)生成可序列化虛擬 DOM 快照的數(shù)據(jù)結(jié)構(gòu)和將其數(shù)據(jù)結(jié)構(gòu)重建為對(duì)應(yīng) DOM 節(jié)點(diǎn)的兩個(gè)功能。
snapshot?將 DOM 及其狀態(tài)轉(zhuǎn)化為可序列化的數(shù)據(jù)結(jié)構(gòu)并添加唯一標(biāo)識(shí) id,使得一個(gè) id 映射對(duì)應(yīng)的一個(gè) DOM 節(jié)點(diǎn),方便后續(xù)以增量的方式來(lái)操作。
首先需要通過(guò)深拷貝 document 生成初始化 DOM 快照。
//?深拷貝?document?節(jié)點(diǎn)
const?docEl?=?document.documentElement.cloneNode(true);
//?回放時(shí)再將深拷貝的節(jié)點(diǎn)掛在回去即可
document.replaceChild(docEl,?document.documentElement);
由于獲取到的 DOM 對(duì)象并不是可序列化的,因此仍需要將其轉(zhuǎn)成特定的文本格式(如 JSON)進(jìn)行傳輸,否則無(wú)法做到遠(yuǎn)程錄制。在實(shí)現(xiàn) DOM 快照可序列化的過(guò)程中,還需對(duì)數(shù)據(jù)進(jìn)行特殊處理:
將相對(duì)路徑改成絕對(duì)路徑; 將頁(yè)面引用的樣式改成內(nèi)聯(lián)樣式; 禁止腳本運(yùn)行,被錄制頁(yè)面中的所有 JavaScript 都不應(yīng)該被執(zhí)行。把? 欧美操逼一区二区 | 免费手机在线看日韩 | 午夜视频成人 | www色老板| 免费高清无码视频在线观看 |
