VideoTexture / useVideoTexture
A convenience hook that returns a THREE.VideoTexture
and integrates loading into suspense.
By default it falls back until the loadedmetadata
event. Then it starts playing the video, which, if the video is muted, is allowed in the browser without user interaction.
type VideoTextureProps = {
unsuspend?: 'canplay' | 'canplaythrough' | 'loadstart' | 'loadedmetadata'
muted?: boolean
loop?: boolean
start?: boolean
crossOrigin?: string
}
export function useVideoTexture(src: string, props: VideoTextureProps) {
const { unsuspend, start, crossOrigin, muted, loop } = {
unsuspend: 'loadedmetadata',
crossOrigin: 'Anonymous',
muted: true,
loop: true,
start: true
...props,
}
const texture = useVideoTexture("/video.mp4")
return (
<mesh>
<meshBasicMaterial map={texture} toneMapped={false} />
MediaStream
It also accepts a MediaStream
from eg. .getDisplayMedia()
or .getUserMedia()
:
const [stream, setStream] = useState()
return (
<mesh onClick={async () => setStream(await navigator.mediaDevices.getDisplayMedia({ video: true }))}>
<React.Suspense fallback={<meshBasicMaterial wireframe />}>
<VideoMaterial src={stream} />
</React.Suspense>
function VideoMaterial({ src }) {
const texture = useVideoTexture(src)
return <meshBasicMaterial map={texture} toneMapped={false} />
}
NB: It's important to wrap VideoMaterial
into React.Suspense
since, useVideoTexture(src)
here will be suspended until the user shares its screen.
HLS
HLS - useVideoTexture supports .m3u8 HLS manifest via (https://github.com/video-dev/hls.js).
You can fine-tune via the hls configuration:
const texture = useVideoTexture('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8', {
hls: { abrEwmaFastLive: 1.0, abrEwmaSlowLive: 3.0, enableWorker: true }
})
Available options: https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning