138 lines
4.8 KiB
JavaScript
138 lines
4.8 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
async function testPipeline() {
|
|
console.log('🧪 Starting End-to-End Test for ProRes 4444 & WebM Alpha Streaming Pipeline...');
|
|
|
|
// 1. Check audio sample file
|
|
const sampleAudioPath = 'd:/Google Drive/Videos/AIWentNonsense/022 - Swing Low - Sweet Cadence/AUDIO/Master_WAV.wav';
|
|
let audioBuffer;
|
|
if (fs.existsSync(sampleAudioPath)) {
|
|
console.log(`Found master audio: ${sampleAudioPath}`);
|
|
audioBuffer = fs.readFileSync(sampleAudioPath);
|
|
} else {
|
|
console.log('Creating synthetic dummy WAV for test...');
|
|
// Create simple 44.1kHz 1s WAV
|
|
audioBuffer = Buffer.alloc(44 + 44100 * 4);
|
|
audioBuffer.write('RIFF', 0);
|
|
audioBuffer.writeUInt32LE(36 + 44100 * 4, 4);
|
|
audioBuffer.write('WAVE', 8);
|
|
audioBuffer.write('fmt ', 12);
|
|
audioBuffer.writeUInt32LE(16, 16);
|
|
audioBuffer.writeUInt16LE(1, 20); // PCM
|
|
audioBuffer.writeUInt16LE(2, 22); // stereo
|
|
audioBuffer.writeUInt32LE(44100, 24);
|
|
audioBuffer.writeUInt32LE(44100 * 4, 28);
|
|
audioBuffer.writeUInt16LE(4, 32);
|
|
audioBuffer.writeUInt16LE(16, 34);
|
|
audioBuffer.write('data', 36);
|
|
audioBuffer.writeUInt32LE(44100 * 4, 40);
|
|
}
|
|
|
|
const formatsToTest = ['prores', 'qtrle', 'webm_alpha', 'mp4'];
|
|
const width = 640;
|
|
const height = 360;
|
|
const fps = 30;
|
|
const testFrameCount = 30; // 1 second
|
|
|
|
for (const fmt of formatsToTest) {
|
|
console.log(`\n▶️ Testing format: ${fmt}...`);
|
|
const formData = new FormData();
|
|
const blob = new Blob([audioBuffer], { type: 'audio/wav' });
|
|
formData.append('audio', blob, 'test_audio.wav');
|
|
formData.append('format', fmt);
|
|
formData.append('width', width.toString());
|
|
formData.append('height', height.toString());
|
|
formData.append('fps', fps.toString());
|
|
formData.append('title', `Test_${fmt}`);
|
|
|
|
const startRes = await fetch('http://localhost:3000/api/export/start', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
if (!startRes.ok) {
|
|
const err = await startRes.text();
|
|
throw new Error(`Start failed for ${fmt}: ${err}`);
|
|
}
|
|
|
|
const { sessionId, outputFilename } = await startRes.json();
|
|
console.log(`Session initialized: ${sessionId} -> ${outputFilename}`);
|
|
|
|
// Stream 30 frames
|
|
const frameByteSize = width * height * 4;
|
|
const dummyFrame = new Uint8Array(frameByteSize);
|
|
|
|
// Fill with a vibrant glowing circle with transparent alpha background
|
|
const cx = width / 2;
|
|
const cy = height / 2;
|
|
const r = 80;
|
|
|
|
for (let y = 0; y < height; y++) {
|
|
for (let x = 0; x < width; x++) {
|
|
const idx = (y * width + x) * 4;
|
|
const d = Math.hypot(x - cx, y - cy);
|
|
if (d < r) {
|
|
dummyFrame[idx] = 0; // R
|
|
dummyFrame[idx + 1] = 240; // G
|
|
dummyFrame[idx + 2] = 255; // B
|
|
dummyFrame[idx + 3] = 255; // A (100% opaque)
|
|
} else if (d < r + 20) {
|
|
const alphaFactor = (1 - (d - r) / 20);
|
|
dummyFrame[idx] = 255; // R
|
|
dummyFrame[idx + 1] = 0; // G
|
|
dummyFrame[idx + 2] = 128; // B
|
|
dummyFrame[idx + 3] = Math.round(alphaFactor * 200); // Gradual Alpha
|
|
} else {
|
|
dummyFrame[idx + 3] = 0; // Fully transparent!
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < testFrameCount; i++) {
|
|
const frameRes = await fetch(`http://localhost:3000/api/export/frame/${sessionId}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/octet-stream' },
|
|
body: dummyFrame
|
|
});
|
|
if (!frameRes.ok) {
|
|
throw new Error(`Frame ${i} failed for ${fmt}`);
|
|
}
|
|
}
|
|
console.log(`Streamed ${testFrameCount} frames successfully.`);
|
|
|
|
const finishRes = await fetch(`http://localhost:3000/api/export/finish/${sessionId}`, {
|
|
method: 'POST'
|
|
});
|
|
|
|
if (!finishRes.ok) {
|
|
throw new Error(`Finish failed for ${fmt}: ${await finishRes.text()}`);
|
|
}
|
|
|
|
let finishData = null;
|
|
while (!finishData) {
|
|
await new Promise(r => setTimeout(r, 200));
|
|
const statusRes = await fetch(`http://localhost:3000/api/export/status/${sessionId}`);
|
|
if (!statusRes.ok) {
|
|
throw new Error(`Status check failed for ${fmt}: ${await statusRes.text()}`);
|
|
}
|
|
const statusJson = await statusRes.json();
|
|
if (statusJson.status === 'ready') {
|
|
finishData = statusJson;
|
|
break;
|
|
} else if (statusJson.status === 'error') {
|
|
throw new Error(`Status error for ${fmt}: ${statusJson.error}`);
|
|
}
|
|
}
|
|
|
|
console.log(`✅ Success for ${fmt}: Ready at ${finishData.downloadUrl} (${(finishData.sizeBytes / 1024).toFixed(1)} KB)`);
|
|
}
|
|
|
|
console.log('\n🎉 ALL EXPORT FORMATS (PRORES 4444, WEBM ALPHA, MP4) PASSED END-TO-END VALIDATION!');
|
|
}
|
|
|
|
testPipeline().catch(err => {
|
|
console.error('❌ Pipeline Test Error:', err);
|
|
process.exit(1);
|
|
});
|