Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 Video source as locally stored blob not working anymore

As of Chrome 80, something seems to have changed in either the way Blobs or IndexedDB work.

Loading a video file as a blob and assigning it to an HTML5 Video element through createObjectURL, still works:

// load the blob through XMLHttprequest
RequestAsBlob("https://devserver/some-video.mp4",
function(blob)
{
  video.src = URL.createObjectURL(blob); 

  // same above, video.src is now "blob:https://devserver/36e15718-e597-4859-95d3-6bc39daaa999"
}

video.play();

Output: Promise {} And the video plays just fine.

Inspecting the blob, it looks like this:

Blob {size: 6752122, type: "video/mp4"}
size: 6752122
type: "video/mp4"
__proto__: Blob
arrayBuffer: ƒ arrayBuffer()
size: (...)
slice: ƒ slice()
stream: ƒ stream()
text: ƒ text()
type: (...)
constructor: ƒ Blob()
Symbol(Symbol.toStringTag): "Blob"
get size: ƒ size()
get type: ƒ type()
__proto__: Object

I used to store the blob to IndexedDB (through LocalForage) and then retrieve it and play it back, as follows. This, no longer

// blob is a blob fetched from indexedDB
video.src = URL.createObjectURL(blob);  

// video.src is now something like this:
// "blob:https://devserver/ec5e1dfe-0884-40e2-ae8c-c6062734d297"

video.play();

Inspecting the retrieved blob, it looks exactly like the one returned by the XMLHttpRequest

However, it doesn't work:

Output: Uncaught (in promise) DOMException: The element has no supported sources.

I can't figure out what is the change that broke what used to work until now. And it gets weirder:

If I get the stored blob, the one that apparently can't be assigned anymore to the video src directly, and I do this...

var url = URL.createObjectURL(cachedblob);

RequestAsBlob(url,
function(blob)
{
 var url = URL.createObjectURL(blob);

 video.src = url;
 video.play();
}

This works!! I am referencing a blob that was stored in indexedDB, creating a url for it, loading it again through XMLHttpRequest just like if it was actually in some remote location, receiving it as a blob again.... and again creating a URL to it... and it works.

It makes no sense. I hope someone can shed some light on this.

like image 403
resle Avatar asked Feb 05 '20 08:02

resle


1 Answers

Could repro, even in Canary build (82), you did great opening this issue.

Now, there are easier workarounds than fetching through XHR, for instance in stable (80) you just need to wrap your retrieved Blob in a new one:

video.src = URL.createObjectURL(new Blob( [ blob ] ) ); 

As a fiddle since StackSnippet™ won't allow access to IndexedDB.

However this workaround only seems to work on stable release (80), on Canary (82) we need to actually read the whole Blob to an ArrayBuffer and build a new Blob from that ArrayBuffer:

const buf = await blob.arrayBuffer();
vid.src = URL.createObjectURL( new Blob( [ buf ] ) );

fiddle.
Since this latter also works for stable, and we don't know when they'll be able to fix the bug, you might want to use the second workaround instead.

1: or let me know if you want me to do it.

like image 165
Kaiido Avatar answered Oct 10 '22 23:10

Kaiido