import { MediaSet, MediaSetServiceClientImpl } from './generated/media_set'; import { newRPC } from './App'; import { useEffect, useRef } from 'react'; interface Props { mediaSet: MediaSet; position: number; duration: number; height: number; video: HTMLVideoElement; } export const VideoPreview: React.FC = ({ mediaSet, position, duration, height, video, }: Props) => { const videoCanvasRef = useRef(null); // effects // render canvas useEffect(() => { // TODO: not sure if requestAnimationFrame is recommended here. requestAnimationFrame(() => { (async function () { const canvas = videoCanvasRef.current; if (canvas == null) { console.error('no canvas ref available'); return; } const ctx = canvas.getContext('2d'); if (ctx == null) { console.error('no 2d context available'); return; } // Set aspect ratio. canvas.width = canvas.height * (canvas.clientWidth / canvas.clientHeight); // If the required position is 0, display the thumbnail instead of // trying to render the video. The most important use case is before a // click event has happened, when autoplay restrictions will prevent // the video being rendered to canvas. if (position == 0) { const service = new MediaSetServiceClientImpl(newRPC()); const thumbnail = await service.GetVideoThumbnail({ id: mediaSet.id, }); // TODO: avoid fetching the image every re-render: const url = URL.createObjectURL( new Blob([thumbnail.image], { type: 'image/jpeg' }) ); const img = new Image(thumbnail.width, thumbnail.height); img.src = url; img.onload = () => ctx.drawImage(img, 0, 0, 177, 100); return; } // otherwise, render the video, which (should) work now. const durSecs = duration / 1000; const ratio = position / durSecs; const x = (canvas.width - 177) * ratio; ctx.clearRect(0, 0, x, canvas.height); ctx.clearRect(x + 177, 0, canvas.width - 177 - x, canvas.height); ctx.drawImage(video, x, 0, 177, 100); })(); }); }, [mediaSet, position]); // render component const containerStyles = { height: height + 'px', position: 'relative', flexGrow: 0, } as React.CSSProperties; const canvasStyles = { position: 'absolute', width: '100%', height: '100%', display: 'block', zIndex: 1, } as React.CSSProperties; return ( <>
); };