Dear,大家好,我是“前端小鑫同学”,😇长期从事前端开发,安卓开发,热衷技术,在编程路上越走越远~
背景阐明:
最近有在看 GitHub 上的 rrweb 我的项目,的确是一款 DOM 录制的神器,在应用文档中提供了很多咱们会用到的场景和对应的示例,咱们明天来看一下其中一个场景《转换为视频》,尽管 rrweb 间接回放的成果最佳但还是会遇到须要转为视频进行存储的要求,通过查看 rrweb 提供的 rrvideo 我的项目后决定写一下整个转换的过程,大抵的流程图如下:
环境配置:
- 装置 FFmpeg:用于将逐帧的图片数据转换为视频。
- 装置 puppeteer:用于在后盾加载网页。
-
装置 rrweb-player:用于播放 rrweb 录制的 events 数据。
应用 puppeteer 关上空白页面:
- 获取 browser 对象实例:
browser = await puppeteer.launch({headless: true});
; - 关上新页签:
page = await browser.newPage();
&await page.goto("about:blank");
; - 通过
page.exposeFunction
在 window 对象上挂载开始和完结录制的调用函数; -
将须要播放的 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 构造:
-
获取装置到 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");
-
拼装满足 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 函数定时截屏获取数据流:
- 获取到须要录制的元素对象:
const wrapperEl = await page.$(".replayer-wrapper");
-
通过 screenshot 来截取以后帧的画面,返回数据类型为二进制数据。
const buffer = await wrapperEl?.screenshot({encoding: "binary",});
执行 ffmpeg 命令并将截屏数据输出到 ffmpeg 过程:
-
咱们应用 NodeJs 提供的 spawn 函数来执行 FFmpeg 命令,此处未配置环境变量而间接援用的 FFmpeg 的绝对路径:
const ffmpegProcess = spawn("D:\\ffmpeg\\bin\\ffmpeg", [ // fps "-framerate", "15", // input "-f", "image2pipe", "-i", "-", // output "-y", _output, ]);
-
将截图失去的二进制数据写入 ffmpegProcess 过程的规范输出流中:
ffmpegProcess.stdin.write(buffer);
总结阐明:
- 以上就是对 rrvideo 流程拆解一些关键点阐明,残缺代码在 GitHub。
- rrvideo 还提供了罕用的一些配置项来便于调整视频的尺寸等信息。
- puppeteer 是继上次做主动生成骨架屏后的第二次应用。
欢送关注我的公众号“前端小鑫同学”,原创技术文章第一工夫推送。