将视频流javascript代码传输到React(ML5)

时间:2019-02-02 23:13:30

标签: javascript reactjs webcam tensorflow.js

我试图将ML5图像分类示例(Link)中的代码转换为我的React组件,如下所示:

class App extends Component {
  video = document.getElementById('video');

  state = {
    result :null
  }

  loop = (classifier) => {
    classifier.predict()
      .then(results => {
        this.setState({result: results[0].className});
        this.loop(classifier) // Call again to create a loop
      })
  }

  componentDidMount(){
    ml5.imageClassifier('MobileNet', this.video)
      .then(classifier => this.loop(classifier))

  }
  render() {

    navigator.mediaDevices.getUserMedia({ video: true })
      .then((stream) => {
        this.video.srcObject = stream;
        this.video.play();
      })

    return (
      <div className="App">
        <video id="video" width="640" height="480" autoplay></video>
      </div>
    );
  }
}

export default App;

但是,这不起作用。错误消息显示Unhandled Rejection (TypeError): Cannot set property 'srcObject' of null

我可以想象video = document.getElementById('video');可能无法通过id来获取元素。所以我尝试了

  class App extends Component {
  video_element = <video id="video" width="640" height="480" autoplay></video>;

  ...

  render() {
    ...
    return (
      <div className="App">
        {video_element}
      </div>
    );
  }
}

哪个也不起作用。我对实现此目标的正确方法感到困惑?

任何帮助表示感谢,谢谢!

2 个答案:

答案 0 :(得分:1)

实例化App时,视频元素尚不存在,但是document.getElementById运行,返回未定义或null。这就是为什么你得到:

Cannot set property 'srcObject' of null

因为在这里:

this.video.srcObject = stream

this.video为空。

这不是执行此操作的正确方法。您应该准备dom元素的引用,将其分配为prop,然后从那里访问该元素。像这样:

class App extends Component {

  video = React.createRef()

  ...

  render() {

    navigator.mediaDevices.getUserMedia({ video: true })
      .then((stream) => {
        if ( this.video.current ) {
          this.video.current.srcObject = stream;
          this.video.current.play();
        }
      })

    return (

      ...

      <video ref={ this.video } 
             id="video" 
             width="640" 
             height="480" 
             autoplay
      />

答案 1 :(得分:1)

我将重点回答一个稍有不同的问题,而不是ref

有一个巨大的问题,由于异常而导致可怕的眨眼和不断失败的承诺……这是在render方法中获取用户媒体的原因!

考虑一下,每次设置状态时,都会重新渲染组件。您有一个不断更新组件状态的循环,并且承诺会不断失败。

安装组件后,您需要获取用户媒体:

componentDidMount() {
  navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
    if (this.video.current) {
      this.video.current.srcObject = stream;
      this.video.current.play();
    }

    ml5.imageClassifier("MobileNet", this.video.current)
       .then(classifier => this.loop(classifier));
  });
}

您的渲染方法要短得多:

render() {
  return (
    <div className="App">
      <video ref={this.video} id="video" width="640" height="480" autoPlay />
    </div>
  )
}