Search code examples
node.jsffmpeggoogle-chrome-devtoolspuppeteerchromium

Page.startScreencast Chrome DevTools Protocol low FPS issue


With puppeteer I'm using Chrome DevTools Protocol Page.startScreencast to taking screenshots of webpages and converting those screenshots to a video with FFMPEG

This is a simplified version of the tool I created:

const browser = await puppeteer.launch({
     headless: true,
});
const page = await browser.newPage();
page.setViewport({
    width: 678,
    height: 1080,
});

await page.goto(`https://youtu.be/7G6FfKXvZX8`,
     {
        waitUntil: 'networkidle0',
     }
);

const client = await this.page.target().createCDPSession();
client.on('Page.screencastFrame', async (frameObject) => {

   await writeImageFilename(frameObject.data);
   await client.send('Page.screencastFrameAck', {
      sessionId: frameObject.sessionId,
   });
}

client.send('Page.startScreencast', {
   format: 'png',
   quality: 100,
   maxWidth: 678,
   maxHeight: 1080,
   everyNthFrame: 1,
});
await page.waitForTimeout(6000);
client.send('Page.stopScreencast');

// Helper func
async writeImageFilename(data) {
   const filename = path.join(
      '/tmp',
      Date.now().toString() + '.png'
    );
    fs.writeFileSync(filename, data, 'base64');
    return filename;
}

(I didn't include the ffmpeg part to keep it simple.)

The script above basicly goes to youtube and takes 60 screeenshots in 6 seconds. This way I can create a FFMPEG 10 fps video.

But that's the problem. Capturing 60 frames in 6 seconds is a very slow performance.

Is there any way to increase this number?


Solution

  • "The script above basicly goes to youtube and takes 60 screeenshots in 6 seconds. "

    I don't think this is strictly true.

    "nthFrame" is not time derived rather it is frames generated by chrome.

    In the case that chrome UI did not change for the 60 seconds, no frames would be sent.

    While chrome is animating, every single frame will be issued to you as a screencast event.

    However, there is a caveat that chrome will not send any more screencast events until the ack has been received.

    I believe that chrome will continue to render but will not provide any updated screencasts while you have not "acked" (I guess it thinks there is no point bombarding the consumer?)

    Having a low "nth-frame" will result in a smoother animation but a lot more screencast events, but no events while the current screencast is "unacked".

    Also, the higher the quality, the larger the screnecast event is to process.

    Personally I would:

    • Increase the nth-frame
    • Decrease the quality
    • "Ack" the screencast as the first line of the "screencastFrame" listener
    • Store the image to memory and then save to disk offline

    The faster you can ack and process, the more images you will receive