如何从Blob网址创建媒体流?

时间:2013-08-19 11:44:24

标签: javascript html5-video html5-audio

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

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网址:

  

团块:HTTP%3A //本地主机%3A1560 / f43bed15-da6c-4ff1-b73c-5640ed94e8ee

有没有办法为此创建媒体流对象?

3 个答案:

答案 0 :(得分:0)

如果您使用的是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));

这应该只是

答案 1 :(得分:0)

video.src不是video.srcObject

并且 ,他们会发生冲突;)!

video.src 获取源URL

video.srcObject 获取源对象(目前仅截至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 :(得分:0)

注意:

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



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

使用Blob,我们仍然可以获取该Blob网址,并获得原始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);
}