Virtual Webcam

Website to buzz at preset time in meetings

Released: Virtual Webcam

Virtualizing webcam

While scrolling internal feed at workplace portal, I came across a hackathon project published by a couple of FB engineers internally. It used a virtual-webcam GitHub repo to provide a chrome extension which can mask the camera input to support certain effects, like overlay Gifs, stickers, dummy video, etc. Although the internal hack was to support some other things, I thought to try and build out what I conceived. My vision is to explore and understand how camera input can be intercepted and replaced with a pre-recorded video. I would play along with multiple things in the journey.


In short, Following are the reasons I decided to fork and play around with Virtual Webcam:

  • Understand how to intercept camera input

  • Understand how to add effects to the camera stream

  • Understand the basics of building chrome extensions

  • Understand testing chrome extensions

As POC, I made a simple website to achieve these: Virtual Webcam. I had observed that I may need to experiment more before it can be called as usable!


  1. How to intercept camera input:

     // override the MediaDevices.getUserMedia() API
     const enumerateDevicesFn = MediaDevices.prototype.enumerateDevices;
     const getUserMediaFn = MediaDevices.prototype.getUserMedia;
     MediaDevices.prototype.enumerateDevices = async function () {
     const res = await;
     // We could add "Virtual VHS" or "Virtual Median Filter" and map devices with filters.
         deviceId: "virtual",
         groupID: "uh",
         kind: "videoinput",
         label: "Virtual Chrome Webcam",
     return res;
     MediaDevices.prototype.getUserMedia = async function () {
     const res = await, ...arguments);
     //// Intercepted here!!
     return res;
  2. How to add effects to the camera stream:

     // camera input
     const video = document.createElement("video");
     const canvas = document.createElement("canvas");
     this.canvas = canvas;
     this.renderer = new ShaderRenderer(this.canvas, video, shader);
     video.addEventListener("playing", () => {
     // Use a 2D Canvas.
     // this.canvas.width =;
     // this.canvas.height =;
     // Use a WebGL Renderer.
     video.srcObject = stream;
     video.autoplay = true; = video;
     //this.ctx = this.canvas.getContext('2d');
     this.outputStream = this.canvas.captureStream();
  3. Basics of building chrome extensions:

     // having a manifest.json but cannot load any external resource
     "name": "Virtual Webcam",
     "version": "1.0.0",
     "minimum_chrome_version": "10.0",
     "description": "Virtual webcam on all chrome tabs",
     "default_popup": "popup.html"
     "content_scripts": [
         "matches": [
         "js": [
         "run_at": "document_start",
         "all_frames": true
         "permissions": [
         "manifest_version": 2,
             "web_accessible_resources": [
  4. Testing chrome extensions:

    I needed to upload the manifest.json in chrome://extensions Load unpacked option and all files were picked up automatically on the go.

I felt it was not so straightforward to implement and it had a lot of dependencies to slow me down, especially around Chrome Extensions, Canvas, WebGL, etc. Having a simple website to overlay camera video with effects worked fine for me, but I am yet to test how it would perform for browser-based video calls.

For my demo, the source is hosted on GitHub repo: Virtual Webcam repo, quick sneak peek is below:

Default Camera Input
B&W Filter

Flicker Filter
Cartoonize Filter

javascript website chrome

Dialogue & Discussion