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 WebRTCand 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:
Webcam input (audio and video) is accessed by getUserMedia.
A new MediaRecorder JS object is created and starts the recording process
MediaRecorder‘s ondataavailable event gets triggered with new audio and video data that’s pushed in an array
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 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:
The way the audio and video constraints need to be defined differs in Chrome and Firefox.
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:
Firefox 30 and up
Chrome 47 & 48 ( no sound is being recorded and it only works with experimental Web Platform features turned on from chrome://flags )
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: