Dear,大家好,我是“前端小鑫同学”,长期从事前端开发,安卓开发,热衷技术,在编程路上越走越远~

背景阐明:

     最近有在看GitHub上的rrweb我的项目,的确是一款DOM录制的神器,在应用文档中提供了很多咱们会用到的场景和对应的示例,咱们明天来看一下其中一个场景《转换为视频》,尽管rrweb间接回放的成果最佳但还是会遇到须要转为视频进行存储的要求,通过查看rrweb提供的rrvideo我的项目后决定写一下整个转换的过程,大抵的流程图如下:

环境配置:

  1. 装置FFmpeg:用于将逐帧的图片数据转换为视频。
  2. 装置puppeteer:用于在后盾加载网页。
  3. 装置rrweb-player:用于播放rrweb录制的events数据。

    应用puppeteer关上空白页面:

  4. 获取browser对象实例:browser = await puppeteer.launch({ headless: true });
  5. 关上新页签:page = await browser.newPage();&await page.goto("about:blank");
  6. 通过page.exposeFunction在window对象上挂载开始和完结录制的调用函数;
  7. 将须要播放的events数据应用page.setContent()加载进页面。

    try {  browser = await puppeteer.launch({ headless: true });  page = await browser.newPage();  await page.goto("about:blank");  // 扩大启动录制函数  await page.exposeFunction("onReplayStart", async () => {    await startReplay();  });  // 扩大完结录制函数  await page.exposeFunction("onReplayFinish", async () => {    await finishReplay();  });  // 读取原数据  const events = JSON.parse(    fs.readFileSync(path.resolve(process.cwd(), _input), "utf-8")  );  await page.setContent(getHtml(events));} catch (error) {  console.log("openPage:", error);}

    组装最简反对rrweb-player播放的DOM构造:

  8. 获取装置到node_modules内的rrweb-player包的内容,便于插入到DOM中;

    // 获取rrweb-player的脚本插入到DOM中const rrwebScriptPath = path.resolve(  require.resolve("rrweb-player"),  "../../dist/index.js");const rrwebStylePath = path.resolve(rrwebScriptPath, "../style.css");const rrwebRaw = fs.readFileSync(rrwebScriptPath, "utf-8");const rrwebStyle = fs.readFileSync(rrwebStylePath, "utf-8");
  9. 拼装满足rrweb-player播放的根底DOM,其中在replayer.play()函数执行前开启录制并在监听到播放实现后完结录制:

    const html = `        <html>          <head>              <style>${rrwebStyle}</style>          </head>          <body>            <script>              ${rrwebRaw};              /*<!--*/              const events = ${JSON.stringify(events).replace(                /<\/script>/g,                "<\\/script>"              )};              /*-->*/              window.replayer = new rrwebPlayer({                target: document.body,                props: {                  events,                  showController: false,                },              });              window.onReplayStart();              window.replayer.play();              window.replayer.addEventListener('finish', () => {                  window.onReplayFinish()              });            </script>          </body>        </html>        `;

    通过puppeteer提供的screenshot函数定时截屏获取数据流:

  10. 获取到须要录制的元素对象:const wrapperEl = await page.$(".replayer-wrapper");
  11. 通过screenshot来截取以后帧的画面,返回数据类型为二进制数据。

    const buffer = await wrapperEl?.screenshot({  encoding: "binary",});

    执行ffmpeg命令并将截屏数据输出到ffmpeg过程:

  12. 咱们应用NodeJs提供的spawn函数来执行FFmpeg命令,此处未配置环境变量而间接援用的FFmpeg的绝对路径:

    const ffmpegProcess = spawn("D:\\ffmpeg\\bin\\ffmpeg", [    // fps    "-framerate",    "15",    // input    "-f",    "image2pipe",    "-i",    "-",    // output    "-y",    _output,  ]);
  13. 将截图失去的二进制数据写入ffmpegProcess过程的规范输出流中:ffmpegProcess.stdin.write(buffer);

    总结阐明:

    1. 以上就是对rrvideo流程拆解一些关键点阐明,残缺代码在GitHub。
    2. rrvideo还提供了罕用的一些配置项来便于调整视频的尺寸等信息。
    3. puppeteer是继上次做主动生成骨架屏后的第二次应用。

欢送关注我的公众号“前端小鑫同学”,原创技术文章第一工夫推送。