Use canvas to save video state before switching to smooth transitions between previews

This commit is contained in:
Nicolas Mowen 2024-03-23 16:49:26 -06:00
parent 3a9607e59b
commit 11b7b90b2b

View File

@ -134,6 +134,7 @@ function PreviewVideoPlayer({
// initial state // initial state
const [loaded, setLoaded] = useState(false); const [loaded, setLoaded] = useState(false);
const [hasCanvas, setHasCanvas] = useState(false);
const initialPreview = useMemo(() => { const initialPreview = useMemo(() => {
return cameraPreviews.find( return cameraPreviews.find(
(preview) => (preview) =>
@ -187,22 +188,51 @@ function PreviewVideoPlayer({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [controller, timeRange]); }, [controller, timeRange]);
// canvas to cover preview transition
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const [videoWidth, videoHeight] = useMemo(() => {
if (!previewRef.current) {
return [0, 0];
}
return [previewRef.current.videoWidth, previewRef.current.videoHeight];
// we know the video size will be known on load
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loaded]);
// handle switching sources
useEffect(() => { useEffect(() => {
if (!currentPreview || !previewRef.current) { if (!currentPreview || !previewRef.current) {
return; return;
} }
if (canvasRef.current) {
canvasRef.current
.getContext("2d")
?.drawImage(previewRef.current, 0, 0, videoWidth, videoHeight);
setHasCanvas(true);
}
previewRef.current.load(); previewRef.current.load();
// we only want this to change when current preview changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentPreview, previewRef]); }, [currentPreview, previewRef]);
return ( return (
<div <div
className={`relative w-full ${className ?? ""} ${onClick ? "cursor-pointer" : ""}`} className={`relative w-full rounded-2xl overflow-hidden ${className ?? ""} ${onClick ? "cursor-pointer" : ""}`}
onClick={onClick} onClick={onClick}
> >
<canvas
ref={canvasRef}
width={videoWidth}
height={videoHeight}
className={`absolute h-full left-1/2 -translate-x-1/2 bg-black ${!loaded && hasCanvas ? "" : "hidden"}`}
/>
<video <video
ref={previewRef} ref={previewRef}
className={`size-full rounded-2xl bg-black`} className="size-full"
preload="auto" preload="auto"
autoPlay autoPlay
playsInline playsInline
@ -227,7 +257,7 @@ function PreviewVideoPlayer({
<source src={currentPreview.src} type={currentPreview.type} /> <source src={currentPreview.src} type={currentPreview.type} />
)} )}
</video> </video>
{!loaded && <Skeleton className="absolute inset-0" />} {!loaded && !hasCanvas && <Skeleton className="absolute inset-0" />}
{cameraPreviews && !currentPreview && ( {cameraPreviews && !currentPreview && (
<div className="absolute inset-0 bg-black text-white rounded-2xl flex justify-center items-center"> <div className="absolute inset-0 bg-black text-white rounded-2xl flex justify-center items-center">
No Preview Found No Preview Found