mirror of
https://github.com/siddharthvaddem/openscreen.git
synced 2026-08-30 17:06:13 +08:00
Merge pull request #491 from AmitwalaH/feature/video-playback-fix
Fix video playback initialization and zoom sync
This commit is contained in:
@@ -184,6 +184,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
const [overlaySize, setOverlaySize] = useState({ width: 800, height: 600 });
|
||||
const [overlayElement, setOverlayElement] = useState<HTMLDivElement | null>(null);
|
||||
const overlayRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const focusIndicatorRef = useRef<HTMLDivElement | null>(null);
|
||||
const [webcamLayout, setWebcamLayout] = useState<StyledRenderRect | null>(null);
|
||||
const [webcamDimensions, setWebcamDimensions] = useState<Size | null>(null);
|
||||
@@ -368,7 +369,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
if (!vid) return;
|
||||
try {
|
||||
allowPlaybackRef.current = true;
|
||||
await vid.play();
|
||||
await vid.play().catch((err) => {
|
||||
console.log("PLAY ERROR:", err);
|
||||
throw err;
|
||||
});
|
||||
} catch (error) {
|
||||
allowPlaybackRef.current = false;
|
||||
throw error;
|
||||
@@ -541,84 +545,24 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
|
||||
useEffect(() => {
|
||||
if (!pixiReady || !videoReady) return;
|
||||
const el = overlayRef.current;
|
||||
if (!el) return;
|
||||
|
||||
const app = appRef.current;
|
||||
const cameraContainer = cameraContainerRef.current;
|
||||
const video = videoRef.current;
|
||||
// Seed immediately so overlays never start at 800×600
|
||||
setOverlaySize({ width: el.clientWidth, height: el.clientHeight });
|
||||
|
||||
if (!app || !cameraContainer || !video) return;
|
||||
|
||||
const tickerWasStarted = app.ticker?.started || false;
|
||||
if (tickerWasStarted && app.ticker) {
|
||||
app.ticker.stop();
|
||||
}
|
||||
|
||||
const wasPlaying = !video.paused;
|
||||
if (wasPlaying) {
|
||||
video.pause();
|
||||
}
|
||||
|
||||
animationStateRef.current = {
|
||||
scale: 1,
|
||||
focusX: DEFAULT_FOCUS.cx,
|
||||
focusY: DEFAULT_FOCUS.cy,
|
||||
progress: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
appliedScale: 1,
|
||||
};
|
||||
|
||||
// Reset motion blur state for clean transitions
|
||||
motionBlurStateRef.current = createMotionBlurState();
|
||||
|
||||
if (blurFilterRef.current) {
|
||||
blurFilterRef.current.blur = 0;
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const container = cameraContainerRef.current;
|
||||
const videoStage = videoContainerRef.current;
|
||||
const sprite = videoSpriteRef.current;
|
||||
const currentApp = appRef.current;
|
||||
if (!container || !videoStage || !sprite || !currentApp) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.scale.set(1);
|
||||
container.position.set(0, 0);
|
||||
videoStage.scale.set(1);
|
||||
videoStage.position.set(0, 0);
|
||||
sprite.scale.set(1);
|
||||
sprite.position.set(0, 0);
|
||||
|
||||
layoutVideoContent();
|
||||
|
||||
applyZoomTransform({
|
||||
cameraContainer: container,
|
||||
blurFilter: blurFilterRef.current,
|
||||
stageSize: stageSizeRef.current,
|
||||
baseMask: baseMaskRef.current,
|
||||
zoomScale: 1,
|
||||
focusX: DEFAULT_FOCUS.cx,
|
||||
focusY: DEFAULT_FOCUS.cy,
|
||||
motionIntensity: 0,
|
||||
isPlaying: false,
|
||||
motionBlurAmount: motionBlurAmountRef.current,
|
||||
});
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const finalApp = appRef.current;
|
||||
if (wasPlaying && video) {
|
||||
video.play().catch(() => {
|
||||
// Ignore autoplay restoration failures.
|
||||
});
|
||||
}
|
||||
if (tickerWasStarted && finalApp?.ticker) {
|
||||
finalApp.ticker.start();
|
||||
}
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
if (!entries[0]) return;
|
||||
const { width, height } = entries[0].contentRect;
|
||||
setOverlaySize((prev) => {
|
||||
if (prev.width === width && prev.height === height) return prev;
|
||||
return { width, height };
|
||||
});
|
||||
});
|
||||
}, [pixiReady, videoReady, layoutVideoContent]);
|
||||
|
||||
observer.observe(el);
|
||||
return () => observer.disconnect();
|
||||
}, [pixiReady, videoReady]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pixiReady || !videoReady) return;
|
||||
@@ -1287,7 +1231,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
<div
|
||||
ref={setOverlayRefs}
|
||||
className="absolute inset-0 select-none"
|
||||
style={{ pointerEvents: "none", zIndex: 30 }}
|
||||
style={{ pointerEvents: "auto", zIndex: 30 }}
|
||||
onPointerDown={handleOverlayPointerDown}
|
||||
onPointerMove={handleOverlayPointerMove}
|
||||
onPointerUp={handleOverlayPointerUp}
|
||||
|
||||
@@ -394,8 +394,8 @@ export class FrameRenderer {
|
||||
this.compositeCtx
|
||||
) {
|
||||
// Calculate scale factor based on export vs preview dimensions
|
||||
const previewWidth = this.config.previewWidth || 1920;
|
||||
const previewHeight = this.config.previewHeight || 1080;
|
||||
const previewWidth = this.config.previewWidth ?? this.config.width;
|
||||
const previewHeight = this.config.previewHeight ?? this.config.height;
|
||||
const scaleX = this.config.width / previewWidth;
|
||||
const scaleY = this.config.height / previewHeight;
|
||||
const scaleFactor = (scaleX + scaleY) / 2;
|
||||
@@ -480,8 +480,8 @@ export class FrameRenderer {
|
||||
this.videoContainer.y = screenRect.y;
|
||||
|
||||
// scale border radius by export/preview canvas ratio
|
||||
const previewWidth = this.config.previewWidth || 1920;
|
||||
const previewHeight = this.config.previewHeight || 1080;
|
||||
const previewWidth = this.config.previewWidth ?? this.config.width;
|
||||
const previewHeight = this.config.previewHeight ?? this.config.height;
|
||||
const canvasScaleFactor = Math.min(width / previewWidth, height / previewHeight);
|
||||
const scaledBorderRadius =
|
||||
compositeLayout.screenBorderRadius != null
|
||||
|
||||
Reference in New Issue
Block a user