Jonna Marie Matthiesen commited on
Commit
234ef1f
Β·
1 Parent(s): 4db51d5

Fix video loading time, prebuffer vids

Browse files
Files changed (1) hide show
  1. demo/demo.js +34 -49
demo/demo.js CHANGED
@@ -208,21 +208,22 @@ async function renderDemo(data, container, optimizedOrg, dataFile, modelColors)
208
  const videoWrap = document.createElement("div");
209
  videoWrap.className = "demo-video-wrap";
210
 
211
- function makeVideoEl() {
 
 
212
  const v = document.createElement("video");
213
  v.loop = true;
214
  v.muted = true;
215
  v.playsInline = true;
216
  v.preload = "auto";
217
  v.className = "demo-video";
 
 
 
218
  return v;
219
- }
220
 
221
- let videoA = makeVideoEl();
222
- let videoB = makeVideoEl();
223
- videoB.style.opacity = "0";
224
- videoWrap.appendChild(videoA);
225
- videoWrap.appendChild(videoB);
226
 
227
  const arrowLeft = document.createElement("button");
228
  arrowLeft.className = "demo-arrow demo-arrow-left";
@@ -238,8 +239,6 @@ async function renderDemo(data, container, optimizedOrg, dataFile, modelColors)
238
  videoWrap.appendChild(arrowRight);
239
  card.appendChild(videoWrap);
240
 
241
- let isFirstClip = true;
242
-
243
  // Device selector (centered under video)
244
  card.appendChild(deviceSelector);
245
 
@@ -348,51 +347,36 @@ async function renderDemo(data, container, optimizedOrg, dataFile, modelColors)
348
  clipSetup.textContent = clip.inference_setup || "";
349
  clipSetup.style.display = clip.inference_setup ? "" : "none";
350
 
351
- // Video β€” crossfade: keep old visible, load new behind, fade when frame ready
352
- if (clip.video) {
 
353
  videoWrap.style.display = "";
354
- if (isFirstClip) {
355
- // First clip: just load directly into videoA
356
- videoA.src = clip.video;
357
- videoA.style.opacity = "1";
358
- videoA.load();
359
- videoA.addEventListener("loadeddata", () => videoA.play(), { once: true });
360
- isFirstClip = false;
 
 
 
 
 
 
 
 
 
361
  } else {
362
- // Crossfade: videoA is the old (visible), videoB gets the new source
363
- videoB.src = clip.video;
364
- videoB.style.opacity = "0";
365
- videoB.load();
366
-
367
- videoB.addEventListener("loadeddata", function onLoaded() {
368
- videoB.removeEventListener("loadeddata", onLoaded);
369
- videoB.play();
370
-
371
- // Wait for actual frame render before fading
372
- const startFade = () => {
373
- videoB.style.opacity = "1";
374
- videoA.style.opacity = "0";
375
- // After transition, pause old and swap roles
376
- setTimeout(() => {
377
- videoA.pause();
378
- videoA.removeAttribute("src");
379
- videoA.load();
380
- // Swap roles
381
- const tmp = videoA;
382
- videoA = videoB;
383
- videoB = tmp;
384
- }, 300);
385
- };
386
-
387
- if (videoB.requestVideoFrameCallback) {
388
- videoB.requestVideoFrameCallback(startFade);
389
- } else {
390
- startFade();
391
- }
392
- });
393
  }
394
  } else {
395
  videoWrap.style.display = "none";
 
 
 
 
 
396
  }
397
 
398
  // Prompt
@@ -422,6 +406,7 @@ async function renderDemo(data, container, optimizedOrg, dataFile, modelColors)
422
  renderOutputs();
423
 
424
  updateArrows();
 
425
  }
426
 
427
  // ── Toggle open/close ───────────────────────────────────────────────
 
208
  const videoWrap = document.createElement("div");
209
  videoWrap.className = "demo-video-wrap";
210
 
211
+ // Pre-create and buffer a <video> element for every clip
212
+ const clipVideos = clips.map(clip => {
213
+ if (!clip.video) return null;
214
  const v = document.createElement("video");
215
  v.loop = true;
216
  v.muted = true;
217
  v.playsInline = true;
218
  v.preload = "auto";
219
  v.className = "demo-video";
220
+ v.style.opacity = "0";
221
+ v.src = clip.video;
222
+ videoWrap.appendChild(v);
223
  return v;
224
+ });
225
 
226
+ let activeVideoIdx = -1;
 
 
 
 
227
 
228
  const arrowLeft = document.createElement("button");
229
  arrowLeft.className = "demo-arrow demo-arrow-left";
 
239
  videoWrap.appendChild(arrowRight);
240
  card.appendChild(videoWrap);
241
 
 
 
242
  // Device selector (centered under video)
243
  card.appendChild(deviceSelector);
244
 
 
347
  clipSetup.textContent = clip.inference_setup || "";
348
  clipSetup.style.display = clip.inference_setup ? "" : "none";
349
 
350
+ // Video β€” switch between pre-buffered video elements
351
+ const newVideo = clipVideos[currentClipIdx];
352
+ if (newVideo) {
353
  videoWrap.style.display = "";
354
+ const oldVideo = activeVideoIdx >= 0 ? clipVideos[activeVideoIdx] : null;
355
+
356
+ const showNew = () => {
357
+ newVideo.style.opacity = "1";
358
+ newVideo.play();
359
+ if (oldVideo && oldVideo !== newVideo) {
360
+ oldVideo.style.opacity = "0";
361
+ oldVideo.pause();
362
+ oldVideo.currentTime = 0;
363
+ }
364
+ activeVideoIdx = currentClipIdx;
365
+ };
366
+
367
+ // If enough data is buffered, show immediately; otherwise wait
368
+ if (newVideo.readyState >= 3) {
369
+ showNew();
370
  } else {
371
+ newVideo.addEventListener("canplay", showNew, { once: true });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  }
373
  } else {
374
  videoWrap.style.display = "none";
375
+ if (activeVideoIdx >= 0 && clipVideos[activeVideoIdx]) {
376
+ clipVideos[activeVideoIdx].style.opacity = "0";
377
+ clipVideos[activeVideoIdx].pause();
378
+ }
379
+ activeVideoIdx = -1;
380
  }
381
 
382
  // Prompt
 
406
  renderOutputs();
407
 
408
  updateArrows();
409
+
410
  }
411
 
412
  // ── Toggle open/close ───────────────────────────────────────────────