canvas實現(xiàn)將rrweb的錄制轉(zhuǎn)換為視頻

首先來實現(xiàn)canvas畫布內(nèi)容轉(zhuǎn)換視頻,canvas生成視頻主要需要captureStreammediaRecorder。

captureStream

canvas中有一個captureStream方法可以將普通畫布轉(zhuǎn)換成一個實時視頻捕獲的畫布,該方法返回一個MediaStream實例。
參數(shù):
frameRate(可選):設(shè)置幀率
詳細文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/%E6%8D%95%E8%8E%B7%E6%B5%81

mediaRecorder

mediaRecorder是一個進行媒體錄制的接口,在實例化時需要傳入MediaStream對象和MIME 類型(視頻類型如video/webm或者video/mp4)。
詳細文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/MediaRecorder

通過這兩者的結(jié)合使用就可以實現(xiàn)canvas轉(zhuǎn)視頻的效果了。

案例效果:
chrome-capture.gif

案例代碼:

// 頁面結(jié)構(gòu)(html)
<button onclick="startRecorder()">錄制</button>
<button onclick="stopRecorder()">停止</button>
<button onclick="drawImageDemo()">播放圖片</button>
<canvas id="canvas" width="200" height="200" control></canvas>
<video controls></video>
  ···
// js腳本
  var data = []
  var canvas = document.getElementById('canvas')
  // 創(chuàng)建一個MediaStream
  const stream = canvas.captureStream()
  // 創(chuàng)建一個對指定的MediaStream進行錄制的MediaRecorder
  const recorder = new MediaRecorder(stream, {mimeType: 'video/webm'})
  // 錄像結(jié)束后的回調(diào),寫入數(shù)據(jù)
  recorder.ondataavailable = function (event) {
    if (event.data && event.data.size) {
      data.push(event.data)
    }
  }
  // 監(jiān)聽錄制結(jié)束
  recorder.onstop = () => {
    const url = URL.createObjectURL(new Blob(data, { type: 'video/webm' }));
    document.querySelector("video").src = url;
  }
  // 開始錄制
  function startRecorder () {
    recorder.start()
  }
  // 停止錄制
  function stopRecorder () {
    recorder.stop()
  }

  // 繪制圖片(播放5張圖片)
  let drawIndex = 1
  function drawImageDemo () {
    var img = document.createElement('img')
    img.src = `./images/${drawIndex}.jpg`
    img.width = 300
    img.height = 300
    var dom = canvas.getContext('2d')
    img.onload = function () {
      dom.drawImage(img, 0, 0, canvas.width, canvas.height)
      setTimeout(() => {
        drawIndex++
        if (drawIndex > 5) {
          drawIndex = 1
          return
        }
        drawImageDemo()
      }, 1000)
    }
  }

現(xiàn)在已經(jīng)實現(xiàn)了canvas的視頻轉(zhuǎn)換,接下來就是需要將rrweb的錄制直接繪制到canvas上或者轉(zhuǎn)換為圖片再繪制到錄制的canvas上。一般的頁面結(jié)構(gòu)繪制canvas的方法使用html2canvas實現(xiàn),當然也可以通過svgforeignObject來實現(xiàn)。

  1. 通過html2canvas實現(xiàn):
    首先使用html2canvas獲取頁面截屏的canvas
// dom:需要截取的頁面節(jié)點,返回繪制好的canvas
    html2canvas(dom, {
      width: window.screen.availWidth,
      height: window.screen.availHeight,
      x: 0,
      y: window.pageYOffset,  // 截取開始的y軸坐標
      allowTaint: true,
      useCORS: true
    }).then(canvas1 => { 
        // 將獲得canvas繪制到實時視頻捕獲的畫布上。周期性調(diào)用html2canvas繪制
    });

html2canvas中可以配置返回的canvas繪制在指定的canvas上,但多次繪制時出現(xiàn)繪制的是同一張圖片,所有采用將返回的canvas轉(zhuǎn)成base64在繪制到錄制的canvas上來實現(xiàn)視頻轉(zhuǎn)換。而在周期性頻繁調(diào)用html2canvas方法時,當前頁面最好不要操作,不然會出現(xiàn)卡頓。

文檔:http://html2canvas.hertzen.com/

  1. 使用svg的foreignObject實現(xiàn)截屏(放棄):
    svgforeignObject中可以內(nèi)嵌html結(jié)構(gòu),但在開發(fā)中發(fā)現(xiàn)foreignObject中需要內(nèi)嵌樣式,用外聯(lián)樣式時在轉(zhuǎn)成base64后無法顯示樣式,且在內(nèi)聯(lián)樣式中不能帶有#不然轉(zhuǎn)成img時會出現(xiàn)圖片加載失敗。

  2. 使用puppeteer來對rrweb錄制進行截屏處理,再將截取的圖片繪制到錄制的canvas上來進行視頻轉(zhuǎn)換。
    截屏函數(shù):

// hasT:rrweb錄制的時間長度,sToL:1秒中幾張圖
const startPupp = (hasT) => {
  (async () => {
    const browser = await puppeteer.launch({
      headless: false
    })
    var sToL = 10
    for (let nowI = 0; nowI <= hasT * sToL; nowI++) {
      let page = await browser.newPage()
      let waitTime = nowI * (1000 / sToL)
      // rrweb錄制的播放頁面
      await page.goto('http://127.0.0.1:2000/rrwebVideo.html')
      await page.setViewport({
        width: 1920,
        height: 1080
      })
      // await page.click('#replayBtn')
      await page.waitForTimeout(waitTime) // 等待錄制的播放時間
      await page.screenshot({
        path: `test${nowI}.png`  // 圖片的存儲位置
      })
      page.close()
    }
  })();
}

在接受到當前rrweb的錄制數(shù)據(jù)后調(diào)用該函數(shù),無痕瀏覽器會自動打開播放頁面進行周期性截圖。

rrweb的錄屏播放頁(用于puppeteer截屏的頁面)

  <link rel="stylesheet" >
  <link rel="stylesheet" />
  ...
  <script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/index.js"></script>
  <script>
  // rrweb行為錄制
    let events = [];
    function record () {
      rrweb.record({
        emit(event) {
          // 用任意方式存儲 event
          events.push(event);
        },
      });
    }
    function replay () {
      new rrwebPlayer({
        target: document.getElementById('playback'), // 可以自定義 DOM 元素
        data: {
          events,
        }
      });
    }
  </script>

rrweb的github地址: https://github.com/rrweb-io/rrweb

需要注意的是由于采用的等待播放后截屏,導(dǎo)致如果錄屏?xí)r間過長,周期性截屏的時間也會相對的變得很長。也可以采用rrwebPlayer中的goto方法跳轉(zhuǎn)到對應(yīng)的時間進行截屏可以縮短等待的時間,只是使用這個方法時多輸入框切換的時候會出現(xiàn)切換前的輸入框被清空的問題。

當截屏圖片保存到對應(yīng)文件夾后就可以使用canvas周期性繪制圖片來轉(zhuǎn)化視頻了。

demo地址:https://github.com/erpang123/rrwebToVideo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容