Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions frontend/src/hooks/useVideoSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,48 @@ export function useVideoSource(props?: UseVideoSourceProps) {
video
.play()
.then(() => {
// Draw video frame to canvas at original resolution
const drawFrame = () => {
// Use captureStream(0) for manual frame capture to avoid
// GPU stalls from automatic ReadPixels at mismatched rates.
// See: https://github.com/daydreamlive/scope/issues/509
const stream = canvas.captureStream(0);
const videoTrack = stream.getVideoTracks()[0];

// Draw video frames to canvas at the target FPS rate only,
// then manually request a frame capture. This avoids the
// "GPU stall due to ReadPixels" warning caused by drawing
// at ~60fps via requestAnimationFrame while capturing at a
// lower rate.
const intervalMs = 1000 / fps;
const intervalId = setInterval(() => {
if (video.paused || video.ended) {
clearInterval(intervalId);
return;
}
ctx.drawImage(
video,
0,
0,
detectedResolution.width,
detectedResolution.height
);
if (!video.paused && !video.ended) {
requestAnimationFrame(drawFrame);
// Manually request frame capture from the stream
if (
videoTrack &&
"requestFrame" in videoTrack &&
videoTrack.readyState === "live"
) {
(
videoTrack as MediaStreamTrack & {
requestFrame: () => void;
}
).requestFrame();
}
};
drawFrame();
}, intervalMs);

// Capture stream from canvas at original resolution
const stream = canvas.captureStream(fps);
// Clean up interval when track ends
videoTrack?.addEventListener("ended", () => {
clearInterval(intervalId);
});

resolve({ stream, resolution: detectedResolution });
})
Expand Down
4 changes: 3 additions & 1 deletion src/scope/core/plugins/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,10 @@ def _list_plugins_sync(self) -> list[dict[str, Any]]:
)

# For git packages, use the git URL; for PyPI, use package name
# Strip .git suffix - not needed for pip/uv and causes issues
# when web platform parses the URL for GitHub API calls (#508)
package_spec = (
f"git+{git_url}"
f"git+{git_url.removesuffix('.git')}"
if source == "git" and git_url
else package_name
)
Expand Down
Loading