Created
December 4, 2023 14:45
-
-
Save bcjordan/dfd2ff165b2c098f1064323be6f5339d to your computer and use it in GitHub Desktop.
recording mp4s from browser canvas (fast)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Muxer, ArrayBufferTarget} from 'mp4-muxer'; | |
const muxerAll = new Muxer({ | |
target: new ArrayBufferTarget(), | |
video: { | |
codec: 'avc', | |
width: 512, | |
height: 512 | |
}, | |
fastStart: 'in-memory' | |
}); | |
const videoEncoderAll = new VideoEncoder({ | |
output: (chunk, meta) => muxerAll.addVideoChunk(chunk, meta), | |
error: e => console.error(e) | |
}); | |
videoEncoderAll.configure({ | |
codec: 'avc1.42001f', | |
width: 512, | |
height: 512, | |
bitrate: 1e6 | |
}); | |
document.addEventListener('keydown', (event) => { | |
switch(event.key) { | |
case 'v': | |
downloadVideoForEncoderAndMuxer(muxerAll, videoEncoderAll); | |
break; | |
default: return; | |
} | |
event.preventDefault(); | |
}); | |
function downloadVideoForEncoderAndMuxer(muxer, videoEncoder) { | |
videoEncoder.flush().then(() => { | |
muxer.finalize(); | |
let { buffer } = muxer.target; // Buffer contains final MP4 file | |
let blob = new Blob([buffer], { type: 'video/mp4' }); | |
let url = URL.createObjectURL(blob); | |
let link = document.createElement('a'); | |
link.href = url; | |
// link.target = '_blank'; - if you want it to open in new window instead, uncomment this / comment next line | |
link.download = 'output.mp4'; | |
link.click(); | |
}); | |
// to handle multiple record/saves might have to make new encoder/muxer | |
} | |
function captureFrameFromCanvas(canvasDomElement) { | |
const videoFrame = new VideoFrame(canvasDomElement, { | |
timestamp: ((framecount++) * 1_000_000) / 10, // 10fps? Timesteps are maybe microseconds? lmao | |
codedWidth: 512, | |
codedHeight: 512, | |
}); | |
captureFrame(videoFrame); | |
} | |
const captureFrame = (frame) => { | |
const keyFrame = (frame.timestamp / 1_000_000) % 2 === 0; // I dunno what keyframes are used for? lmao | |
videoEncoderAll.encode(frame, { keyFrame }); | |
videoEncoderLatest.encode(frame, { keyFrame }); | |
frame.close(); | |
}; | |
// | |
// NOW CAPTURE FRAMES! | |
// | |
// Snag a frame after every render you wanna capture: | |
// captureFrameFromCanvas(myThreeJSRenderer.domElement) // or e.g. document.getElementById("my-canvas-element") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment