DEV Community

Abhirup Pal
Abhirup Pal

Posted on

Compressing videos to webm in the browser

πŸš€ 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.

Top comments (0)