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 (1)

Collapse
 
chen_ce2c53c4b554 profile image
FL • Edited

Hello, blogger! Why is the size of the downloaded video 0B after I compress it? What is the reason for this?