1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const canvas = new OffscreenCanvas(width, height)
const ctx = canvas.getContext('2d')!
const muxer = new Muxer({ target: new ArrayBufferTarget(), video: { codec: 'avc', width, height }, fastStart: 'in-memory' })
const encoder = new VideoEncoder({
output: (chunk, meta) => muxer.addVideoChunk(chunk, meta),
error: e => postMessage({ type: 'error', message: e.message }),
})
encoder.configure({ codec: 'avc1.640028', width, height, bitrate: 6_000_000, framerate: fps, hardwareAcceleration: 'prefer-hardware' })
for (let i = 0; i < totalFrames; i++) {
drawTimeline(ctx, timeline, i / fps)
const frame = new VideoFrame(canvas, { timestamp: Math.round((i * 1e6) / fps) })
encoder.encode(frame, { keyFrame: i % (fps * 2) === 0 })
frame.close()
while (encoder.encodeQueueSize > 8) await new Promise(r => setTimeout(r, 0))
if (i % fps === 0) postMessage({ type: 'progress', value: i / totalFrames })
}
await encoder.flush()
muxer.finalize()
const { buffer } = muxer.target
postMessage({ type: 'done', buffer }, [buffer])