“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Dear, hello, everyone. I am “Front-end Xiaoxin”. 😇 has been engaged in front-end development and Android development for a long time


Background note:

Recently, I have been looking at rrWeb project on GitHub, which is really a masterpiece of DOM recording. There are many scenarios and corresponding examples provided in the usage document. Today, we will take a look at one of the scenarios “Conversion to Video”. Although rrWeb has the best direct playback effect, it still needs to be converted to video for storage. After checking rrVideo project provided by RRWeb, I decided to write the whole conversion process. The general flow chart is as follows:

Environment configuration:

  1. Install FFmpeg: For converting frame-by-frame picture data to video.
  2. Install puppeteer: Used to load web pages in the background.
  3. Install rrweb-player to play events data recorded by RRWeb.

Open a blank page using puppeteer:

  1. Get the browser object instance:browser = await puppeteer.launch({ headless: true });;
  2. Open a new TAB:page = await browser.newPage();&await page.goto("about:blank");;
  3. throughpage.exposeFunctionMount the start and end recorded calling functions on the window object;
  4. Will need to playeventsThe data usedpage.setContent()Load into the page.
    try {
      browser = await puppeteer.launch({ headless: true });
      page = await browser.newPage();
      await page.goto("about:blank");
      // Extend the start recording function
      await page.exposeFunction("onReplayStart".async() = > {await startReplay();
      });
      // Extend the end recording function
      await page.exposeFunction("onReplayFinish".async() = > {await finishReplay();
      });
      // Read the original data
      const events = JSON.parse(
        fs.readFileSync(path.resolve(process.cwd(), _input), "utf-8"));await page.setContent(getHtml(events));
    } catch (error) {
      console.log("The openPage.", error);
    }
    Copy the code

Construct the DOM structure for rrWeb-player playback with minimal support:

  1. Get the contents of the RRweb-player package installed in node_modules for easy insertion into the DOM;

    // Get the rrweb-player script and insert it into the 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");
    Copy the code
  2. Assemble the basic DOM for rrweb-player playback, where recording starts before replayer.play() and ends after listening for playback:

    const html = `
            <html>
              <head>
                  <style>${rrwebStyle}</style>
              </head>
              <body>
                <script>
                  ${rrwebRaw}; / * <! --*/ const events =The ${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>
            `;
    Copy the code

Obtain data streams from timed screenshots provided by the Puppeteer screenshot function:

  1. Get the element object to record:const wrapperEl = await page.$(".replayer-wrapper");
  2. Screenshot from a screenshot of the current frame that returns binary data.
    const buffer = awaitwrapperEl? .screenshot({encoding: "binary"});Copy the code

Execute the ffmpeg command and enter the screenshot data into the FFmpeg process:

  1. We use the spawn function provided by NodeJs to execute the FFmpeg command. The absolute path of FFmpeg referenced directly without setting the environment variable:

    const ffmpegProcess = spawn("D:\\ffmpeg\\bin\\ffmpeg"[// fps
        "-framerate"."15".// input
        "-f"."image2pipe"."-i"."-".// output
        "-y",
        _output,
      ]);
    Copy the code
  2. Will capture the binary data into the standard input stream ffmpegProcess process: ffmpegProcess. Stdin. Write (buffer);

Summary:

  1. These are some of the key points of dismantling the RRVideo process. The complete code is available on GitHub.
  2. Rrvideo also provides common configuration items to facilitate resizing and other information.
  3. Puppeteer is the second use of puppeteer after the last time puppeteer was used to automatically generate skeleton screens.

Welcome to follow my public account “Front-end Xiaoxin students”, the first time to push original technical articles.