【问题标题】:HTML5 Video source as locally stored blob not working anymoreHTML5 视频源作为本地存储的 blob 不再工作
【发布时间】:2020-02-05 20:33:21
【问题描述】:

从 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();

输出:承诺{} 而且视频播放得很好。

检查 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

我曾经将 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();

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

但是,它不起作用:

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

我不知道是什么改变打破了以前的工作方式。 它变得更奇怪了:

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

var url = URL.createObjectURL(cachedblob);

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

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

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

这毫无意义。 我希望有人能对此有所了解。

【问题讨论】:

标签: javascript blob indexeddb


【解决方案1】:

Could repro,即使在 Canary 版本 (82) 中,你的开场也很棒this issue

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

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

作为 a fiddle,因为 StackSnippet™ 不允许访问 IndexedDB。

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

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

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

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

【讨论】:

  • 感谢 Kaiido,打开了这个问题。不知何故,我怀疑与..安全相关的回归?只是一种直觉。我还看到应该可以直接将 Blob 分配给 HTMLVideo.srcObject,但这似乎也不起作用。我想知道是否有任何方法可以从 blob 创建 MediaTrack?
  • 根据规范,我们应该能够将 srcObject 用于 Blob 和 MediaSources,是的,但目前除了 MediaStreams 之外没有人实现它。将 Blob 中的视频转换为 MediaStream 需要将其加载到视频中,这并不是很有用。 MediaSource 会更合适,但您需要将其读取为 ArrayBuffer,因此new Blob( [ blob.arrayBuffer() ] ) 解决方法仍然是最好的解决方法。
  • 我们也有同样的问题,显然所有没有快速启动的 mp4 都坏了(开头是 moov) - 我们也打开了一个问题 -bugs.chromium.org/p/chromium/issues/detail?id=1049096 是的,你的解决方案有效(arrayBuffer 之一,我们已经从 blob 获得了新的 Blob,但它仍然停止在 v80 上工作),谢谢!
  • 由于该问题出现在文件末尾带有 moov 原子的 mpeg 4 第 14 部分 (mp4) 视频中,因此视频播放器必须跳转到文件末尾,然后返回开始。我认为这可能会破坏缓存系统或损坏缓存文件,具体取决于他们实际缓存它的方式。如果他们对它进行流式缓存,那么在文件中跳转就不好了。我认为通过请求整个arrayBuffer,您可以强制缓冲区在将其传递给播放器以跳过它之前完全缓存,尽管我想知道这是否适用于较大的文件(我认为 arrayBuffer 保存在 RAM 中)。
  • @Kaiido 已确认。我刚刚记得的事情:这似乎正是我之前在 iOS 上遇到的一些 MP4 文件,但不是全部。我想这些可能是 Eek 所引用的(缺少快速启动),但我对编码怪癖不太熟悉。不幸的是,我不记得哪个 iOS / Safari 版本有这个问题,但我很确定我在去年 11 月看到它发生过。顺便问一下,有没有什么快速解决方法可以在 MP4 中添加快速启动而无需重新编码?
猜你喜欢
  • 2014-01-30
  • 1970-01-01
  • 2019-03-30
  • 2014-02-28
  • 1970-01-01
  • 1970-01-01
  • 2019-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多