DEV Community

Cover image for Save your web camera recording locally in your browser
EneasLari
EneasLari

Posted on

6 2 1

Save your web camera recording locally in your browser

This post is the sequel of How to record your web camera only with JavaScript.

Today we will store the video after recording into browser's indexedDB.

So lets start with the already existing code of web camera recording Source code. We will make a new branch for this project:

Image description

I know I know I am good at naming!

Next let's create a new file named idb-file-storage.js. This is a wrapper of indexedDB API

Now lets create a new file named indexedDB.js:

import { IDBFileStorage, getFileStorage } from './idb-file-storage.js'
async function saveRecordedVideoInDB(recordedpecies, stored_name, blob_name) {
const blob = new Blob(recordedpecies, { type: 'video/webm' })
const storedVideo = await getFileStorage({ name: stored_name });
await storedVideo.put(blob_name, blob);
}
async function retreiveVideoFromDB(stored_name) {
const storedVideo = await getFileStorage({ name: stored_name });
const videosList = await storedVideo.list();
var array = []
for (const blobname of videosList) {
const blob = await storedVideo.get(blobname);
blob.name = blobname
array.push(blob)
}
if (array) {
return array
} else {
return "no videos recorded"
}
}
async function removeStoredVideo(bloburl, videoname, stored_name) {
const videosStore = await getFileStorage({ name: stored_name });
URL.revokeObjectURL(bloburl);
await videosStore.remove(videoname);
}
window.retreiveVideoFromDB = retreiveVideoFromDB
window.saveRecordedVideoInDB = saveRecordedVideoInDB
window.removeStoredVideo = removeStoredVideo
view raw indexedDB.js hosted with ❤ by GitHub

In this file we define three functions:

  • saveRecordedVideoInDB(recordedpieces, stored_name, blob_name)
    function that saves the array of recorded pieces

  • retreiveVideoFromDB(stored_name)
    returns an array of stored videos in indexedDB

  • removeStoredVideo(bloburl, videoname, stored_name)
    removes a specific video from indexedDB

Now add a script tag with indexedDB script at index.html:

<script type="module" src="js/indexedDB.js"></script>

And finally edit the index.js. Call saveRecordedVideoInDB function when the recording stops.

    mediarecorder.onstop = ()=>{ 
     window.saveRecordedVideoInDB([recordedChunks],"storedvideos", "videoname" + datetime).then(() => {
            download();
          })
    }
Enter fullscreen mode Exit fullscreen mode

The final index.html and index.js:

index.html:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Web camera recorder</title>
</head>
<body>
<div class="container text-center">
<div class="btn-group" role="group">
<button type="button" id="recbutton" class="btn btn-secondary">Rec</button>
<button type="button" id="stopbutton" class="btn btn-secondary">Stop</button>
</div>
</div>
<div class="container">
<video autoplay playsinline webkit-playsinline muted id="videoelement"
style="max-width: 100%;height: auto;"></video>
</div>
<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
<script type="module" src="indexedDB.js"></script>
<script src="index.js"></script>
</body>
</html>
view raw index.html hosted with ❤ by GitHub

index.js

var videoelement = document.getElementById("videoelement");
var localStreamConstraints = {
audio: true,
video: { width: 1920, height: 1080 },
};
var mediarecorder
var options = { mimeType: "video/webm; codecs=vp9" };
var recordedChunks=[]
if (videoelement) {
console.log("we have the video")
navigator.mediaDevices
.getUserMedia(localStreamConstraints)
.then(gotStream)
.catch(function (e) {
if (confirm("An error with camera occured:(" + e.name + ") Do you want to reload?")) {
location.reload();
}
});
}
//if found stream found
function gotStream(stream) {
console.log("Adding local stream.");
videoelement.srcObject = stream
mediarecorder=new MediaRecorder(stream,options)
mediarecorder.ondataavailable = handleDataAvailable;
var today = new Date();
var date = today.getUTCFullYear()+""+(today.getUTCMonth()+1)+""+today.getUTCDate()
var time = today.getUTCHours() + "" + today.getUTCMinutes() + "" + today.getUTCSeconds()+""+today.getUTCMilliseconds();
var datetime=date+ "" + time
mediarecorder.onstop = ()=>{
window.saveRecordedVideoInDB([recordedChunks], "storedvideos", "videoname" + datetime).then(() => {
download();
})
}
}
var recbtn=document.getElementById("recbutton")
if(recbtn){
recbtn.addEventListener('click',()=>{
mediarecorder.start()
})
}
var stopbtn=document.getElementById("stopbutton")
if(stopbtn){
stopbtn.addEventListener('click',()=>{
mediarecorder.stop()
})
}
function handleDataAvailable(event) {
if (event.data.size > 0) {
recordedChunks.push(event.data);
console.log(event.data)
}
}
function download() {
var blob = new Blob(recordedChunks, {
type: 'video/webm'
});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'test.webm';
a.click();
window.URL.revokeObjectURL(url);
}
view raw index.js hosted with ❤ by GitHub

If you press f12 and you navigate to Application > Storage > IndexedDb in console panel you will see that a new entry added.

If you want to retrieve it or delete it from html, simply call the retreiveVideoFromDB and removeStoredVideo.

Source code provided below:

Source Code

Thanks for your time.
Leave a question or comment below.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
gladyslowe profile image
GladysLowe

These info-packed moving pictures are a fantastic way to share information and tell the world about your brand. Spell to end a relationship

Collapse
 
thien711 profile image
Thien Nguyen • Edited

Thank for your post.
Regarding to dowload the recorded, I am facing an issue that cannot waiting for the recorded to dowload done (in my case: dowload done then close tab).
Is there any way to wait the video for dowloaded?

I am Vietnammes. Sorry for my english not well.