Hello,
I'm not sure if it's a bug or if I can find a workaround, so I'm starting here.
I'm using Chrome Canary 67 in MacOs, starting with this command :
chrome --headless --no-sandbox --hide-scrollbars --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222 --disable-setuid-sandbox
I'm trying to build a system where a node script will trigger function to update the HTML, and then take a screenshot of it.
I implemented 2 different script to compare screenshot and screencast.
With screenshot, there is no problem, but it's quite slow.
With screencast, there is some missing frame, that never comes to Page.screencastFrame.
I attached the code sample to be simpler to test.
Here is how I send a function to the HTML to update it:
return client.Runtime.evaluate({
expression: 'showFrame(' + currentFrame + ');',
awaitPromise: true
}).then(function(showRes) {
if (!showRes.result) {
throw new Error('Failed showFrame ' + currentFrame);
}
return saveScreenshot(client, width, height, currentFrame);
});
For the screenshot, here is the code :
return Page.captureScreenshot({
format: 'png',
clip: {
x: 0,
y: 0,
width: width,
height: height,
scale: 1
}
}).then(function(screenshot) {
return new Buffer(screenshot.data, 'base64');
}).then((buffer) => {
let outputFile = filePath + formatFrameNumber(currentFrame) + '.png';
return new Promise((resolve, reject) => {
fs.writeFile(outputFile, buffer, 'base64', async (err) => {
if (err) {
console.error(err);
reject();
} else {
console.log('Screenshot saved to "' + outputFile + '"');
resolve();
}
});
});
}).catch((err) => {
console.error('ERORO WRITE BUFFER '+err);
});
For screencast, it's requested with this code just after the load:
Page.screencastFrame(({ sessionId, data, metadata }) => {
console.log('screencastFrame');
lastScreencastData = data;
lastScreencastMetadata = metadata;
Page.screencastFrameAck({ sessionId });
});
await Page.startScreencast({
format: 'png'
});
The last screencastFrame is saved in a global variable, and then used when saving is requested:
return new Promise((resolve, reject) => {
if (!lastScreencastData || !lastScreencastMetadata) {
throw new Error('screencast frame '+currentFrame+' is empty');
reject();
}
resolve(new Buffer(lastScreencastData, 'base64'));
}).then((buffer) => {
lastScreencastData = false;
let outputFile = filePath + formatFrameNumber(currentFrame) + '.png';
return new Promise((resolve, reject) => {
fs.writeFile(outputFile, buffer, 'base64', async (err) => {
if (err) {
console.error(err);
reject();
} else {
console.log('Screenshot saved to "' + outputFile + '"');
resolve();
}
});
});
}).catch((err) => {
console.error('ERORO WRITE BUFFER '+err);
});
In some cases, there is error with "screencast frame XXX is empty".
In some other cases, the resulting PNG is the same as the previous one.
There is 2 screencastFrame which looks exactly the same.
In the HTML, here is the code called by the node script:
async function showFrame(frame) {
frameDiv.innerHTML+= ' '+frame;
console.log('show frame '+frame);
return new Promise(function(resolve, reject) {
requestAnimationFrame(function() {
requestAnimationFrame(function() {
console.log('show frame END '+frame);
resolve({
result: true
});
});
});
});
};
As you can see, I already add a double requestAnimationFrame, but it's still not sufficient for screencasting...
The difference of timing between the 2 scripts :
- 8 seconds for screenshot
- 1 second for screencast
For screen casting, if I add a setTimeout in the HTML of 100ms, there is no frame missing or problem.
But I'd like to avoid this problem in order to be as fast as possible...
Could anybody already experience same problem and found any solutions?
Thanks in advance.