├── README.md └── CanvasRecorder.js /README.md: -------------------------------------------------------------------------------- 1 | # CanvasRecorder.js 2 | [![HitCount](http://hits.dwyl.io/smusamashah/CanvasRecorder.svg)](http://hits.dwyl.io/smusamashah/CanvasRecorder) 3 | 4 | Record a canvas to webm video without effecting rendering performance. 5 | 6 | *NOTE: Only tested it with Chrome and should work fine with Firefox* 7 | 8 | Blog article: https://smusamashah.github.io/blog/2018/10/26/CanvasRecorder 9 | 10 | ## How to use 11 | 12 | Create a recorder 13 | 14 | ```javascript 15 | const canvas = document.getElementById('animation'); 16 | const recorder = new CanvasRecorder(canvas); 17 | ``` 18 | 19 | ```javascript 20 | // optional: bits per second for video quality, defaults to 2.5Mbps 21 | const recorder = new CanvasRecorder(canvas, 4500000); 22 | ``` 23 | 24 | Start recording 25 | ```javascript 26 | recorder.start(); 27 | ``` 28 | 29 | Stop recording 30 | ```javascript 31 | recorder.stop(); 32 | ``` 33 | 34 | Save/download recording 35 | ```javascript 36 | recorder.save(); 37 | 38 | // Save with given file name 39 | recorder.save('busy_motion.webm'); 40 | ``` 41 | 42 | ## How it works 43 | 44 | It is based on this [WebRTC sample](https://webrtc.github.io/samples/src/content/capture/canvas-record/). Captures [`MediaStream`](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API) from a canvas element and records it with [`MediaRecorder`](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder). 45 | -------------------------------------------------------------------------------- /CanvasRecorder.js: -------------------------------------------------------------------------------- 1 | // CanvasRecorder.js - smusamashah 2 | // To record canvas effitiently using MediaRecorder 3 | // https://webrtc.github.io/samples/src/content/capture/canvas-record/ 4 | 5 | function CanvasRecorder(canvas, video_bits_per_sec) { 6 | this.start = startRecording; 7 | this.stop = stopRecording; 8 | this.save = download; 9 | 10 | var recordedBlobs = []; 11 | var supportedType = null; 12 | var mediaRecorder = null; 13 | 14 | var stream = canvas.captureStream(); 15 | if (typeof stream == undefined || !stream) { 16 | return; 17 | } 18 | 19 | const video = document.createElement('video'); 20 | video.style.display = 'none'; 21 | 22 | function startRecording() { 23 | let types = [ 24 | "video/webm", 25 | 'video/webm,codecs=vp9', 26 | 'video/vp8', 27 | "video/webm\;codecs=vp8", 28 | "video/webm\;codecs=daala", 29 | "video/webm\;codecs=h264", 30 | "video/mpeg" 31 | ]; 32 | 33 | for (let i in types) { 34 | if (MediaRecorder.isTypeSupported(types[i])) { 35 | supportedType = types[i]; 36 | break; 37 | } 38 | } 39 | if (supportedType == null) { 40 | console.log("No supported type found for MediaRecorder"); 41 | } 42 | let options = { 43 | mimeType: supportedType, 44 | videoBitsPerSecond: video_bits_per_sec || 2500000 // 2.5Mbps 45 | }; 46 | 47 | recordedBlobs = []; 48 | try { 49 | mediaRecorder = new MediaRecorder(stream, options); 50 | } catch (e) { 51 | alert('MediaRecorder is not supported by this browser.'); 52 | console.error('Exception while creating MediaRecorder:', e); 53 | return; 54 | } 55 | 56 | console.log('Created MediaRecorder', mediaRecorder, 'with options', options); 57 | mediaRecorder.onstop = handleStop; 58 | mediaRecorder.ondataavailable = handleDataAvailable; 59 | mediaRecorder.start(100); // collect 100ms of data blobs 60 | console.log('MediaRecorder started', mediaRecorder); 61 | } 62 | 63 | function handleDataAvailable(event) { 64 | if (event.data && event.data.size > 0) { 65 | recordedBlobs.push(event.data); 66 | } 67 | } 68 | 69 | function handleStop(event) { 70 | console.log('Recorder stopped: ', event); 71 | const superBuffer = new Blob(recordedBlobs, { type: supportedType }); 72 | video.src = window.URL.createObjectURL(superBuffer); 73 | } 74 | 75 | function stopRecording() { 76 | mediaRecorder.stop(); 77 | console.log('Recorded Blobs: ', recordedBlobs); 78 | video.controls = true; 79 | } 80 | 81 | function download(file_name) { 82 | const name = file_name || 'recording.webm'; 83 | const blob = new Blob(recordedBlobs, { type: supportedType }); 84 | const url = window.URL.createObjectURL(blob); 85 | const a = document.createElement('a'); 86 | a.style.display = 'none'; 87 | a.href = url; 88 | a.download = name; 89 | document.body.appendChild(a); 90 | a.click(); 91 | setTimeout(() => { 92 | document.body.removeChild(a); 93 | window.URL.revokeObjectURL(url); 94 | }, 100); 95 | } 96 | } 97 | --------------------------------------------------------------------------------