Videos can be recorded from a camera using MediaDevices & MediaRecorder APIs :
- Use getUserMedia() method to get access to the user's webcam.
- Use the camera stream to create a new MediaRecorder object.
- Use start() & stop() methods on the MediaRecorder object to start & stop recording.
Demo
HTML & Javascript
<button id="start-camera">Start Camera</button>
<video id="video" width="320" height="240" autoplay></video>
<button id="start-record">Start Recording</button>
<button id="stop-record">Stop Recording</button>
<a id="download-video" download="test.webm">Download Video</a>
- #start-camera button requests user for camera access.
- #video displays the camera stream.
- #start-record starts video recording.
- #stop-record stops video recording.
- #download-video downloads the recorded video.
let camera_button = document.querySelector("#start-camera");
let video = document.querySelector("#video");
let start_button = document.querySelector("#start-record");
let stop_button = document.querySelector("#stop-record");
let download_link = document.querySelector("#download-video");
let camera_stream = null;
let media_recorder = null;
let blobs_recorded = [];
camera_button.addEventListener('click', async function() {
camera_stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
video.srcObject = camera_stream;
});
start_button.addEventListener('click', function() {
// set MIME type of recording as video/webm
media_recorder = new MediaRecorder(camera_stream, { mimeType: 'video/webm' });
// event : new recorded video blob available
media_recorder.addEventListener('dataavailable', function(e) {
blobs_recorded.push(e.data);
});
// event : recording stopped & all blobs sent
media_recorder.addEventListener('stop', function() {
// create local object URL from the recorded video blobs
let video_local = URL.createObjectURL(new Blob(blobs_recorded, { type: 'video/webm' }));
download_link.href = video_local;
});
// start recording with each recorded blob having 1 second video
media_recorder.start(1000);
});
stop_button.addEventListener('click', function() {
media_recorder.stop();
});
- getUserMedia() method requests access to the user's webcam.
- Using the video stream from the camera, a new MediaRecorder object is created.
- The format of the recorded video has been set as video/webm as its support is great across browsers. video/mp4 would have even better, however it has limited browser support.
- start() method starts the recording. Its parameter represents the timeslice of captured video chunks (however it is optional — if no parameter is passed then entire video will be recorded as a single chunk).
- dataavailable event is fired each time when a recorded video chunk is available (if no timeslice has been provided during start, then this will be fired only once).
- stop() method stops the recording.
- stop event is fired after recording is stopped and final dataavailable event has been fired. At this point all recorded blobs can be combined.
Browser Compatibility
Chrome, Edge & Firefox have support for the MediaRecorder API. They all support video/webm.
For Safari it is available in iOS 14.3 as beta. It is also available in Safari Technology Preview. Proper support for Safari should be there by 2021 year end. Safari will support video/mp4 format.
Other FAQs
How to add a pause/resume feature to recording ?
The pause() & resume() methods can be used to pause and resume the recording.
// media_recorder refers to created MediaRecorder object
// pauses recording
media_recorder.pause();
// resume recording after it was paused
media_recorder.resume();
How to upload the recorded video to server ?
The recorded blobs can be converted to a Javascript File, which can be uploaded to server via XMLHttpRequest or fetch().
// blobs_recorded refers to recorded blobs array
let recording = new File(blobs_recorded, 'recording.webm', { type: 'video/webm' });
let data = new FormData();
data.append('file', recording);
// send fetch along with cookies
let response = await fetch('/upload.php', {
method: 'POST',
credentials: 'same-origin',
body: data
});
Comments