前端屏幕錄製?截屏?網頁生成圖片?幀圖?說到錄屏,我一開始想到的是前面這些詞。大體的想法是持續的生成當前頁面的截圖,而後把這些幀圖再合併成一個視頻文件。前端頁面生成圖片咱們應該比較熟悉的是 html2canvas。另外也有一些現成的庫可使用來進行屏幕的錄製, RecordRTC上就有不少屏幕錄製的實現。有聲音(Audio)、視頻(Video)、屏幕(Screen)的錄製;有針對canvas的錄製等等,一共有三十多個示例。這裏主要想簡單的講一講原生的 Screen Capture API。參見: Using the Screen Capture API
navigator.mediaDevices.getDisplayMedia()css
該方法會返回一個promise, 該promise會resolve當前屏幕內容的實時數據流。html
使用 async / await 實現以下:前端
async function startCapture(displayMediaOptions) { let captureStream = null; try { captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions); } catch(err) { console.error("Error: " + err); } return captureStream; }
使用 promise 的方式實現以下:web
function startCapture(displayMediaOptions) { let captureStream = null; return navigator.mediaDevices.getDisplayMedia(displayMediaOptions) .catch(err => { console.error("Error:" + err); return null; }); }
咱們在獲取屏幕數據的時候有可能會獲取到一些敏感信息,全部在使用getDisplayMedia的時候,爲了安全考慮,會彈出一個選擇框,然用戶本身選擇須要共享那一部分的內容。能夠共享當前屏幕,也能夠共享其餘的應用窗口和瀏覽器的其餘標籤頁。canvas
2、參數配置:
咱們在上面的實現中能夠看到, 傳遞給startCapture函數的參數爲displayMediaOptions。這個參數是用於配置返回數據流的。數據形式以下:promise
const displayMediaOptions = { video: { cursor: "never" }, // 視頻信息的設置 audio: false, // 是否包含音頻信息 logicalSurface: false, // 設置是否包含所選屏幕外區域的一些信息 };
開能夠針對音視頻作詳細的配置:瀏覽器
const gdmOptions = { video: { cursor: "always" // 始終顯示鼠標信息 }, // audio 配置信息是可選的 audio: { echoCancellation: true, noiseSuppression: true, sampleRate: 44100 } }
HTML:安全
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Screen Record</title> <link rel="stylesheet" href="./css/index.css"> </head> <body> <p>This example shows you the contents of the selected part of your display. Click the Start Capture button to begin.</p> <p><button id="start">Start Capture</button> <button id="stop">Stop Capture</button></p> <video id="video" autoplay></video> <br> <strong>Log:</strong> <br> <pre id="log"></pre> <script src="./js/index.js"></script> </body> </html>
CSS:服務器
#video { border: 1px solid #999; width: 98%; max-width: 860px; } .error { color: red; } .warn { color: orange; } .info { color: darkgreen; }
JS:websocket
const videoElem = document.getElementById("video"); const logElem = document.getElementById("log"); const startElem = document.getElementById("start"); const stopElem = document.getElementById("stop"); // Options for getDisplayMedia() const displayMediaOptions = { video: { cursor: "never" }, audio: false }; // Set event listeners for the start and stop buttons startElem.addEventListener("click", function(evt) { startCapture(); }, false); stopElem.addEventListener("click", function(evt) { stopCapture(); }, false); console.log = msg => logElem.innerHTML += `${msg}<br>`; console.error = msg => logElem.innerHTML += `<span class="error">${msg}</span><br>`; console.warn = msg => logElem.innerHTML += `<span class="warn">${msg}<span><br>`; console.info = msg => logElem.innerHTML += `<span class="info">${msg}</span><br>`; async function startCapture() { logElem.innerHTML = ""; try { videoElem.srcObject = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions); dumpOptionsInfo(); } catch(err) { console.error("Error: " + err); } } function stopCapture(evt) { let tracks = videoElem.srcObject.getTracks(); tracks.forEach(track => track.stop()); videoElem.srcObject = null; } function dumpOptionsInfo() { const videoTrack = videoElem.srcObject.getVideoTracks()[0]; console.info("Track settings:"); console.info(JSON.stringify(videoTrack.getSettings(), null, 2)); console.info("Track constraints:"); console.info(JSON.stringify(videoTrack.getConstraints(), null, 2)); }
效果以下:
點擊Start Capture 以後選擇須要共享的部分就能夠共享以下的內容:
點擊Stop Capture便可˙中止錄製共享。這個例子只是調取接口獲取到當前分享屏幕的數據流,並經過video的形式顯示出來。咱們在拿到數據流信息這個,能夠把這些信息上傳到服務器,生成相應的視頻文件。也能夠結合websocket之類的處理方式,實現實時的屏幕共享功能。