Summary: Write .PNGs to the sandboxed file system in Chrome. Then sneak in and move them out.
1) Set up a sandboxed file system
// Request 40 GB (should be enough for ~5 minutes of 1080p)
var bytes = 1024*1024*1024*40;
window.webkitStorageInfo.requestQuota(PERSISTENT, bytes, function(grantedBytes) {
console.log('Got storage', grantedBytes);
window.webkitRequestFileSystem(PERSISTENT, grantedBytes, function (fs) {
window.fs = fs;
console.log("Got filesystem");
});
}, function(e) {
console.log('Storage error', e);
});
2) Override requestAnimationFrame to capture N frames and write them to PNGs
var frames = 1000;
var raf = window.requestAnimationFrame;
var next = null;
var hold = false;
window.requestAnimationFrame = function rafOverride(callback) {
// Find canvas
var canvas = document.querySelector('canvas');
if (canvas && window.fs) {
// Done capturing?
if (frames < 0) {
window.requestAnimationFrame = raf;
return raf(callback);
}
// Hold rendering until screenshot is done
if (!hold) {
hold = true;
frames--;
setTimeout(function () {
callback();
capture(canvas, function () {
// Resume rendering
hold = false;
rafOverride(next);
});
}, 66);
}
else {
next = callback;
}
}
else {
// Canvas not created yet?
return raf(callback);
}
}
function capture(canvas, callback) {
var name = Math.random(); // File name doesn't matter
var image = canvas.toDataURL('image/png').slice(22);
fs.root.getFile(name, {create: true}, function (entry) {
entry.createWriter(function (writer) {
// Convert base64 to binary without UTF-8 mangling.
var data = atob(image);
var buf = new Uint8Array(data.length);
for (var i = 0; i < data.length; ++i) {
buf[i] = data.charCodeAt(i);
}
// Write data
var blob = new Blob([buf], {});
writer.seek(0);
writer.write(blob);
console.log('Writing file', frames, blob.size);
setTimeout(function () {
// Resume rendering
callback();
}, 66);
});
}, function () { console.log('File error', arguments); });
}
3) Find where the files are stored and move them out
The reason the filenames are random in capture() is because they get written out as sequential 00000000, 00000001, etc. files, somewhere buried deep inside Chrome's profile.
On a Mac, I used the following node.js script to get them out. The specific location will differ, but you're looking for a directory full of 00, 01, 02, 03 subdirectories, with 100 numbered files inside each.
var fs = require('fs');
var path = "/Users/steven/Library/Application Support/Google/Chrome/Default/File System/009/p/";
var first = 0;
var last = 9899;
var j = 0;
for (var i = first; i <= last; ++i) {
var subdir = ("00" + Math.floor(i / 100)).slice(-2);
var file = path + subdir + '/' + ("000000000" + i).slice(-8);
var target = './file' + ("00000000" + (++j)).slice(-8);
console.log(file, target + '.png');
fs.renameSync(file, target + '.png');
}
4) Assemble the PNGs into a movie with your favorite tool.
I used the old school Quicktime Player 7, as it still has the capability to open numbered image sequences. Then I used the x264 QuickTime plug-in to encode it (it's both faster and better than Apple's H.264 encoder).
5) Clear your Google Chrome cache to clean up the file system.
You might also pipe them through a websocket and write directly to a location of your choice.