Skip to content

Instantly share code, notes, and snippets.

@bcjordan
Created December 4, 2023 14:45
Show Gist options
  • Save bcjordan/dfd2ff165b2c098f1064323be6f5339d to your computer and use it in GitHub Desktop.
Save bcjordan/dfd2ff165b2c098f1064323be6f5339d to your computer and use it in GitHub Desktop.
recording mp4s from browser canvas (fast)
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