【问题标题】:Callback event for getUserMedia()getUserMedia() 的回调事件
【发布时间】:2017-01-25 15:28:23
【问题描述】:

我正在尝试使用 navigator.mediaDevices.getUserMedia()canvas.getContext('2d').drawImage() 函数从我的网络摄像头拍摄快照。

当我这样做时,它完美地工作:

function init(){
  myVideo = document.getElementById("myVideo") 
  myCanvas = document.getElementById("myCanvas");
  videoWidth = myCanvas.width;
  videoHeight = myCanvas.height;
    
  startVideoStream();
}

function startVideoStream(){
  navigator.mediaDevices.getUserMedia({audio: false, video: { width: videoWidth, height: videoHeight }}).then(function(stream) {
    myVideo.src = URL.createObjectURL(stream);
  }).catch(function(err) {
      console.log("Unable to get video stream: " + err);
  });
}

function snapshot(){
  myCanvas.getContext('2d').drawImage(myVideo, 0, 0, videoWidth, videoHeight);
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="debug.js"></script>
</head>
<body onload="init()">
    <div id="mainContainer">
        <video id="myVideo" width="640" height="480" autoplay style="display: inline;"></video>
        <canvas id="myCanvas" width="640" height="480" style="display: inline;"></canvas>
        <input type="button" id="snapshotButton" value="Snapshot" onclick="snapshot()"/>
    </div>
</body>
</html>

问题是,我不想使用按钮单击来拍摄快照,而是在相机流加载后立即拍摄快照。 我尝试设置视频源后直接调用snapshot()函数:

function init(){
  myVideo = document.getElementById("myVideo") 
  myCanvas = document.getElementById("myCanvas");
  videoWidth = myCanvas.width;
  videoHeight = myCanvas.height;
    
  startVideoStream();
}

function startVideoStream(){
  navigator.mediaDevices.getUserMedia({audio: false, video: { width: videoWidth, height: videoHeight }}).then(function(stream) {
    myVideo.src = URL.createObjectURL(stream);
    snapshot();
  }).catch(function(err) {
      console.log("Unable to get video stream: " + err);
  });
}

function snapshot(){
  myCanvas.getContext('2d').drawImage(myVideo, 0, 0, videoWidth, videoHeight);
}

但它不起作用。我的画布保持白色。我想这是因为此时相机流尚未完全加载。

那么是否有任何其他事件被触发,我可以在加载相机源后立即使用它来绘制快照?还是我完全走错了路?

提前致谢!

【问题讨论】:

  • 你能把myVideo的快照打印出来吗?
  • 当我在 snapshot() 函数中记录 myVideo 时,它会显示:&lt;video id="myVideo" width="640" height="480" autoplay="" style="display: inline;" src="blob:https://localhost:8081/317a70de-e87d-442a-bde7-cb4c75db01f3"&gt;&lt;/video&gt;
  • 也许看看这个问题会有所帮助:stackoverflow.com/questions/12256668/…
  • 这篇文章是关于错误的视频格式,但它让我走上了正轨:-)视频元素有一个“播放”-EventListener,所以我可以使用myVideo.addEventListener('play', function(){ snapshot(); }, false);})非常感谢很多!

标签: javascript getusermedia


【解决方案1】:

等待loadedmetadata 事件:

navigator.mediaDevices.getUserMedia({video: true})
  .then(stream => {
    video.srcObject = stream;
    return new Promise(resolve => video.onloadedmetadata = resolve);
  })
  .then(() => canvas.getContext('2d').drawImage(video, 0, 0, 160, 120))
  .catch(e => console.log(e));
<video id="video" width="160" height="120" autoplay></video>
<canvas id="canvas" width="160" height="120"></canvas>

以上内容应该适用于所有浏览器(执行 WebRTC)。

在 Chrome 中,您也可以执行 this - 但 play() 尚未在任何其他浏览器中返回承诺。

另请注意,URL.createObjectURL(stream) 已弃用。使用srcObject

更新:感谢 cmets 中的@KyleMcDonald 指出注册loadedmetadata 侦听器与设置srcObject 同步的重要性!— 代码已更新。

【讨论】:

  • "URL.createObjectURL is deprecated" 更多的是使用不推荐使用的 URL.createObjectURL 将视频的 src 设置为流,对吧? URL.createObjectURL 仍然是从 Blob 创建 URL 的方法。如果我没记错的话,目前还没有人支持srcObject = Blob
  • @Kaiido 没错。 srcObject 缺少对 blob 和 mediaSource 的支持。虽然一旦改善,这里希望URL.createObjectURL 将完全消失。
  • 但是srcObject 会应用于&lt;img&gt;&lt;iframe&gt;&lt;object&gt; 等吗?会有&lt;a&gt;hrefObject 吗? createObjectURL 是下载具有download 属性的>4MB Blob 的唯一方法。我认为它不会很快消失,而 IMO 这将是一个糟糕的主意。
  • @Kaiido 好点。 srcObject 不适用于这些,因此 createObjectURL 可能会保留用于这些用途。我会更新答案。 createObjectURL 对流特别不利,因为流可以保持实时硬件资源打开,因为很少有人正确调用revokeObjectURL
  • :-) 已经投票了,但很高兴你更新了。此外,可能会有一个关于 WHATWG play() 的词,它返回一个 Promise,避免我们创建一个,即使目前只有 chrome 确实遵循这个版本的规范。 (也许你知道 FF 的计划?)。你对 revokeObjectURL 是正确的,我一直在我的每个 cmets/answers 中添加它。但对于其他用途,createObjectURL 比 readAsDataURL 好得多,尤其是从用户文件中,它只是指向硬盘驱动器的指针。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多