UNPKG

recordrtc

Version:

RecordRTC is a server-less (entire client-side) JavaScript library can be used to record WebRTC audio/video media streams. It supports cross-browser audio/video recording.

306 lines (253 loc) 9.38 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#license|MIT} * @author {@link http://www.MuazKhan.com|Muaz Khan} * @typedef CanvasRecorder * @class * @example * var recorder = new CanvasRecorder(htmlElement, { disableLogs: 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' && htmlElement.nodeName.toLowerCase() !== 'canvas') { throw 'Please link: //cdn.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; } }); if (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) { isCanvasSupportsStreamCapturing = false; } var globalCanvas, globalContext, mediaStreamRecorder; if (isCanvasSupportsStreamCapturing) { if (!config.disableLogs) { console.debug('Your browser supports both MediRecorder API and canvas.captureStream!'); } globalCanvas = document.createElement('canvas'); globalCanvas.width = htmlElement.clientWidth || window.innerWidth; globalCanvas.height = htmlElement.clientHeight || window.innerHeight; globalCanvas.style = 'top: -9999999; left: -99999999; visibility:hidden; position:absoluted; display: none;'; (document.body || document.documentElement).appendChild(globalCanvas); globalContext = globalCanvas.getContext('2d'); } else if (!!navigator.mozGetUserMedia) { if (!config.disableLogs) { alert('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) { // CanvasCaptureMediaStream var canvasMediaStream; if ('captureStream' in globalCanvas) { canvasMediaStream = globalCanvas.captureStream(25); // 25 FPS } else if ('mozCaptureStream' in globalCanvas) { canvasMediaStream = globalCanvas.captureStream(25); } else if ('webkitCaptureStream' in globalCanvas) { canvasMediaStream = globalCanvas.captureStream(25); } try { var mdStream = new MediaStream(); mdStream.addTrack(canvasMediaStream.getVideoTracks()[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: '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; document.title = framesRemaining + '/' + framesLength + ' frames remaining'; if (config.onEncodingCallback) { config.onEncodingCallback(framesRemaining, framesLength); } var webp = frame.image.toDataURL('image/webp', 1); whammy.frames[idx].image = webp; }); document.title = '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) { var slef = this; mediaStreamRecorder.stop(function() { for (var prop in mediaStreamRecorder) { self[prop] = mediaStreamRecorder[prop]; } if (callback) { callback(that.blob); } }); 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) { document.title = '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; }; /** * This method resumes the recording process. * @method * @memberof CanvasRecorder * @example * recorder.resume(); */ this.resume = function() { isPausedRecording = false; if (!isRecording) { this.record(); } }; /** * This method resets currently recorded data. * @method * @memberof CanvasRecorder * @example * recorder.clearRecordedData(); */ this.clearRecordedData = function() { this.pause(); whammy.frames = []; }; 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; }