/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {RefObject, useEffect, useMemo, useRef} from 'react'; import VideoWorkerBridge from './VideoWorkerBridge'; type Options = { createVideoWorker?: () => Worker; createWorkerBridge?: CreateWorkerBridgeFunction; }; const DEFAULT_OPTIONS: Options = { createVideoWorker: () => new Worker(new URL('./VideoWorker', import.meta.url), { type: 'module', }), }; type WorkerFactory = () => Worker; type CreateWorkerBridgeFunction = ( workerFactory: WorkerFactory, ) => VideoWorkerBridge; export default function useVideoWorker( src: string, canvasRef: RefObject, options: Options = {}, ) { const isControlTransferredToOffscreenRef = useRef(false); const mergedOptions = useMemo(() => { const definedProps = (o: Options) => Object.fromEntries( Object.entries(o).filter(([_k, v]) => v !== undefined), ); return Object.assign( DEFAULT_OPTIONS, definedProps(options), ) as Required; }, [options]); const worker = useMemo(() => { if (mergedOptions.createWorkerBridge) { return mergedOptions.createWorkerBridge(mergedOptions.createVideoWorker); } return VideoWorkerBridge.create(mergedOptions.createVideoWorker); }, [mergedOptions]); useEffect(() => { const canvas = canvasRef.current; if (canvas == null) { return; } if (isControlTransferredToOffscreenRef.current) { return; } isControlTransferredToOffscreenRef.current = true; worker.setCanvas(canvas); return () => { // Cannot terminate worker in DEV mode // workerRef.current?.terminate(); }; }, [canvasRef, mergedOptions, worker]); useEffect(() => { worker.setSource(src); }, [src, worker]); return worker; }