Live video on the AT Protocol
at next 89 lines 2.3 kB view raw
1/** 2 * Utility functions for capturing video frames 3 */ 4import React from "react"; 5 6const isWeb = typeof window !== "undefined"; 7 8/** 9 * Captures a frame from a video ref or element and returns it as a compressed JPEG blob 10 * 11 * @param videoRefOrElement The video ref or element to capture from 12 * @param maxWidth Maximum width of the output image (maintains aspect ratio) 13 * @param quality JPEG quality (0-1), lower means smaller file size 14 * @returns A Promise that resolves to a Blob of the compressed image 15 */ 16export const captureVideoFrame = async ( 17 videoRefOrElement: 18 | React.MutableRefObject<HTMLVideoElement | null> 19 | HTMLVideoElement, 20 maxWidth = 1280, 21 quality = 0.85, 22): Promise<Blob> => { 23 let videoElement: HTMLVideoElement; 24 25 if ( 26 videoRefOrElement && 27 typeof videoRefOrElement === "object" && 28 "current" in videoRefOrElement 29 ) { 30 if (!videoRefOrElement.current) { 31 throw new Error("No video element available in ref"); 32 } 33 videoElement = videoRefOrElement.current; 34 } else { 35 videoElement = videoRefOrElement as HTMLVideoElement; 36 } 37 38 if (!isWeb) { 39 throw new Error("captureVideoFrame is only available on web platforms"); 40 } 41 42 return new Promise((resolve, reject) => { 43 try { 44 const canvas = document.createElement("canvas"); 45 const ctx = canvas.getContext("2d"); 46 47 if (!ctx) { 48 reject(new Error("Could not get canvas context")); 49 return; 50 } 51 52 const videoWidth = videoElement.videoWidth; 53 const videoHeight = videoElement.videoHeight; 54 55 if (videoWidth === 0 || videoHeight === 0) { 56 reject(new Error("Video has no dimensions, may not be playing yet")); 57 return; 58 } 59 60 let width = videoWidth; 61 let height = videoHeight; 62 63 if (width > maxWidth) { 64 const ratio = maxWidth / width; 65 width = maxWidth; 66 height = height * ratio; 67 } 68 69 canvas.width = width; 70 canvas.height = height; 71 72 ctx.drawImage(videoElement, 0, 0, width, height); 73 74 canvas.toBlob( 75 (blob) => { 76 if (blob) { 77 resolve(blob); 78 } else { 79 reject(new Error("Failed to create blob from canvas")); 80 } 81 }, 82 "image/jpeg", 83 quality, 84 ); 85 } catch (error) { 86 reject(error); 87 } 88 }); 89};