Safari BlobUrl 30mb limit

Viewed 788

I'm currently in the process of building a media player web application which requires audio and video to be stored client side. The requirement is to also avoid streaming and that it must work in Safari.

For this I chose IndexedDb and have everything stored just fine in the browser. I have no problem getting the audio and playing via web audio api, however - I soon run into problems with the video.

My current approach is getting the video from indexeddb and creating a blob url for the src attribute:

const objectUrl = createObjectURL(record.videoData);
this.video.src = objectUrl;

This approach works fine for small videos (anything under 30mb), but for larger videos the playback stutters and i notice several error requests to the blob url in the web inspector (see image):

error requests to blob url

details of error request

Despite the 'error' requests the video loads and plays. The only issue is the stuttering. I've also noticed this becomes increasingly worse in proportion to the file size.

I have looked around but have not found any alternative ways of achieving playback without streaming. I took a look at the Safari release notes and i noticed the following (from: safari release notes):

Changed memory handling to keep all of the decoded frames for an animated image if the total memory size of the frames is under 30MB (up from 5MB)

This looks likely to be the cause of the stuttering - and i assume that safari is trying to download chunks of the bloburl.

Is there an alternative approach to what i'm trying to achieve? This behaves much better in chrome (no stuttering), however - this has to work in Safari.

Any help is much appreciated.

1 Answers

I can see three things that might help you.

First, do you revoke all your blobURIs every time you don't use it anymore?
Retrieving Blobs from indexedDB will actually duplicate the data in memory, unlike what happens with input[file], this means that when you create a blobURI from these Blobs, these blobURIs don't point to the file on disk, but will tie the Blob's data in memory until the blobURI is revoked, or the session expires. So when you refresh your page, you may have multiple time the same data held in memory.

Then, you may try to split your big files in smaller chunks, and merge them when you need. If you think 5MB files are working fine, you could use Blob.slice(startByte, endByte) in a loop to generate smaller Blobs, that you would merge with new Blob([chunks]), and only create a blobURI from this merged Blob.
Here is a fiddle demonstrating it.

While the merged Blobs solution was already enough on my end to get rid of these stuttering renderings, this might fail on devices with less memory, so as a final approach, you could use the chunks idea, but without merging them. Instead, you could use the MediaSource API, and feed a stream with arrayBuffers you would get from your chunks (via FileReader.readAsArrayBuffer).

Related