import { VideoEncoder, VideoFrame } from 'node-webcodecs';
import { writeFileSync } from 'fs';
interface EncoderOptions {
width: number;
height: number;
fps: number;
duration: number; // seconds
}
async function encodeRedVideo(options: EncoderOptions): Promise<Buffer> {
const { width, height, fps, duration } = options;
const chunks: Buffer[] = [];
const encoder = new VideoEncoder({
output: (chunk) => {
const buffer = Buffer.alloc(chunk.byteLength);
chunk.copyTo(buffer);
chunks.push(buffer);
},
error: (err) => { throw err; }
});
encoder.configure({
codec: 'avc1.42E01E',
width,
height,
bitrate: width * height * fps * 0.1, // 0.1 bits per pixel
});
const rgbaBuffer = createColorFrame(width, height, [255, 0, 0, 255]);
const frameDuration = 1_000_000 / fps; // microseconds
const totalFrames = duration * fps;
for (let i = 0; i < totalFrames; i++) {
const frame = new VideoFrame(rgbaBuffer, {
format: 'RGBA',
codedWidth: width,
codedHeight: height,
timestamp: i * frameDuration,
});
encoder.encode(frame, { keyFrame: i % (fps * 2) === 0 }); // Keyframe every 2s
frame.close();
}
await encoder.flush();
encoder.close();
return Buffer.concat(chunks);
}
function createColorFrame(
width: number,
height: number,
rgba: [number, number, number, number]
): Buffer {
const buffer = Buffer.alloc(width * height * 4);
for (let i = 0; i < buffer.length; i += 4) {
buffer[i] = rgba[0];
buffer[i + 1] = rgba[1];
buffer[i + 2] = rgba[2];
buffer[i + 3] = rgba[3];
}
return buffer;
}
// Usage
encodeRedVideo({ width: 1920, height: 1080, fps: 30, duration: 5 })
.then(buffer => {
writeFileSync('output.h264', buffer);
console.log(`Encoded ${buffer.length} bytes`);
})
.catch(console.error);