mirror of
https://github.com/DeNNiiInc/Web-Page-Performance-Test.git
synced 2026-04-17 20:05:58 +00:00
Fix video generation crash: patch Whammy.js logic and safeguard empty frames
This commit is contained in:
28
main.js
28
main.js
@@ -649,7 +649,12 @@ async function downloadVideo() {
|
||||
|
||||
// We will generate a frame for every 1/30th of a second
|
||||
const frameInterval = 1000 / fps; // ~33.33ms
|
||||
const totalOutputFrames = Math.ceil(totalDuration / frameInterval);
|
||||
let totalOutputFrames = Math.ceil(totalDuration / frameInterval);
|
||||
|
||||
// Ensure at least one frame if duration is 0 or very small
|
||||
if (totalOutputFrames <= 0) totalOutputFrames = 1;
|
||||
|
||||
console.log(`Generating ${totalOutputFrames} output frames`);
|
||||
|
||||
// Pre-load all images
|
||||
const loadedImages = await Promise.all(videoFrames.map(async frame => {
|
||||
@@ -664,6 +669,10 @@ async function downloadVideo() {
|
||||
|
||||
const validImages = loadedImages.filter(i => i !== null);
|
||||
|
||||
if (validImages.length === 0) {
|
||||
throw new Error("Failed to load any source images");
|
||||
}
|
||||
|
||||
// Generate video frames
|
||||
for (let i = 0; i < totalOutputFrames; i++) {
|
||||
const currentTime = i * frameInterval;
|
||||
@@ -685,14 +694,16 @@ async function downloadVideo() {
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Center and scale image (Contain)
|
||||
const scale = Math.min(canvas.width / currentImage.img.width, canvas.height / currentImage.img.height);
|
||||
const x = (canvas.width - currentImage.img.width * scale) / 2;
|
||||
const y = (canvas.height - currentImage.img.height * scale) / 2;
|
||||
if (currentImage && currentImage.img) {
|
||||
const scale = Math.min(canvas.width / currentImage.img.width, canvas.height / currentImage.img.height);
|
||||
const x = (canvas.width - currentImage.img.width * scale) / 2;
|
||||
const y = (canvas.height - currentImage.img.height * scale) / 2;
|
||||
|
||||
// Use high quality image smoothing
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
ctx.drawImage(currentImage.img, x, y, currentImage.img.width * scale, currentImage.img.height * scale);
|
||||
// Use high quality image smoothing
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
ctx.drawImage(currentImage.img, x, y, currentImage.img.width * scale, currentImage.img.height * scale);
|
||||
}
|
||||
|
||||
// Add timestamp overlay (crisp text)
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
|
||||
@@ -702,6 +713,7 @@ async function downloadVideo() {
|
||||
ctx.fillText(`${(currentTime / 1000).toFixed(1)}s`, 40, canvas.height - 35);
|
||||
|
||||
// Add frame to encoder
|
||||
// Note: add() might parse the webp immediately, so this must happen
|
||||
encoder.add(canvas);
|
||||
|
||||
// Yield to UI thread occasionally to prevent freezing
|
||||
|
||||
20
whammy.js
20
whammy.js
@@ -208,16 +208,24 @@
|
||||
var height = tmp & 0x3FFF;
|
||||
}
|
||||
|
||||
// now we want to put the VP8 chunk into the RIFF
|
||||
// we use valid RIFF structures: RIFF -> WEBP -> VP8
|
||||
// but we only care about the VP8 chunk
|
||||
// so we just throw it in there
|
||||
//riff.RIFF[0].WEBP.push(vp8); // this won't work because it's not a valid RIFF stucture
|
||||
// Fix: Assign dimensions to the frame object so checkFrames can access them
|
||||
if (typeof width !== 'undefined') {
|
||||
frames[i].width = width;
|
||||
frames[i].height = height;
|
||||
} else {
|
||||
// Copy from first frame if not the first iteration
|
||||
frames[i].width = frames[0].width;
|
||||
frames[i].height = frames[0].height;
|
||||
}
|
||||
|
||||
// we need to keep track of the duration of each frame
|
||||
frames[i].data = vp8;
|
||||
}
|
||||
|
||||
// Safety check for empty frames
|
||||
if (!frames || frames.length === 0) {
|
||||
throw "No frames to compile";
|
||||
}
|
||||
|
||||
var info = checkFrames(frames);
|
||||
|
||||
var CLUSTER_MAX_DURATION = 30000;
|
||||
|
||||
Reference in New Issue
Block a user