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