UNPKG

canvas-record

Version:

Record a video in the browser or directly on the File System from a canvas region (2D/WebGL/WebGPU) as MP4, WebM, MKV, MOV, GIF, PNG/JPG Sequence using WebCodecs and wasm when available.

83 lines (65 loc) 2.12 kB
import Encoder from "./Encoder.js"; import { Deferred } from "../utils.js"; /** * @typedef {object} MediaCaptureEncoderOptions * @property {number} [flushFrequency=10] * @property {MediaCaptureEncoderEncoderOptions} [encoderOptions={}] */ /** * @typedef {MediaRecorderOptions} MediaCaptureEncoderEncoderOptions * @see [MediaRecorder#options]{@link https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder#options} */ class MediaCaptureEncoder extends Encoder { static supportedExtensions = ["mkv", "webm"]; static defaultOptions = { extension: MediaCaptureEncoder.supportedExtensions[0], frameMethod: "requestFrame", flushFrequency: 10, }; /** * @param {MediaCaptureEncoderOptions} [options] */ constructor(options) { super({ ...MediaCaptureEncoder.defaultOptions, ...options }); } async init(options) { super.init(options); this.chunks = []; // Forces the use of requestFrame. Use canvas-record v3 for real-time capture. this.stream = this.canvas.captureStream(this.frameRate); this.recorder = new MediaRecorder(this.stream, { mimeType: this.mimeType, // "video/x-matroska;codecs=avc1", // audioBitsPerSecond: 128000, // 128 Kbit/sec // videoBitsPerSecond: 2500000, // 2.5 Mbit/sec ...this.encoderOptions, }); this.recorder.ondataavailable = (event) => { event.data.size && this.chunks.push(event.data); if (this.q) this.q.resolve(); }; } async encode(frame, number) { if (this.recorder.state !== "recording") { this.chunks = []; this.recorder.start(); } if (!this.frameRate !== 0) { (this.stream.getVideoTracks?.()?.[0] || this.stream).requestFrame(); } if (this.flushFrequency && (number + 1) % this.flushFrequency === 0) { this.recorder.requestData(); } } async stop() { this.q = new Deferred(); this.recorder.stop(); await this.q.promise; delete this.q; return this.chunks; } async dispose() { this.recorder = null; this.stream = null; } } export default MediaCaptureEncoder;