Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(useVideoTexture): now accepting a src that is a MediaStream #1370

Merged
merged 1 commit into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .storybook/public/images/share-screen.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .storybook/public/images/sintel-cover.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 86 additions & 8 deletions .storybook/stories/useVideoTexture.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import * as React from 'react'
import { useState } from 'react'
import * as THREE from 'three'

import { Setup } from '../Setup'

import { Plane, useVideoTexture } from '../../src'
import { Plane, useVideoTexture, useTexture } from '../../src'

export default {
title: 'Loaders/VideoTexture',
title: 'Misc/useVideoTexture',
component: useVideoTexture,
decorators: [(storyFn) => <Setup>{storyFn()}</Setup>],
}

//
// simple
//

function VideoTexturedPlane() {
const videoTexture = useVideoTexture(
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4',
{}
)
const texture = useVideoTexture('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4')

return (
<>
<Plane>
<meshBasicMaterial side={THREE.DoubleSide} map={videoTexture} toneMapped={false} />
<Plane args={[4, 2.25]}>
<meshBasicMaterial side={THREE.DoubleSide} map={texture} toneMapped={false} />
</Plane>
</>
)
Expand All @@ -38,3 +40,79 @@ export const UseVideoTextureSceneSt = () => <UseVideoTextureScene />
UseVideoTextureSceneSt.story = {
name: 'Default',
}

//
// Suspense
//

function VideoTexturedPlane2() {
return (
<>
<Plane args={[4, 2.25]}>
<React.Suspense fallback={<FallbackMaterial url="images/sintel-cover.jpg" />}>
<VideoMaterial src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4" />
</React.Suspense>
</Plane>
</>
)
}

function VideoMaterial({ src }) {
const texture = useVideoTexture(src)
return <meshBasicMaterial side={THREE.DoubleSide} map={texture} toneMapped={false} />
}

function FallbackMaterial({ url }: { url: string }) {
const texture = useTexture(url)
return <meshBasicMaterial map={texture} toneMapped={false} />
}

function UseVideoTextureScene2() {
return (
<React.Suspense fallback={null}>
<VideoTexturedPlane2 />
</React.Suspense>
)
}

export const UseVideoTextureSceneSt2 = () => <UseVideoTextureScene2 />
UseVideoTextureSceneSt2.story = {
name: 'Suspense',
}

//
// getDisplayMedia (Screen Capture API)
//

function VideoTexturedPlane3() {
const [mediaStream, setMediaStream] = useState(new MediaStream())

return (
<>
<Plane
args={[4, 2.25]}
onClick={async (e) => {
const mediaStream = await navigator.mediaDevices.getDisplayMedia({ video: true })
setMediaStream(mediaStream)
}}
>
<React.Suspense fallback={<FallbackMaterial url="images/share-screen.jpg" />}>
<VideoMaterial src={mediaStream} />
</React.Suspense>
</Plane>
</>
)
}

function UseVideoTextureScene3() {
return (
<React.Suspense fallback={null}>
<VideoTexturedPlane3 />
</React.Suspense>
)
}

export const UseVideoTextureSceneSt3 = () => <UseVideoTextureScene3 />
UseVideoTextureSceneSt3.story = {
name: 'MediaStream',
abernier marked this conversation as resolved.
Show resolved Hide resolved
}
9 changes: 5 additions & 4 deletions src/core/useVideoTexture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface VideoTextureProps extends HTMLVideoElement {
start?: boolean
}

export function useVideoTexture(src: string, props: Partial<VideoTextureProps>) {
export function useVideoTexture(src: string | MediaStream, props?: Partial<VideoTextureProps>) {
const { unsuspend, start, crossOrigin, muted, loop, ...rest } = {
unsuspend: 'loadedmetadata',
crossOrigin: 'Anonymous',
Expand All @@ -19,11 +19,12 @@ export function useVideoTexture(src: string, props: Partial<VideoTextureProps>)
...props,
}
const gl = useThree((state) => state.gl)
const texture = suspend<[url: string], () => Promise<THREE.VideoTexture>>(
const texture = suspend(
() =>
new Promise((res, rej) => {
const video = Object.assign(document.createElement('video'), {
src,
src: (typeof src === 'string' && src) || undefined,
srcObject: (src instanceof MediaStream && src) || undefined,
abernier marked this conversation as resolved.
Show resolved Hide resolved
crossOrigin,
loop,
muted,
Expand All @@ -34,7 +35,7 @@ export function useVideoTexture(src: string, props: Partial<VideoTextureProps>)
video.addEventListener(unsuspend, () => res(texture))
}),
[src]
)
) as THREE.VideoTexture
useEffect(() => void (start && texture.image.play()), [texture, start])
return texture
}