Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Sync from GitHub via hub-sync
Browse files
src/components/simple-videos-player.tsx
CHANGED
|
@@ -85,6 +85,25 @@ export const SimpleVideosPlayer = ({
|
|
| 85 |
|
| 86 |
const timeout = setTimeout(markReady, VIDEO_READY_TIMEOUT_MS);
|
| 87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
videoRefs.current.forEach((video, index) => {
|
| 89 |
if (!video) return;
|
| 90 |
const info = videosInfo[index];
|
|
@@ -100,9 +119,13 @@ export const SimpleVideosPlayer = ({
|
|
| 100 |
video.currentTime >=
|
| 101 |
segmentEnd - THRESHOLDS.VIDEO_SEGMENT_BOUNDARY
|
| 102 |
) {
|
| 103 |
-
|
|
|
|
|
|
|
| 104 |
if (index === firstVisibleIdxRef.current) {
|
| 105 |
-
|
|
|
|
|
|
|
| 106 |
}
|
| 107 |
return;
|
| 108 |
}
|
|
@@ -141,9 +164,13 @@ export const SimpleVideosPlayer = ({
|
|
| 141 |
const handleEnded = info.isSegmented
|
| 142 |
? null
|
| 143 |
: () => {
|
| 144 |
-
|
|
|
|
|
|
|
| 145 |
if (index === firstVisibleIdxRef.current) {
|
| 146 |
-
|
|
|
|
|
|
|
| 147 |
}
|
| 148 |
};
|
| 149 |
|
|
|
|
| 85 |
|
| 86 |
const timeout = setTimeout(markReady, VIDEO_READY_TIMEOUT_MS);
|
| 87 |
|
| 88 |
+
// Coordinated loop reset — when the primary video hits its segment end
|
| 89 |
+
// (or natural end), seek every camera to its own segmentStart in a
|
| 90 |
+
// single synchronous burst. The previous design seeked the primary,
|
| 91 |
+
// then bumped externalSeekVersion which scheduled the other seeks via
|
| 92 |
+
// a React render — leaving an 80ms (throttled) gap where the primary
|
| 93 |
+
// played fresh frames while the others still showed the segment-end
|
| 94 |
+
// frame. Now the gap is microseconds.
|
| 95 |
+
const loopAllVideos = () => {
|
| 96 |
+
videoRefs.current.forEach((other, otherIdx) => {
|
| 97 |
+
if (!other) return;
|
| 98 |
+
const otherInfo = videosInfo[otherIdx];
|
| 99 |
+
if (!otherInfo) return;
|
| 100 |
+
other.currentTime = otherInfo.segmentStart || 0;
|
| 101 |
+
});
|
| 102 |
+
// Update the slider as a status report — don't bump externalSeekVersion
|
| 103 |
+
// since we already drove every video to its target.
|
| 104 |
+
setCurrentTime(0, "video");
|
| 105 |
+
};
|
| 106 |
+
|
| 107 |
videoRefs.current.forEach((video, index) => {
|
| 108 |
if (!video) return;
|
| 109 |
const info = videosInfo[index];
|
|
|
|
| 119 |
video.currentTime >=
|
| 120 |
segmentEnd - THRESHOLDS.VIDEO_SEGMENT_BOUNDARY
|
| 121 |
) {
|
| 122 |
+
// Primary drives the coordinated loop. Non-primary cameras
|
| 123 |
+
// that race ahead just snap to segmentStart and wait — the
|
| 124 |
+
// primary's next loop will re-align everyone.
|
| 125 |
if (index === firstVisibleIdxRef.current) {
|
| 126 |
+
loopAllVideos();
|
| 127 |
+
} else {
|
| 128 |
+
video.currentTime = segmentStart;
|
| 129 |
}
|
| 130 |
return;
|
| 131 |
}
|
|
|
|
| 164 |
const handleEnded = info.isSegmented
|
| 165 |
? null
|
| 166 |
: () => {
|
| 167 |
+
// Same coordinated loop strategy for non-segmented videos at
|
| 168 |
+
// their natural end — primary drives, others wait for primary
|
| 169 |
+
// to align them.
|
| 170 |
if (index === firstVisibleIdxRef.current) {
|
| 171 |
+
loopAllVideos();
|
| 172 |
+
} else {
|
| 173 |
+
video.currentTime = 0;
|
| 174 |
}
|
| 175 |
};
|
| 176 |
|