April 2016 update: added info about Chrome 49

October 2016 update: added H.264 support for Chrome 52

For many years recording webcam video on the web meant using Adobe’s Flash plugin. This is still true at the moment, but the new JavaScript Media Recorder API (previously known as the MediaStream Recording API) is slowly crawling its way in today’s modern browsers – and it will allow video recording using just HTML 5 and JavaScript.

In this article we will dig deeper into what the Media Recorder API is, it’s current state, browser support and what it could mean for the future of the web.

What is the Media Recorder API?

Until recently it was just a proposal by the Media Capture Task Force (a joint task force between the WebRTC and Device APIs working groups) that attempts to make basic audio and video recording in the browser very simple.

But recent versions of Chrome and Firefox have started implementing this proposed API.

The API defines the new MediaRecorder JS object, its functions:

  • start()
  • stop()
  • pause()
  • resume()

events:

  • onstart
  • onstop
  • ondataavailable
  • onpause
  • onresume
  • on error

and properties:

  • state
  • stream
  • mimeType

The new MediaRecorder object relies on the (existing) getUserMedia JavaScript function to access to the webcam and microphone but, as we’ll see next, that’s where the touch points with WebRTC end.

HTML5’s Media Recorder API in Action

So how does video recording work using this new API ? The document draft contains all the details, but the gist of it is:

  1. Webcam input (audio and video) is accessed by getUserMedia.
  2. A new MediaRecorder JS object is created and starts the recording process
  3. MediaRecorder‘s ondataavailable event gets triggered with new audio and video data that’s pushed in an array
  4. When the MediaRecorder‘s stop method is called, the onstop event is triggered. This is where all the data can be saved as a video file (webm) or played back immediately in a <video> tag.

HTML5 Video Recorder – Quick Implementation

I’ve created a cross browser demo (Chrome + Firefox) that implements the API. Check it out here or download it from GitHub.

Now let’s go over the JavaScript code a bit.

In the demo code the 1st thing I’m doing is I’m detecting whether the code is run on Chrome or Firefox. This information is important because:

  1. The way the audio and video constraints need to be defined differs in Chrome and Firefox.
  2. At the time of writing, audio recording is not supported in Chrome when using the Media Recorder API.

This is also where I’m specifying the desired video resolution for the recording.

if (getBrowser() == "Chrome") {
    var constraints = {
        "audio": false,
        "video": {
            "mandatory": {
                "minWidth": 320,
                "maxWidth": 320,
                "minHeight": 240,
                "maxHeight": 240
            },
            "optional": []
        }
    };
} else if (getBrowser() == "Firefox") {
    var constraints = {
        audio: true,
        video: {
            width: {
                min: 320,
                ideal: 320,
                max: 1280
            },
            height: {
                min: 240,
                ideal: 240,
                max: 720
            }
        }
    };
}

With that out of the way, clicking the Record button triggers the startRecording function:

function onBtnRecordClicked() {
    if (typeof MediaRecorder === 'undefined' || !navigator.getUserMedia) {
        alert('Sorry! This demo requires Firefox 30 and up or Chrome 47 and up.');
    } else {
        navigator.getUserMedia(constraints, startRecording, errorCallback);
    }
}

startRecording is where all the juicy stuff happens:

function startRecording(stream) {
    console.log('Starting...');
    mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.start();
    var url = window.URL || window.webkitURL;
    videoElement.src = url ? url.createObjectURL(stream) : stream;
    videoElement.play();
    mediaRecorder.ondataavailable = function(e) {
        chunks.push(e.data);
    };
    mediaRecorder.onerror = function(e) {
        log('Error: ' + e);
        console.log('Error: ', e);
    };
    mediaRecorder.onstart = function() {
        log('Started, state = ' + mediaRecorder.state);
    };
    mediaRecorder.onstop = function() {
        log('Stopped, state = ' + mediaRecorder.state);
        var blob = new Blob(chunks, {
            type: "video/webm"
        });
        chunks = [];
        var videoURL = window.URL.createObjectURL(blob);
        downloadLink.href = videoURL;
        videoElement.src = videoURL;
        downloadLink.innerHTML = 'Download video file';
        var rand = Math.floor((Math.random() * 10000000));
        var name = "video_" + rand + ".webm";
        downloadLink.setAttribute("download", name);
        downloadLink.setAttribute("name", name);
    };
    mediaRecorder.onwarning = function(e) {
        log('Warning: ' + e);
    };
}

The function takes as parameter the stream object from getUserMedia. The stream data is made available when ondataavailable gets triggered and that’s where it gets pushed into the aptly named chunks array.

When we press the Stop button onstopis triggered. A new video/webm Blob object is created with the data from the chunks array.

A source for the video tag gets created directly from the Blob data with createObjectURL. The same Blob is also saved as a video when the download is made.

File Formats and Audio Video Codecs

According to the draft:

The contents of the recording will be made available in the platform’s default encoding via the dataavailable event. Functions are available to query the platform’s available set of encodings, and to select the desired ones if the author wishes.

The video container used by both Chrome and Firefox is:

  • .webm

The video codecs available are:

  • VP8 on Firefox and Chrome 47+
  • VP8/VP9 on Chrome 49+
  • VP8/VP9/H.264 on Chrome 52+

The audio codec used is:

  • Vorbis @ 44100 Hz on Firefox 30+
  • Opus Audio @ 48000 Hz on Chrome 49+
Chrome 49+ Chrome 52+ Firefox 30 and up
Container webm webm webm
Video codec VP8/VP9 VP8/VP9/H.264 VP8
Audio codec Opus @ 48kHz Opus @ 48kHz Vorbis @ 44.1 kHz

Not quite the standard .MP4 file with H.264 video and AAC audio.

Browser Support and Limitations

Currently the Media Recorder API is supported on the following browsers:

On Desktop:

On Mobile:

  • Chrome for Android.

Downloaded .webm recordings also work in a video player like VLC regardless if they originate on Firefox or Chrome.

Final Conclusions

Although a simple and promising start, the Media Recording API still has some way to go before it can be used in a production environment:

  • there’s a lack of implementation and even initiative on major browsers like Safari and IE/Edge
  • there are no container or audio/video codec options
  • no sound in the Chrome implementation (audio recording works in Chrome 49)
  • there’s no bitrate or picture quality control
  • there’s no sample rate or audio quality control
  • no support for .mp4, H.264 video and/or AAC audio
  • .webm files (with Vorbis/Opus audio and VP8/VP9 video) will have to be converted before they playback on virtually anything else other than the browsers they were recorded in
  • all the recorded data is stored locally in the RAM, which limits the amount of video you can record to short video clips – as opposed to video recording solutions that rely on streaming the data
  • the standard’s pause() and resume() functions are not implemented yet

As for being a direct competitor for Flash when it comes to video recording, it can and most surely will happen, but at the current stage of the API, a Flash client connected to a media server is still the best production ready and cross (desktop) browser solution for recording video.

More about the MediaStream Recording API on our blog: