Dec 8, 2020

Video capture using WebRTC

Capturing the feed of a users camera can be a daunting undertaking involving one or multiple third party packages. Often we opt for prompting the user to upload the video or image we need, causing more steps for the user and a more difficult user experience. Luckily, there is a simple and easy solution for this scenario

What is WebRTC?

WebRTC (Web Real-Time Communication) is an open source technology released by Google in 2011. It enables Web applications and sites to capture and optionally stream audio and/or video media, as well as to exchange arbitrary data between browsers without requiring an intermediary. The set of standards that comprise WebRTC makes it possible to share data and perform teleconferencing peer-to-peer, without requiring that the user install plug-ins or any other third-party software.

There are many different use-cases for WebRTC, from basic web apps that uses the camera or microphone, to more advanced video-calling applications and screen sharing. We’ll be looking at one of the simpler use cases, streaming video in the browser

Getting started

For simplicity, we’ll just build our photo capture feature in a basic JavaScript application. We’ll start with our index.html

<!doctype html>
<html>
  <head>
    <title>WebRTC Starter</title>
  </head>
  <body>
    <div style="flex-direction: column;align-items: center;display: flex;" id="root">
      <video id="video" autoplay></video>
      
      <button 
        style="margin: 2rem 0;height: 2rem; width: 8rem;" 
        type="button" 
        id="start-button">
          Start Video
      </button>

      <button 
        hidden 
        style="margin: 2rem 0;height: 2rem; width: 8rem;" 
        type="button" 
        id="stop-button">
          Stop Video
      </button>

    </div>
    <script type="text/javascript" src="index.js"></script>
  </body>
</html>

There’s a few things going on here but this is the most important part

 <button 
   style="margin: 2rem 0; height: 2rem; width: 8rem;" 
   type="button" 
    id="start-button">
      Start Video
  </button>

 <button 
   hidden 
   style="margin: 2rem 0;height: 2rem; width: 8rem;" 
    type="button" 
    id="stop-button">
       Stop Video
 </button>

<video id="video" autoplay></video>

We have a button that we want to click to start the video, a button that is hidden that we will use to stop our video, and the video element to render our WebRTC stream. Next we move on to our JavaScript implementation

The JavaScript

First we’ll set a few variables for interacting with our video and buttons

const startButton = document.getElementById('start-button')
const stopButton = document.getElementById('stop-button')
const video = document.getElementById('video')

Next, we’ll define a couple of functions for starting and stopping our video

const playVideo = () => {
  startButton.hidden = true
  stopButton.hidden = false

  const constraints = {
    video: {
      width: 500,     
      height: 500
    }
  }

  navigator.mediaDevices.getUserMedia(constraints)
  .then((stream) => {
    video.srcObject = stream
    video.play()
  })
  .catch((err) => {
    console.log(err);
  })
}

const stopVideo = () => {
  startButton.hidden = false
  stopButton.hidden = true

  video.srcObject = null
}

Let’s unpack these functions a little.

getUserMedia()

const playVideo = () => {
  startButton.hidden = true
  stopButton.hidden = false

  const constraints = {
    video: {
      width: 500,     
      height: 500
    }
  }

  navigator.mediaDevices.getUserMedia(constraints)
  .then((stream) => {
    video.srcObject = stream
    video.play()
  })
  .catch((err) => {
    console.log(err);
  })
}

The first 2 lines are pretty clear. As we start the video we hide our start button and show out stop button. The real meat of this function is in the getUserMedia function.

getUserMedia is a function given to us by WebRTC to be called on a MediaDevices object, which we have accessed by using navigator.mediaDevices. It returns a Promise that resolves to a MediaStream object, and accepts an object of constraints for things such as height, width, etc, defined above.

When our Promise resolves, we set the srcObject of our video element to the returned MediaStream, and call the play() function. We should now see the video stream from our primary camera

Stopping the video

Now stopping the video becomes as simple as nulling out the srcObject on the video and changing which button is displayed

const stopVideo = () => {
  startButton.hidden = false
  stopButton.hidden = true

  video.srcObject = null
}

That’s it! WebRTC gives us the power to capture camera feed from the browser, using very little code. Note that this does not account for specific behavior in other browsers. We’ll go over that in a later post

About the Author

Caleb Cowen profile.

Caleb Cowen

Sr Consultant
Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
An Exploration in Rust: Musings From a Java/C++ Developer
Why Rust? It’s fast (runtime performance) It’s small (binary size) It’s safe (no memory leaks) It’s modern (build system, language features, etc) When Is It Worth It? Embedded systems (where it is implied that interpreted […]
Getting Started with CSS Container Queries
For as long as I’ve been working full-time on the front-end, I’ve heard about the promise of container queries and their potential to solve the majority of our responsive web design needs. And, for as […]
Simple improvements to making decisions in teams
Software development teams need to make a lot of decisions. Functional requirements, non-functional requirements, user experience, API contracts, tech stack, architecture, database schemas, cloud providers, deployment strategy, test strategy, security, and the list goes on. […]
JavaScript Bundle Optimization – Polyfills
If you are lucky enough to only support a small subset of browsers (for example, you are targeting a controlled set of users), feel free to move along. However, if your website is open to […]