# Access Cameara with MediaDevices API

A snippet to show how we can access camera to capture an image with MediaDevices API:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Cam test</title>
</head>
<body>
  <video autoplay></video>
  <button id="capture-btn">Capture</button>
  <canvas style="display:none;"></canvas>
  <img src="">
  <script>
    const video = document.querySelector('video');
    const captureBtn = document.querySelector('#capture-btn');
    const canvas = document.querySelector('canvas');
    const img = document.querySelector('img');

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

    captureBtn.addEventListener('click', () => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      canvas.getContext('2d').drawImage(video, 0, 0);
      // Other browsers will fall back to image/png
      img.src = canvas.toDataURL('image/webp');
    })
  </script>
</body>
</html>

What’s happening here?

  • The video tag receives video stream from the camera instead of a source video URL. autoplay attribute is needed, otherwise the video display will be frozen on the first frame.
  • navigator.mediaDevices.getUserMedia is where the camera is accessed. The parameters could include audio: true if you want to access audio. After accessing camera successfully, the video feed streams video data into the video element
  • To capture a screenshot, the canvas is used to draw the image, which then gets displayed within the img element.

# Switching Cameras

A crude implementation of switching cameras (back vs front in mobile):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Cam test</title>
</head>
<body>
  <video autoplay></video>
  <button id="capture-btn">Capture</button>
  <button id="change-cam-btn">Change camera</button>
  <canvas style="display:none;"></canvas>
  <img src="">
  <script>
    const video = document.querySelector('video');
    const captureBtn = document.querySelector('#capture-btn');
    const changeCamBtn = document.querySelector('#change-cam-btn');
    const canvas = document.querySelector('canvas');
    const img = document.querySelector('img');

    let deviceIdArr = [];
    let index = 0;
    let constraints = {
      video: {
        deviceId: {
          exact: ''
        }
      }
    }
    let videoStream;

    function displayVideoFeed() {
      navigator.mediaDevices.getUserMedia(constraints)
        .then((stream) => {
          videoStream = stream;
          video.srcObject = stream;
      })
    }

    function stopAllVideoTracks() {
      if(videoStream && videoStream.getVideoTracks().length > 0) {
        videoStream.getVideoTracks().forEach((track) => {
          track.stop();
        })
      }
    }

    function incrementIndex() {
      index++;
      if(index >= deviceIdArr.length) {
        index = 0;
      }
    }

    navigator.mediaDevices.enumerateDevices()
      .then((devices) => {
        const videoDevices = devices.filter((device) => device.kind === 'videoinput');
        deviceIdArr = videoDevices.map((device) => device.deviceId);
        constraints.video.deviceId.exact = deviceIdArr[index];
        displayVideoFeed();
      })

    changeCamBtn.addEventListener('click', () => {
      incrementIndex();
      constraints.video.deviceId.exact = deviceIdArr[index];
      stopAllVideoTracks();
      displayVideoFeed();
    })

    captureBtn.addEventListener('click', () => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      canvas.getContext('2d').drawImage(video, 0, 0);
      // Other browsers will fall back to image/png
      img.src = canvas.toDataURL('image/webp');
    })
  </script>
</body>
</html>