UNPKG

@vikasietum_tecknology/record-rtc

Version:

record-rtc is a library based on recordrtc library. In this forked version of the original library we have optimized the memory management. The video recording is stored in IndexDB in chunks.

345 lines (288 loc) 10.2 kB
// _________________ // CanvasRecorder.js /** * CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}. * @summary HTML2Canvas recording into video WebM. * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} * @author {@link https://MuazKhan.com|Muaz Khan} * @typedef CanvasRecorder * @class * @example * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true }); * recorder.record(); * recorder.stop(function(blob) { * video.src = URL.createObjectURL(blob); * }); * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} * @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc. * @param {object} config - {disableLogs:true, initCallback: function} */ function CanvasRecorder(htmlElement, config) { if (typeof html2canvas === "undefined") { throw "Please link: https://www.webrtc-experiment.com/screenshot.js"; } config = config || {}; if (!config.frameInterval) { config.frameInterval = 10; } // via DetectRTC.js var isCanvasSupportsStreamCapturing = false; ["captureStream", "mozCaptureStream", "webkitCaptureStream"].forEach( function(item) { if (item in document.createElement("canvas")) { isCanvasSupportsStreamCapturing = true; } } ); var _isChrome = (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) && !!window.chrome; var chromeVersion = 50; var matchArray = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); if (_isChrome && matchArray && matchArray[2]) { chromeVersion = parseInt(matchArray[2], 10); } if (_isChrome && chromeVersion < 52) { isCanvasSupportsStreamCapturing = false; } if (config.useWhammyRecorder) { isCanvasSupportsStreamCapturing = false; } var globalCanvas, mediaStreamRecorder; if (isCanvasSupportsStreamCapturing) { if (!config.disableLogs) { console.log( "Your browser supports both MediRecorder API and canvas.captureStream!" ); } if (htmlElement instanceof HTMLCanvasElement) { globalCanvas = htmlElement; } else if (htmlElement instanceof CanvasRenderingContext2D) { globalCanvas = htmlElement.canvas; } else { throw "Please pass either HTMLCanvasElement or CanvasRenderingContext2D."; } } else if (!!navigator.mozGetUserMedia) { if (!config.disableLogs) { console.error("Canvas recording is NOT supported in Firefox."); } } var isRecording; /** * This method records Canvas. * @method * @memberof CanvasRecorder * @example * recorder.record(); */ this.record = function() { isRecording = true; if (isCanvasSupportsStreamCapturing && !config.useWhammyRecorder) { // CanvasCaptureMediaStream var canvasMediaStream; if ("captureStream" in globalCanvas) { canvasMediaStream = globalCanvas.captureStream(25); // 25 FPS } else if ("mozCaptureStream" in globalCanvas) { canvasMediaStream = globalCanvas.mozCaptureStream(25); } else if ("webkitCaptureStream" in globalCanvas) { canvasMediaStream = globalCanvas.webkitCaptureStream(25); } try { var mdStream = new MediaStream(); mdStream.addTrack(getTracks(canvasMediaStream, "video")[0]); canvasMediaStream = mdStream; } catch (e) {} if (!canvasMediaStream) { throw "captureStream API are NOT available."; } // Note: Jan 18, 2016 status is that, // Firefox MediaRecorder API can't record CanvasCaptureMediaStream object. mediaStreamRecorder = new MediaStreamRecorder(canvasMediaStream, { mimeType: config.mimeType || "video/webm", }); mediaStreamRecorder.record(); } else { whammy.frames = []; lastTime = new Date().getTime(); drawCanvasFrame(); } if (config.initCallback) { config.initCallback(); } }; this.getWebPImages = function(callback) { if (htmlElement.nodeName.toLowerCase() !== "canvas") { callback(); return; } var framesLength = whammy.frames.length; whammy.frames.forEach(function(frame, idx) { var framesRemaining = framesLength - idx; if (!config.disableLogs) { console.log(framesRemaining + "/" + framesLength + " frames remaining"); } if (config.onEncodingCallback) { config.onEncodingCallback(framesRemaining, framesLength); } var webp = frame.image.toDataURL("image/webp", 1); whammy.frames[idx].image = webp; }); if (!config.disableLogs) { console.log("Generating WebM"); } callback(); }; /** * This method stops recording Canvas. * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. * @method * @memberof CanvasRecorder * @example * recorder.stop(function(blob) { * video.src = URL.createObjectURL(blob); * }); */ this.stop = function(callback) { isRecording = false; var that = this; if (isCanvasSupportsStreamCapturing && mediaStreamRecorder) { mediaStreamRecorder.stop(callback); return; } this.getWebPImages(function() { /** * @property {Blob} blob - Recorded frames in video/webm blob. * @memberof CanvasRecorder * @example * recorder.stop(function() { * var blob = recorder.blob; * }); */ whammy.compile(function(blob) { if (!config.disableLogs) { console.log("Recording finished!"); } that.blob = blob; if (that.blob.forEach) { that.blob = new Blob([], { type: "video/webm", }); } if (callback) { callback(that.blob); } whammy.frames = []; }); }); }; var isPausedRecording = false; /** * This method pauses the recording process. * @method * @memberof CanvasRecorder * @example * recorder.pause(); */ this.pause = function() { isPausedRecording = true; if (mediaStreamRecorder instanceof MediaStreamRecorder) { mediaStreamRecorder.pause(); return; } }; /** * This method resumes the recording process. * @method * @memberof CanvasRecorder * @example * recorder.resume(); */ this.resume = function() { isPausedRecording = false; if (mediaStreamRecorder instanceof MediaStreamRecorder) { mediaStreamRecorder.resume(); return; } if (!isRecording) { this.record(); } }; /** * This method resets currently recorded data. * @method * @memberof CanvasRecorder * @example * recorder.clearRecordedData(); */ this.clearRecordedData = function() { if (isRecording) { this.stop(clearRecordedDataCB); } clearRecordedDataCB(); }; function clearRecordedDataCB() { whammy.frames = []; isRecording = false; isPausedRecording = false; } // for debugging this.name = "CanvasRecorder"; this.toString = function() { return this.name; }; function cloneCanvas() { //create a new canvas var newCanvas = document.createElement("canvas"); var context = newCanvas.getContext("2d"); //set dimensions newCanvas.width = htmlElement.width; newCanvas.height = htmlElement.height; //apply the old canvas to the new one context.drawImage(htmlElement, 0, 0); //return the new canvas return newCanvas; } function drawCanvasFrame() { if (isPausedRecording) { lastTime = new Date().getTime(); return setTimeout(drawCanvasFrame, 500); } if (htmlElement.nodeName.toLowerCase() === "canvas") { var duration = new Date().getTime() - lastTime; // via #206, by Jack i.e. @Seymourr lastTime = new Date().getTime(); whammy.frames.push({ image: cloneCanvas(), duration: duration, }); if (isRecording) { setTimeout(drawCanvasFrame, config.frameInterval); } return; } html2canvas(htmlElement, { grabMouse: typeof config.showMousePointer === "undefined" || config.showMousePointer, onrendered: function(canvas) { var duration = new Date().getTime() - lastTime; if (!duration) { return setTimeout(drawCanvasFrame, config.frameInterval); } // via #206, by Jack i.e. @Seymourr lastTime = new Date().getTime(); whammy.frames.push({ image: canvas.toDataURL("image/webp", 1), duration: duration, }); if (isRecording) { setTimeout(drawCanvasFrame, config.frameInterval); } }, }); } var lastTime = new Date().getTime(); var whammy = new Whammy.Video(100); } if (typeof RecordRTC !== "undefined") { RecordRTC.CanvasRecorder = CanvasRecorder; }