Fix dashboard live rendering and rotated cover fitting

This commit is contained in:
ibs0d 2026-03-08 16:26:56 +11:00
parent 4721dd4ed0
commit 5aa80022ae

View File

@ -94,6 +94,7 @@ export default function LivePlayer({
const shouldRotateClockwise = applyDashboardTransforms && rotateClockwise; const shouldRotateClockwise = applyDashboardTransforms && rotateClockwise;
const mediaViewportRef = useRef<HTMLDivElement | null>(null); const mediaViewportRef = useRef<HTMLDivElement | null>(null);
const mediaContentRef = useRef<HTMLDivElement | null>(null);
const [{ width: viewportWidth, height: viewportHeight }] = const [{ width: viewportWidth, height: viewportHeight }] =
useResizeObserver(mediaViewportRef); useResizeObserver(mediaViewportRef);
@ -104,17 +105,54 @@ export default function LivePlayer({
transforms.push("rotate(90deg)"); transforms.push("rotate(90deg)");
} }
// For a 90° rotation, the media box must use swapped viewport dimensions if (!shouldRotateClockwise || !viewportWidth || !viewportHeight) {
// before rotating, otherwise the rotated content can under-fill one axis. return {
const rotatedWidth = viewportHeight ? `${viewportHeight}px` : "100%"; transform: transforms.join(" "),
const rotatedHeight = viewportWidth ? `${viewportWidth}px` : "100%"; width: "100%",
height: "100%",
};
}
const sourceWidth = cameraConfig.detect.width || 1;
const sourceHeight = cameraConfig.detect.height || 1;
const rotatedAspect = sourceHeight / sourceWidth;
const containerAspect = viewportWidth / viewportHeight;
let renderedWidth = viewportWidth;
let renderedHeight = viewportHeight;
if (shouldFillContainer) {
if (rotatedAspect > containerAspect) {
renderedHeight = viewportHeight;
renderedWidth = renderedHeight * rotatedAspect;
} else {
renderedWidth = viewportWidth;
renderedHeight = renderedWidth / rotatedAspect;
}
} else if (rotatedAspect > containerAspect) {
renderedWidth = viewportWidth;
renderedHeight = renderedWidth / rotatedAspect;
} else {
renderedHeight = viewportHeight;
renderedWidth = renderedHeight * rotatedAspect;
}
const rotatedWidth = `${Math.ceil(renderedHeight)}px`;
const rotatedHeight = `${Math.ceil(renderedWidth)}px`;
return { return {
transform: transforms.join(" "), transform: transforms.join(" "),
width: shouldRotateClockwise ? rotatedWidth : "100%", width: shouldRotateClockwise ? rotatedWidth : "100%",
height: shouldRotateClockwise ? rotatedHeight : "100%", height: shouldRotateClockwise ? rotatedHeight : "100%",
}; };
}, [shouldRotateClockwise, viewportHeight, viewportWidth]); }, [
cameraConfig.detect.height,
cameraConfig.detect.width,
shouldFillContainer,
shouldRotateClockwise,
viewportHeight,
viewportWidth,
]);
// stats // stats
const [stats, setStats] = useState<PlayerStatsType>({ const [stats, setStats] = useState<PlayerStatsType>({
@ -310,7 +348,7 @@ export default function LivePlayer({
className={cn( className={cn(
"size-full rounded-lg md:rounded-2xl", "size-full rounded-lg md:rounded-2xl",
shouldFillContainer && "object-cover", shouldFillContainer && "object-cover",
liveReady ? "" : "hidden", liveReady ? "opacity-100" : "opacity-0",
)} )}
camera={streamName} camera={streamName}
playbackEnabled={cameraActive || liveReady} playbackEnabled={cameraActive || liveReady}
@ -333,7 +371,7 @@ export default function LivePlayer({
className={cn( className={cn(
"size-full rounded-lg md:rounded-2xl", "size-full rounded-lg md:rounded-2xl",
shouldFillContainer && "object-cover", shouldFillContainer && "object-cover",
liveReady ? "" : "hidden", liveReady ? "opacity-100" : "opacity-0",
)} )}
camera={streamName} camera={streamName}
playbackEnabled={cameraActive || liveReady} playbackEnabled={cameraActive || liveReady}
@ -373,7 +411,11 @@ export default function LivePlayer({
} }
useWebGL={useWebGL} useWebGL={useWebGL}
setStats={setStats} setStats={setStats}
containerRef={containerRef ?? internalContainerRef} containerRef={
applyDashboardTransforms
? mediaContentRef
: (containerRef ?? internalContainerRef)
}
onPlaying={playerIsPlaying} onPlaying={playerIsPlaying}
fit={shouldFillContainer ? "cover" : "contain"} fit={shouldFillContainer ? "cover" : "contain"}
/> />
@ -421,6 +463,7 @@ export default function LivePlayer({
)} )}
> >
<div <div
ref={mediaContentRef}
className="absolute left-1/2 top-1/2" className="absolute left-1/2 top-1/2"
style={mediaTransformStyle} style={mediaTransformStyle}
> >