diff --git a/frontend/src/components/VideoPreview.tsx b/frontend/src/components/VideoPreview.tsx new file mode 100644 index 0000000..0d843f1 --- /dev/null +++ b/frontend/src/components/VideoPreview.tsx @@ -0,0 +1,67 @@ +import React, { useEffect, useRef } from 'react'; +import Hls from 'hls.js'; + +interface VideoPreviewProps { + portIndex: number; +} + +export function VideoPreview({ portIndex }: VideoPreviewProps) { + const videoRef = useRef(null); + const hlsRef = useRef(null); + + useEffect(() => { + const src = `/hls/port_${portIndex}.m3u8`; + + if (!videoRef.current) { + return; + } + + if (Hls.isSupported()) { + const hls = new Hls({ + enableWorker: true, + lowLatencyMode: true, + }); + + hlsRef.current = hls; + hls.loadSource(src); + hls.attachMedia(videoRef.current); + + hls.on(Hls.Events.MANIFEST_PARSED, () => { + videoRef.current?.play().catch((err) => { + console.error('Failed to autoplay video:', err); + }); + }); + + hls.on(Hls.Events.ERROR, (event, data) => { + console.error('HLS.js error:', data); + }); + } else if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) { + // Safari native HLS support + videoRef.current.src = src; + videoRef.current.play().catch((err) => { + console.error('Failed to autoplay video:', err); + }); + } else { + console.error('HLS streaming is not supported in this browser'); + } + + return () => { + if (hlsRef.current) { + hlsRef.current.destroy(); + hlsRef.current = null; + } + }; + }, [portIndex]); + + return ( +
+
+ ); +}