Created
October 11, 2023 07:35
-
-
Save netgfx/889116d1ca6e58fe840e8375169d41eb to your computer and use it in GitHub Desktop.
R3F HLS Video texture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as THREE from 'three' | |
import { useEffect, useRef } from 'react' | |
import { useThree } from '@react-three/fiber' | |
import { suspend, preload, clear } from 'suspend-react' | |
import Hls from 'hls.js' | |
export function useHLSVideoTexture(src, props) { | |
const { unsuspend, start, crossOrigin, muted, loop, ...rest } = { | |
unsuspend: 'loadedmetadata', | |
crossOrigin: 'Anonymous', | |
muted: true, | |
loop: true, | |
start: true, | |
playsInline: true, | |
...props | |
} | |
const videoRef = useRef() | |
const gl = useThree((state) => state.gl) | |
const createHLSBinding = () => { | |
if (Hls.isSupported()) { | |
var video = videoRef.current | |
console.log(video) | |
// If you are using the ESM version of the library (hls.mjs), you | |
// should specify the "workerPath" config option here if you want | |
// web workers to be used. Note that bundlers (such as webpack) | |
// will likely use the ESM version by default. | |
var hls = new Hls() | |
hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { | |
console.log('manifest loaded, found ' + data.levels.length + ' quality level') | |
}) | |
hls.attachMedia(video) | |
hls.loadSource(src) | |
// If you are using the ESM version of the library (hls.mjs), you | |
// should specify the "workerPath" config option here if you want | |
// web workers to be used. Note that bundlers (such as webpack) | |
// will likely use the ESM version by default.) | |
// MEDIA_ATTACHED event is fired by hls object once MediaSource is ready | |
hls.on(Hls.Events.MEDIA_ATTACHED, function () { | |
console.log('video and hls.js are now bound together !') | |
}) | |
} | |
} | |
const texture = suspend( | |
() => | |
new Promise((res, rej) => { | |
const video = Object.assign(document.createElement('video'), { | |
src: (typeof src === 'string' && src) || undefined, | |
srcObject: (src instanceof MediaStream && src) || undefined, | |
crossOrigin, | |
loop, | |
muted, | |
...rest | |
}) | |
videoRef.current = video | |
createHLSBinding() | |
const texture = new THREE.VideoTexture(video) | |
if ('colorSpace' in texture) texture.colorSpace = gl.outputColorSpace | |
else texture.encoding = gl.outputEncoding | |
// flip video | |
texture.wrapS = texture.wrapT = THREE.RepeatWrapping | |
texture.repeat.x = -1 | |
video.addEventListener(unsuspend, () => res(texture)) | |
}), | |
[src] | |
) | |
useEffect(() => { | |
start && texture.image.play() | |
}, [texture, start]) | |
return texture | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment