【问题标题】:Javascript DOMException: The associated Track is in an invalid stateJavascript DOMException:关联的 Track 处于无效状态
【发布时间】:2020-06-26 19:55:55
【问题描述】:

我正在尝试在 nodeJS 服务器上创建一个照片捕获网络应用程序,并且我正在使用下面的 javascript 代码。

const btn = document.querySelector('#btn');

btn.addEventListener('click', (event) => {
 navigator.mediaDevices.getUserMedia({video: true})
  .then(gotMedia)
  .catch(error => console.error('getUserMedia() error:', error));

  event.preventDefault()
})

gotMedia 函数是这样的:

function gotMedia(mediaStream) {
    const mediaStreamTrack = mediaStream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(mediaStreamTrack);
    console.log(imageCapture);

    const canvas = document.querySelector('canvas');
    // ...
    imageCapture.grabFrame()
    .then(imageBitmap => {
        canvas.width = imageBitmap.width;
        canvas.height = imageBitmap.height;
        canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
    })
    .catch(error => console.error('grabFrame() error:', error));
}

一切正常,图像捕获还可以,但是当我一张一张快速拍摄照片时出现错误,提示:

grabFrame() 错误:DOMException:关联的 Track 处于无效状态。

这通常发生在我拍摄太多照片时(例如快速点击大约 20 秒以上),但前五张快照也会发生这种情况。有谁知道发生了什么,我应该改变什么,以解决这个问题?感谢您的宝贵时间。

【问题讨论】:

  • 你有没有想过这个问题?我遇到了完全相同的事情。如果它似乎也不会永久终止视频流,即使被捕获,我也不介意这个例外。
  • 不幸的是我还没有找到任何解决方案,但我仍在努力解决这个问题,如果我成功了,我会告诉你
  • 嗨,我也遇到了完全相同的事情。循环开始使用相同的功能每 20 秒拍照一次,在拍摄了一系列照片后,它开始抛出这个(关联的 Track 处于无效状态)错误。我们应该如何修复无效状态?你们中有人成功地提出了解决方案吗?谢谢

标签: javascript domexception mediadevices


【解决方案1】:

我的两分钱:

let preview = document.getElementById('preview')
let recording = document.getElementById('recording')
let photo = document.getElementById('photo')
let photoButton = document.getElementById('photoButton')
let imageHolder = document.getElementById('image-holder')

async function startWebcam() {
  return navigator.mediaDevices.getUserMedia({
    video: true
  })
};

photoButton.addEventListener('click', async() => {
  let webcamStream = await startWebcam()
  preview.srcObject = webcamStream
  const track = webcamStream.getVideoTracks()[0]
  const imageCapture = new ImageCapture(track)
  const bitmap = await imageCapture.grabFrame()
  const canvas = document.getElementById('canvas')
  canvas.width = bitmap.width
  canvas.height = bitmap.height
  const context = canvas.getContext('2d')
  context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height)
  let image = canvas.toDataURL()
  imageHolder.innerHTML += `<img src="${image}"></img>`
  track.stop()

})
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Desktoprecord</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css">
  <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
  <script src="node_modules/axios/dist/axios.min.js"></script>
  <script src="app4.js" defer></script>
</head>

<div class="container">
  <video id="preview" width="25%" height="auto" autoplay muted poster="https://placekitten.com/g/150"></video>
  <canvas id="canvas"></canvas>
  <img src="http://placekitten.com/g/320/261" id="photo" alt="photo">
  <div id="image-holder">
    To be replaced with pretty pictures
  </div>
  <video src="" id="preview"></video>
  </jdiv>
  <div class="buttons are-large">
    <button id="photoButton" class="button is-success"><i class="fas fa-camera"></i></button>
  </div>
</div>

每次你要拍照时你启动相机,当你得到照片后你必须停止跟踪

【讨论】:

    【解决方案2】:

    根据spec,此类错误可能是不可接受状态的结果。在铬源中我发现了this method

    我已经使用这样的代码克服了错误:

      const promise = getPrevImagePromise();
    
      if (!promise && !(imageCapture.track.readyState != 'live' || !imageCapture.track.enabled || imageCapture.track.muted)) {
        const imagePromise = imageCapture.grabFrame()
          .then((image) => {
            // do work with image
          })
          .then(() => {
            deletePrevImagePromise()
          })
          .catch((error) => {
            // 
          });
    
        setPrevImagePromise(imagePromise);
      }
    

    【讨论】:

    • 你拯救了我的一天。在调用 grabFrame() 之前,我的应用程序必须检查 readyState
    【解决方案3】:

    我遇到了同样的问题,无法让最先进的 grabFrame 函数可靠地工作。

    相反,您可以从中间视频源中进行绘制。在您的函数中,它看起来像这样(未经测试):

    function gotMedia(mediaStream) {
        const mediaStreamTrack = mediaStream.getVideoTracks()[0];
        const canvas = document.querySelector('canvas');
        const video = document.createElement('video');
    
        video.autoplay = true;
        video.srcObject = mediaStream;
        video.onplay = () => {
             canvas.width = video.videoWidth;
             canvas.height = video.videoHeight;
             canvas.getContext('2d').drawImage(video, 0, 0);
        };
    }
    

    当然,如果您要捕获大量帧,最好在流旁边创建一个视频并每次都从该视频中捕获。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      • 2023-03-10
      • 2020-08-21
      • 2016-03-21
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多