|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import {EnableStatsRequest} from '@/common/components/video/VideoWorkerTypes'; |
|
|
import stylex from '@stylexjs/stylex'; |
|
|
import {useEffect, useMemo, useRef, useState} from 'react'; |
|
|
import {useLocation} from 'react-router-dom'; |
|
|
import useVideo from '../../common/components/video/editor/useVideo'; |
|
|
import { |
|
|
GetMemoryStatsRequest, |
|
|
GetStatsCanvasRequest, |
|
|
MemoryStatsResponse, |
|
|
SetStatsCanvasResponse, |
|
|
} from './Stats'; |
|
|
|
|
|
const styles = stylex.create({ |
|
|
container: { |
|
|
position: 'fixed', |
|
|
top: 0, |
|
|
left: 0, |
|
|
width: '100%', |
|
|
overflowX: 'auto', |
|
|
display: 'flex', |
|
|
flexDirection: 'row', |
|
|
cursor: 'pointer', |
|
|
opacity: 0.9, |
|
|
zIndex: 10000, |
|
|
}, |
|
|
}); |
|
|
|
|
|
const URL_PARAM = 'monitors'; |
|
|
|
|
|
export default function StatsView() { |
|
|
const {search} = useLocation(); |
|
|
const video = useVideo(); |
|
|
const containerRef = useRef<HTMLDivElement | null>(null); |
|
|
const [isWrapped, setIsWrapped] = useState<boolean>(false); |
|
|
|
|
|
const isEnabled = useMemo(() => { |
|
|
const urlSearchParams = new URLSearchParams(search); |
|
|
return ( |
|
|
urlSearchParams.has(URL_PARAM) && |
|
|
['true', ''].includes(urlSearchParams.get('monitors') ?? '') |
|
|
); |
|
|
}, [search]); |
|
|
|
|
|
useEffect(() => { |
|
|
if (!isEnabled) { |
|
|
return; |
|
|
} |
|
|
|
|
|
const worker = video?.getWorker_ONLY_USE_WITH_CAUTION(); |
|
|
|
|
|
|
|
|
worker?.postMessage({ |
|
|
action: 'enableStats', |
|
|
} as EnableStatsRequest); |
|
|
|
|
|
function onMessage( |
|
|
event: MessageEvent<GetStatsCanvasRequest | GetMemoryStatsRequest>, |
|
|
) { |
|
|
if (event.data.action === 'getStatsCanvas') { |
|
|
|
|
|
const canvas = document.createElement('canvas'); |
|
|
canvas.width = event.data.width * window.devicePixelRatio; |
|
|
canvas.height = event.data.height * window.devicePixelRatio; |
|
|
canvas.style.width = `${event.data.width}px`; |
|
|
canvas.style.height = `${event.data.height}px`; |
|
|
containerRef.current?.appendChild(canvas); |
|
|
|
|
|
const offscreenCanvas = canvas.transferControlToOffscreen(); |
|
|
worker?.postMessage( |
|
|
{ |
|
|
action: 'setStatsCanvas', |
|
|
id: event.data.id, |
|
|
canvas: offscreenCanvas, |
|
|
devicePixelRatio: window.devicePixelRatio, |
|
|
} as SetStatsCanvasResponse, |
|
|
{ |
|
|
transfer: [offscreenCanvas], |
|
|
}, |
|
|
); |
|
|
} else if (event.data.action === 'getMemoryStats') { |
|
|
|
|
|
const memory = performance.memory ?? { |
|
|
jsHeapSizeLimit: 0, |
|
|
totalJSHeapSize: 0, |
|
|
usedJSHeapSize: 0, |
|
|
}; |
|
|
worker?.postMessage({ |
|
|
action: 'memoryStats', |
|
|
id: event.data.id, |
|
|
jsHeapSizeLimit: memory.jsHeapSizeLimit, |
|
|
totalJSHeapSize: memory.totalJSHeapSize, |
|
|
usedJSHeapSize: memory.usedJSHeapSize, |
|
|
} as MemoryStatsResponse); |
|
|
} |
|
|
} |
|
|
|
|
|
worker?.addEventListener('message', onMessage); |
|
|
return () => { |
|
|
worker?.removeEventListener('message', onMessage); |
|
|
}; |
|
|
}, [video, isEnabled]); |
|
|
|
|
|
function handleClick() { |
|
|
setIsWrapped(w => !w); |
|
|
} |
|
|
|
|
|
if (!isEnabled) { |
|
|
return null; |
|
|
} |
|
|
|
|
|
return ( |
|
|
<div |
|
|
ref={containerRef} |
|
|
{...stylex.props(styles.container)} |
|
|
style={{flexWrap: isWrapped ? 'wrap' : 'unset'}} |
|
|
onDoubleClick={handleClick} |
|
|
/> |
|
|
); |
|
|
} |
|
|
|