score:14

Accepted answer

There are a few things to understand about the way React components work. Firstly according to the React docs:

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not directly interact with the browser.

You should move initializing your video element to an alternate lifecycle method like componentDidMount to ensure that it is only initialized once.

Secondly, you rarely need to interact with the DOM directly. In this case we can use the component's internal state to manage the src attribute for the video stream, ensuring it only updates after the stream has initialized.

Here's an updated component that might work:

var MyComponent = React.createClass({
  getInitialState: function(){
    return { videoSrc: null }
  },
  componentDidMount: function(){
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
    if (navigator.getUserMedia) {
        navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
    }
  },
  handleVideo: function(stream) {
    // Update the state, triggering the component to re-render with the correct stream
    this.setState({ videoSrc: window.URL.createObjectURL(stream) });
  },
  videoError: function() {

  },
  render: function() {
    return <div>
      <video src={this.state.videoSrc} autoPlay="true" />
    </div>;
    }
});

score:0

You can make use of react-webcam. follow the link below, it already has a "getScreenshot" function which returns the base64 encoded picture of the current frame from the webcam.

https://www.npmjs.com/package/react-webcam

const WebcamCapture = () => {
  const webcamRef = React.useRef(null);
  const [imgSrc, setimgSrc] = React.useState(null);

  const capture = React.useCallback(
    () => {
      const imageSrc = webcamRef.current.getScreenshot();
      setimgSrc(imageSrc);

    },
    [webcamRef,setimgSrc]
  );

  return (
    <div>
      <Webcam
        audio={false}
        height={720}
        ref={webcamRef}
        screenshotFormat="image/jpeg"
        width={1280}
      />
      <button onClick={capture}>Capture photo</button>
      {imgSrc && (<img src = {imgSrc}/>) }
    </div>
  );
};    

Happy to help!

score:1

This is AG_HIHI's solution written as functional component. I removed the start button, instead start right away once mouted. Place the AppStreamCam component in you parant react component and it shows your webcam feed. Worked like a charm for me.

import React, {useEffect} from 'react'

const AppStreamCam = () => {

  const streamCamVideo = () => {
  var constraints = { audio: true, video: { width: 1280, height: 720 } };
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(function(mediaStream) {
      var video = document.querySelector("video");

      video.srcObject = mediaStream;
      video.onloadedmetadata = function(e) {
        video.play();
      };
    })
    .catch(function(err) {
      console.log(err.name + ": " + err.message);
    }); // always check for errors at the end.
  }

  useEffect(()=>{
    streamCamVideo()
  },[])

  return (
    <div>
        <video autoPlay={true} id="videoElement" ></video>
    </div>
  );
}

export default AppStreamCam

score:2

Your handleVideo method references video, but you don't define that variable anywhere handleVideo can see it. Instead, you define it in render:

var video = document.querySelector("#videoElement");

So there's your first problem, but it's not your real problem. Your real problem is that in React-land you want to avoid document.anything (getElementById, getByTagAndClassName, querySelector, etc.). This is because React uses a virtual DOM, and if you aren't careful when you reference actual DOM elements those references can quickly go bad (as the virtual DOM replaces the actual DOM after a render).

The solution is to use React's own alternative technique: refs. They're easier to explain by example, so here's your code fixed using refs:

handleVideo: function(stream) {
    // KEY CHANGE #1
    this.refs.video.src = window.URL.createObjectURL(stream);
},
render: function() {
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

    if (navigator.getUserMedia) {       
        navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
    }
    return <div>
        {{/* KEY CHANGE #2 */}}
        <video autoplay="true" id="videoElement" ref="video">
        </video>
    </div>;

In other words, if you add a ref="something" attribute to any element you return in your render function, you can reference that element anywhere else in your (React) code by referring to this.refs.something.

There's also other ways to use refs (eg. you can pass a function), but that's outside the scope of this question, so I'd just recommend you read up on the React docs for refs:

https://facebook.github.io/react/docs/refs-and-the-dom.html

EDIT

As Jordan Burnett's answer highlighted, there are other important differences between React and normal JS DOM work. Again, explaining all of them would be outside the scope of this question, but I strongly encourage you to read:

https://facebook.github.io/react/docs/react-component.html

to learn the appropriate methods to override to do DOM-interaction work (eg. binding event handlers on non-React components).

score:3

Some of the code posted in the answer has been deprecated and may no longer work in all browsers.
I have created a new React application which uses the latest syntax. It is very simple and straightforward. I hope it helps someone :)

class AppStreamCam extends React.Component {
  constructor(props) {
    super(props);
    this.streamCamVideo= this.streamCamVideo.bind(this)
  }
  streamCamVideo() {
    var constraints = { audio: true, video: { width: 1280, height: 720 } };
    navigator.mediaDevices
      .getUserMedia(constraints)
      .then(function(mediaStream) {
        var video = document.querySelector("video");

        video.srcObject = mediaStream;
        video.onloadedmetadata = function(e) {
          video.play();
        };
      })
      .catch(function(err) {
        console.log(err.name + ": " + err.message);
      }); // always check for errors at the end.
  }
  render() {
    return (
      <div>
        <div id="container">
          <video autoPlay={true} id="videoElement" controls></video>
        </div>
        <br/>
        <button onClick={this.streamCamVideo}>Start streaming</button>
      </div>
    );
  }
}

Here's my Medium article about it :
How to create a React application to stream your webcam | Basic, Beginner

If it helped don't forget to clap :)

Finally, here's the github repo of the working example : Basic-WebCam-Streamer


Related Query

More Query from same tag