diff --git a/next.config.js b/next.config.js index 34df58c0..44e4c7ed 100644 --- a/next.config.js +++ b/next.config.js @@ -8,6 +8,15 @@ module.exports = { basePath: BASE_PATH, compress: true, reactStrictMode: true, + async redirects() { + return [ + { + source: '/samples/videoUploadingWebCodecs', + destination: '/samples/videoUploading?videoSource=videoFrame', + permanent: true, + }, + ] + }, webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => { config.module.rules.push({ test: /\.(png|jpe?g|gif|webm)$/i, diff --git a/src/pages/samples/[slug].tsx b/src/pages/samples/[slug].tsx index 7a180e37..ab03cede 100644 --- a/src/pages/samples/[slug].tsx +++ b/src/pages/samples/[slug].tsx @@ -72,9 +72,6 @@ const gpuComputeDemoPages: PageComponentType = { const webPlatformPages: PageComponentType = { resizeCanvas: dynamic(() => import('../../sample/resizeCanvas/main')), videoUploading: dynamic(() => import('../../sample/videoUploading/main')), - videoUploadingWebCodecs: dynamic( - () => import('../../sample/videoUploadingWebCodecs/main') - ), worker: dynamic(() => import('../../sample/worker/main')), }; diff --git a/src/sample/videoUploading/main.ts b/src/sample/videoUploading/main.ts index 1cfa5d9c..1febff57 100644 --- a/src/sample/videoUploading/main.ts +++ b/src/sample/videoUploading/main.ts @@ -58,10 +58,14 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => { minFilter: 'linear', }); + const params = new URLSearchParams(window.location.search); + const settings = { requestFrame: 'requestAnimationFrame', + videoSource: params.get('videoSource') || 'videoElement', }; + gui.add(settings, 'videoSource', ['videoElement', 'videoFrame']); gui.add(settings, 'requestFrame', [ 'requestAnimationFrame', 'requestVideoFrameCallback', @@ -71,6 +75,9 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => { // Sample is no longer the active page. if (!pageState.active) return; + const externalTextureSource = + settings.videoSource === 'videoFrame' ? new VideoFrame(video) : video; + const uniformBindGroup = device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries: [ @@ -81,7 +88,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => { { binding: 2, resource: device.importExternalTexture({ - source: video, + source: externalTextureSource, }), }, ], diff --git a/src/sample/videoUploadingWebCodecs/main.ts b/src/sample/videoUploadingWebCodecs/main.ts deleted file mode 100644 index 3fe34500..00000000 --- a/src/sample/videoUploadingWebCodecs/main.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { makeSample, SampleInit } from '../../components/SampleLayout'; - -import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl'; -import sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl'; - -const init: SampleInit = async ({ canvas, pageState, gui }) => { - // Set video element - const video = document.createElement('video'); - video.loop = true; - video.autoplay = true; - video.muted = true; - video.src = '../assets/video/pano.webm'; - await video.play(); - - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - - if (!pageState.active) return; - - const context = canvas.getContext('webgpu') as GPUCanvasContext; - const devicePixelRatio = window.devicePixelRatio; - canvas.width = canvas.clientWidth * devicePixelRatio; - canvas.height = canvas.clientHeight * devicePixelRatio; - const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); - - context.configure({ - device, - format: presentationFormat, - alphaMode: 'premultiplied', - }); - - const pipeline = device.createRenderPipeline({ - layout: 'auto', - vertex: { - module: device.createShaderModule({ - code: fullscreenTexturedQuadWGSL, - }), - entryPoint: 'vert_main', - }, - fragment: { - module: device.createShaderModule({ - code: sampleExternalTextureWGSL, - }), - entryPoint: 'main', - targets: [ - { - format: presentationFormat, - }, - ], - }, - primitive: { - topology: 'triangle-list', - }, - }); - - const sampler = device.createSampler({ - magFilter: 'linear', - minFilter: 'linear', - }); - - const settings = { - requestFrame: 'requestAnimationFrame', - }; - - gui.add(settings, 'requestFrame', [ - 'requestAnimationFrame', - 'requestVideoFrameCallback', - ]); - - function frame() { - // Sample is no longer the active page. - if (!pageState.active) return; - - const videoFrame = new VideoFrame(video); - - const uniformBindGroup = device.createBindGroup({ - layout: pipeline.getBindGroupLayout(0), - entries: [ - { - binding: 1, - resource: sampler, - }, - { - binding: 2, - resource: device.importExternalTexture({ - source: videoFrame as any, // eslint-disable-line @typescript-eslint/no-explicit-any - }), - }, - ], - }); - - const commandEncoder = device.createCommandEncoder(); - const textureView = context.getCurrentTexture().createView(); - - const renderPassDescriptor: GPURenderPassDescriptor = { - colorAttachments: [ - { - view: textureView, - clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }, - loadOp: 'clear', - storeOp: 'store', - }, - ], - }; - - const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); - passEncoder.setPipeline(pipeline); - passEncoder.setBindGroup(0, uniformBindGroup); - passEncoder.draw(6); - passEncoder.end(); - device.queue.submit([commandEncoder.finish()]); - - if (settings.requestFrame == 'requestVideoFrameCallback') { - video.requestVideoFrameCallback(frame); - } else { - requestAnimationFrame(frame); - } - } - - if (settings.requestFrame == 'requestVideoFrameCallback') { - video.requestVideoFrameCallback(frame); - } else { - requestAnimationFrame(frame); - } -}; - -const VideoUploadingWebCodecs: () => JSX.Element = () => - makeSample({ - name: 'Video Uploading with WebCodecs', - description: `This example shows how to upload a WebCodecs VideoFrame to WebGPU.`, - gui: true, - init, - sources: [ - { - name: __filename.substring(__dirname.length + 1), - contents: __SOURCE__, - }, - { - name: '../../shaders/fullscreenTexturedQuad.wgsl', - contents: fullscreenTexturedQuadWGSL, - editable: true, - }, - { - name: '../../shaders/sampleExternalTexture.wgsl', - contents: sampleExternalTextureWGSL, - editable: true, - }, - ], - filename: __filename, - }); - -export default VideoUploadingWebCodecs;