Search code examples
javascriptwebrtcindexeddbfileapimediastream

Can client-side javascript create a file download that is too big to fit in memory?


I am using captureStream to record from a HTML canvas, and currently use the example code in https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API. However, this only works for short recordings as each blob is stored in memory.

I’d like to be able to record for long periods of time e.g. >1 hour and let the user download the resulting .webm/.mkv file. If this sounds unusual, it’s because I’m using the web browser for an (open source) scientific application and need to know what was displayed during an experiment :).

It’s simple enough to adapt the MDN code to store each blob in IndexedDB instead of an in-memory array, but I’m stuck on how to construct the download without creating an enormous blob that would exhaust memory:

var blob = new Blob([IDBchunk1, IDBchunk2, ...], {
  type: "video/webm"
});

Another approach would be to construct a “streaming” download, but not sure if this is possible.

One workable, but horribly inefficient solution is to use WebRTC to send the stream back to nodejs server, append each blob to on-disk video file on server, then serve the video download over http. I dislike this solution as involves the complexity of setting up webRTC + requires massive bandwidth back and forth.

Let me know if you have any thoughts for how to do this on client-side only?


Solution

  • In Chrome, at least, the new Blob([IDBchunk1, IDBchunk2, ...]...) approach does not require any of the blobs to be loaded into memory. The new blob internally references the dependent blobs/files, and a read over the blob (e.g. during download) pulls bytes from the dependent blobs as needed.