Compressing videos to webm in the browser

Abhirup Pal - Oct 5 - - Dev Community

🚀 Supercharge Your Web Videos: MP4 to WebM Compression with React

Ever bored with nothing interesting at work? Well, that’s when I decided to scratch my itch to tinker around with the current state of browser APIs. Could we compress videos directly through web APIs? In this blog, I’ll show you how to use modern browser features to compress MP4 videos to WebM format—all within a React app.

🛠️ What You'll Need

Before we dive in, make sure you've got:

  • React with Typescript
  • Ant Design to build some nice UI.

Quick setup:



npm install antd

Enter fullscreen mode Exit fullscreen mode




Setting up the component

Let's set up our React component with all the React imports:



import { useState, useRef, useEffect, ChangeEvent } from "react";
import { Button, Progress, message, Flex } from "antd";

const VideoCompression = () => {
const [sourceVideo, setSourceVideo] = useState<File | null>(null);
const [compressedVideo, setCompressedVideo] = useState<Blob | null>(null);
const [isCompressing, setIsCompressing] = useState(false);
const [progress, setProgress] = useState(0);
const [width, setWidth] = useState<string>("");
const [height, setHeight] = useState<string>("");
const videoRef = useRef<HTMLVideoElement>(null);
const inputRef = useRef<HTMLInputElement>(null);

Enter fullscreen mode Exit fullscreen mode




Accepting the File Upload

We need a way to choose our MP4 file:



const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
if (!event.target.files) return;
const file = event.target.files[0];
if (file && file.type.startsWith("video/")) {
setSourceVideo(file);
setCompressedVideo(null);
} else {
message.error("Please select a valid video file.");
}
};

Enter fullscreen mode Exit fullscreen mode




Extracting Video Metadata

Let's get the video metadata:



useEffect(() => {
if (sourceVideo) {
const video = document.createElement("video");
video.onloadedmetadata = () => {
setWidth(video.videoWidth.toString());
setHeight(video.videoHeight.toString());
};
video.src = URL.createObjectURL(sourceVideo);
}
}, [sourceVideo]);

Enter fullscreen mode Exit fullscreen mode




Video Compression

Here's where the magic happens:



const compressVideo = async () => {
if (!sourceVideo) {
message.error("Please upload a video first.");
return;
}
setIsCompressing(true);
setProgress(0);
try {
const stream = videoRef.current?.captureStream();
const mediaRecorder = new MediaRecorder(stream, {
mimeType: "video/webm",
videoBitsPerSecond: 1000000,
});
const chunks: BlobPart[] = [];
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
chunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
const blob = new Blob(chunks, { type: "video/webm" });
setCompressedVideo(blob);
setIsCompressing(false);
setProgress(100);
};
if (!videoRef.current) return;
videoRef.current.onloadedmetadata = () => {
videoRef.current!.muted = true;
videoRef.current?.play();
mediaRecorder.start();
};
videoRef.current.onended = () => {
mediaRecorder.stop();
videoRef.current?.pause();
};
videoRef.current.ontimeupdate = () => {
if (!videoRef.current) return;
const progress =
(videoRef.current.currentTime / videoRef.current.duration) * 100;
setProgress(progress);
};
if (!videoRef.current) return;
videoRef.current.width = Number.parseFloat(width);
videoRef.current.height = Number.parseFloat(height);
videoRef.current.src = URL.createObjectURL(sourceVideo);
} catch (err) {
message.error("Error compressing video: " + (err as Error).message);
setIsCompressing(false);
}
};

Enter fullscreen mode Exit fullscreen mode




Downloading the Compressed Video




const downloadCompressedVideo = () => {
if (compressedVideo) {
const url = URL.createObjectURL(compressedVideo);
const a = document.createElement("a");
a.href = url;
a.download = "compressed_video.webm";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
};

Enter fullscreen mode Exit fullscreen mode




🚀 Launch Time: Putting It All Together

Here's a sneak peek of our complete work:

Image description

Deployment Link:
https://abhirup-99.github.io/browser-compression-webm/

Code Link:
https://github.com/Abhirup-99/browser-compression-webm

🎉 Wrap-up: You're Now a Video Compression Wizard!

Congratulations! You've just built a powerful MP4 to WebM video compressor using React. Your web videos will now load faster than ever, delighting users and boosting your site's performance.

🚀 Next Steps:

  • I will be tinkering with the browser compression APIs further and hopefully there will be an blog out soon.

.
Terabox Video Player