如何从 Blob url 中检索 MediaStream?

Posted

技术标签:

【中文标题】如何从 Blob url 中检索 MediaStream?【英文标题】:How to retrieve a MediaStream from a Blob url? 【发布时间】:2013-08-21 04:48:34 【问题描述】:

可以使用window.URL.createObjectURL() 从如下代码中的流中获取 URL。

navigator.getUserMedia( video: true, audio: true , function (localMediaStream) 

    var video = document.querySelector('video');
    video.src = window.URL.createObjectURL(localMediaStream);
    video.onloadedmetadata = function (e) 
        // Do something with the video here.
    ;
, 
function (err) 
    console.log("The following error occured: " + err);

);

问题是我现在有一个像这样的 blob URL:

blob:http%3A//localhost%3A1560/f43bed15-da6c-4ff1-b73c-5640ed94e8ee

有没有办法从中检索 MediaStream 对象?

【问题讨论】:

是的。 developer.mozilla.org/en-US/docs/WebRTC/MediaStream_API 如果您发布的代码不起作用,很可能是因为您在 src 之后设置了侦听器,请记住 blob 是本地资源,因此加载速度比互联网资源。 【参考方案1】:

注意:

URL.createObjectURL(MediaStream) 已被弃用。 不要再在代码中使用它,它会在任何最近的浏览器中抛出。 但问题的前提仍然有效。



没有内置方法来检索 blob URL 指向的原始对象。

使用 Blob,我们仍然可以获取此 Blob URL,并且我们将获得原始 Blob 的副本

const blob = new Blob(['hello']);
const url = URL.createObjectURL(blob);

fetch(url)
  .then(r => r.blob())
  .then(async (copy) => 
    console.log('same Blobs?', copy === blob);
    const blob_arr = new Uint8Array(await new Response(blob).arrayBuffer());
    const copy_arr = new Uint8Array(await new Response(copy).arrayBuffer());
    console.log("same content?", JSON.stringify(blob_arr) === JSON.stringify(copy_arr))
    console.log(JSON.stringify(copy_arr));
  )

但对于其他对象,这将不起作用...

const source = new MediaSource();
const url = URL.createObjectURL(source);

fetch(url)
  .then(r => r.blob())
  .then(console.log)
  .catch(console.error);

唯一的方法就是跟踪你的原始对象。

为此,我们可以围绕createObjectURLrevokeObjectURL 设计简单的包装器来更新可通过URL 访问的对象字典:

(() => 
  // overrides URL methods to be able to retrieve the original blobs later on
  const old_create = URL.createObjectURL;
  const old_revoke = URL.revokeObjectURL;
  Object.defineProperty(URL, 'createObjectURL', 
    get: () => storeAndCreate
  );
  Object.defineProperty(URL, 'revokeObjectURL', 
    get: () => forgetAndRevoke
  );
  Object.defineProperty(URL, 'getFromObjectURL', 
    get: () => getBlob
  );
  const dict = ;

  function storeAndCreate(blob) 
    var url = old_create(blob); // let it throw if it has to
    dict[url] = blob;
    return url
  

  function forgetAndRevoke(url) 
    old_revoke(url);
    // some checks just because it's what the question titel asks for, and well to avoid deleting bad things
    try 
      if(new URL(url).protocol === 'blob:')
        delete dict[url];
    catch(e) // avoided deleting some bad thing ;)
  

  function getBlob(url) 
    return dict[url];
  
)();

// a few example uses

// first a simple Blob
test(new Blob(['foo bar']));

// A more complicated MediaSource
test(new MediaSource());

function test(original) 
  const url = URL.createObjectURL(original);
  const retrieved = URL.getFromObjectURL(url);
  console.log('retrieved: ', retrieved);
  console.log('is same object: ', retrieved === original);
  URL.revokeObjectURL(url);

【讨论】:

【参考方案2】:

如果您使用的是 angular2,您可以使用 platform-b​​rowser-package 中提供的 DOMSanitizer:

import  DomSanitizer  from '@angular/platform-browser';
constructor(
    private sanitizer: DomSanitizer) 

然后像下面这样使用你的流:

//your code comes here...
video.src = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(stream));

这应该只是

【讨论】:

createObjectURL 即将被弃用【参考方案3】:

video.src 不是 video.srcObject

而且是的他们会发生冲突 ;) !

video.src获取源网址

video.srcObject 获取源 OBJECT(目前截至 2019 年只有 MediaStream is safely supported,也许将来您可以将 Blob 直接放在这里,但现在不行......)

所以这取决于你真正想做什么:

A) 显示当前正在录制的内容

您必须有可用的MediaStream 对象(您可以这样做)并将其放入video.srcObject

navigator.getUserMedia( video: true, audio: true , function (localMediaStream) 
    var video = document.querySelector('video');
    video.src = ''; // just to be sure src does not conflict with us
    video.srcObject = localMediaStream;

B) 显示现有视频/刚刚录制的视频

video.srcObject = null; // make sure srcObject is empty and does not overlay our src
video.src = window.URL.createObjectURL(THE_BLOB_OBJECT);

THE_BLOB_OBJECT - 你要么已经通过 File API 创建了一个,或者通常如果你有某种记录器,让我们假设在 recorder 变量中,通常有 getBlob() 或类似的东西,如 recorder.getBlob() 我强烈建议您为此使用一些现有的记录器库,但要完整,有一个官方的 MediaRecorder API - https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder

所以您看到您刚刚将 2 件事组合在一起,您只需将它们分开并确保它们不会冲突 :)

【讨论】:

你说的是真的,但它没有回答问题......在 2013 年(当问题被问到时)没有srcObject,当时显示 MediaStream 的唯一方法是制作指向此 MediaStream 的 BlobURL。从那时起,这已被弃用,但在发布该问题时,这是正常的做法。那么问题是“如何从指向 MediaStream 的 Blob URL 中检索 MediaStream”。因为我们可以用于 Blob 的 fetch(blobURL) 在这里不起作用。 如果您愿意,根据我们今天可以做的,问题将是“如何从 blobURL 检索 MediaSource 对象,其中 blobURL 是通过执行 URL.createObjectURL(MediaSource_instance) 生成的。” @Kaiido 你是对的,我错过了日期,虽然问题是如何获得MediaStream 对象,而不是MediaSource,除非你想要,否则这没有多大意义录制视频。 我使用 MediaSource 作为示例,因为它是另一个非 Blob 对象,我们可以从中生成 blobURI(就像之前可以使用 MediaStream 一样)。所以它是当代的等价物。并且有很好的案例想要检索一个 MSE,例如,能够将新的块附加到它。 好的,但是如果能够追加新的块,你不应该已经有了对象引用吗? (只是想知道:D)

以上是关于如何从 Blob url 中检索 MediaStream?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 从 MYSQL 中插入和检索图像 blob?

如何使用 c# 从 azure blob 存储中检索 xml 文件

如何将图像存储为 Sqlite 中的 blob 以及如何检索它?

如何从 Azure 容器中的 blob 中获取所有 URL 的列表?

如何从 blob:url 获取原始图像数据?

C#如何检索存储在BLOB中的XML,然后更新它并存储