HTML5 视频源作为本地存储的 blob 不再工作

res*_*sle 10 javascript blob indexeddb

从 Chrome 80 开始,Blob 或 IndexedDB 的工作方式似乎发生了一些变化。

将视频文件作为 blob 加载并通过 createObjectURL 将其分配给 HTML5 Video 元素,仍然有效:

// 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();
Run Code Online (Sandbox Code Playgroud)

输出:Promise {} 并且视频播放得很好。

检查 blob,它看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

我曾经将blob存储到IndexedDB(通过LocalForage)然后检索它并播放它,如下所示。这个,不再

// 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();
Run Code Online (Sandbox Code Playgroud)

检查检索到的 blob,它看起来与 XMLHttpRequest 返回的完全一样

但是,它不起作用:

输出:未捕获(承诺)DOMException:该元素没有支持的来源。

我无法弄清楚是什么变化打破了以前的工作直到现在。它变得更奇怪:

如果我得到存储的 blob,那个显然不能再直接分配给视频 src 的 blob,我这样做......

var url = URL.createObjectURL(cachedblob);

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

 video.src = url;
 video.play();
}
Run Code Online (Sandbox Code Playgroud)

这有效!!我正在引用一个存储在 indexedDB 中的 blob,为它创建一个 url,通过 XMLHttpRequest 再次加载它,就像它实际上在某个远程位置一样,再次将它作为 blob 接收......并再次为其创建一个 URL ...它的工作原理。

这没有道理。我希望有人能对此有所了解。

Kai*_*ido 8

可以重现,即使在 Canary 版本 (82) 中,您在打开此问题时也做得很好。

现在,有比通过 XHR 获取更简单的解决方法,例如在 stable (80) 中,您只需要将检索到的 Blob 包装在一个新的 Blob 中:

video.src = URL.createObjectURL(new Blob( [ blob ] ) ); 
Run Code Online (Sandbox Code Playgroud)

作为一个小提琴,因为 StackSnippet™ 不允许访问 IndexedDB。

然而,这种解决方法似乎只适用于稳定版本 (80),在 Canary (82) 上,我们需要实际将整个 Blob 读取到一个 ArrayBuffer 并从该 ArrayBuffer 构建一个新的 Blob:

const buf = await blob.arrayBuffer();
vid.src = URL.createObjectURL( new Blob( [ buf ] ) );
Run Code Online (Sandbox Code Playgroud)

小提琴
由于后者也适用于稳定版,并且我们不知道他们何时能够修复该错误,因此您可能希望改用第二种解决方法。

1:或者如果你想让我这样做,请告诉我。

  • 我们也有同样的问题,显然它对于所有没有 faststart 的 mp4 来说都是坏的(开头是 moov) - 我们也提出了一个问题 - https://bugs.chromium.org/p/chromium/issues/detail ?id=1049096 是的,你的解决方案有效(arrayBuffer 方案,我们已经从 blob 中获得了新的 Blob,但它在 v80 上仍然停止工作),谢谢! (2认同)
  • 由于该问题出现在文件末尾有“moov”原子的 mpeg 4 第 14 部分 (mp4) 视频上,因此视频播放器必须跳到文件末尾,然后返回到开头。我认为这可能会破坏缓存系统或损坏缓存文件,具体取决于它们实际缓存的方式。如果他们对它进行流缓存,那么在文件中跳转就不好了。我认为通过请求整个“arrayBuffer”,您可以强制缓冲区完全缓存,然后再将其传递给播放器以在其周围跳转,尽管我想知道这是否适用于较大的文件(我认为 arrayBuffer 保存在 RAM 中)。 (2认同)