UNPKG

mighty-webcamjs

Version:

HTML5 Webcam Image Capture Library with Flash Fallback

196 lines (168 loc) 6.4 kB
'use strict'; /* global MediaRecorder, Blob, FileReader */ var Webcam = void 0; var recordedBlobs = void 0; var mediaRecorder = void 0; var videoMimeType = void 0; var maxVideoLengthTimeout = void 0; var isMobile = global.navigator ? /(mobile)/i.test(global.navigator.userAgent) : false; var videoFormats = ['video/webm;codecs=h264', 'video/x-matroska;codecs=h264', 'video/mp4;codecs=h264', 'video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm;codecs=daala', 'video/x-matroska;codecs=avc1', 'video/mp4;codecs=avc1', 'video/mp4', 'video/mpeg', 'video/hevc', '']; var RECORD_TIMESCALE = 20; // collect 20ms of data in each blob. var VideoRecorder = { init: function init(webcamObj) { Webcam = webcamObj; return VideoRecorder; }, checkIfCanRecord: function checkIfCanRecord() { // No Webcam.stream.active means camera not started or not available. // No MediaRecorder means - file fallabck video recording will be used. return !!(Webcam.stream && Webcam.stream.active) || !global.MediaRecorder; }, resetWebrtcCamera: function resetWebrtcCamera() { var stream = this.stream; if (stream) { if (stream.getVideoTracks) { // get video track to call stop on it var tracks = stream.getVideoTracks(); if (tracks && tracks[0] && tracks[0].stop) tracks[0].stop(); } else if (stream.stop) { // deprecated, may be removed in future stream.stop(); } } VideoRecorder.stopRecording(); }, stopRecording: function stopRecording(dispatch) { clearTimeout(maxVideoLengthTimeout); // HACK: // mediaRecorder can be inactive in Incognito mode Chrome@Windows 7, even while recording. if (mediaRecorder && mediaRecorder.state !== 'inactive') { mediaRecorder.stop(); } Webcam.params.set('videoRecording', false); if (dispatch && recordedBlobs.length) { Webcam.dispatch('videoTaken', { blob: new Blob(recordedBlobs, { type: videoMimeType.split(';')[0] }) }); } }, startRecording: function startRecording() { if (!Webcam.video) { Webcam.dispatch('error', new Webcam.errors.WebcamError('Video is not loaded yet.')); return; } // phones have trouble with high bitrate for high resolutions var bitRateLimiter = 1; if (isMobile) { bitRateLimiter = Math.min(1024 * 1024, Webcam.video.videoWidth * Webcam.video.videoHeight) / (Webcam.video.videoWidth * Webcam.video.videoHeight); bitRateLimiter = Math.min(1, bitRateLimiter + bitRateLimiter / 2); } recordedBlobs = []; var autoDetectedBitrate = Webcam.params.get('video_bitrate_per_pixel') * Webcam.video.videoWidth * Webcam.video.videoHeight * bitRateLimiter; var options = { videoBitsPerSecond: autoDetectedBitrate }; for (var i = 0; i < videoFormats.length; i++) { if (MediaRecorder.isTypeSupported(videoFormats[i])) { options.mimeType = videoFormats[i]; break; } } videoMimeType = options.mimeType; try { mediaRecorder = new MediaRecorder(Webcam.stream, options); // var maxWidth = 9999; // // android-version-based optimisation so video is not lagging // if (parseFloat(getAndroidVersion()) < 6) { // maxWidth = 1280; // } // if (parseFloat(getAndroidVersion()) === 6) { // maxWidth = 1440; // } // if (parseFloat(getAndroidVersion()) >= 7) { // maxWidth = 1600; // } // const longerSide = Math.max( Webcam.video.videoWidth, Webcam.video.videoHeight ); // const shorterSide = Math.min( Webcam.video.videoWidth, Webcam.video.videoHeight ); // if (longerSide > maxWidth) { // if (longerSide === Webcam.video.videoWidth) { // mediaRecorder.videoWidth = maxWidth; // mediaRecorder.videoHeight = shorterSide * (Webcam.video.videoWidth / maxWidth); // } else { // mediaRecorder.videoHeight = maxWidth; // mediaRecorder.videoWidth = shorterSide * (Webcam.video.videoHeight / maxWidth); // } // } } catch (e) { console.error('Exception while creating MediaRecorder: ' + e); // eslint-disable-line var alertMsg = 'Exception while creating MediaRecorder: ' // eslint-disable-line + e + '. mimeType: ' + options.mimeType; Webcam.dispatch('error', new Webcam.errors.WebcamError(alertMsg)); return; } if (process.env.NODE_ENV !== 'production' && Webcam.params.get('verbose')) { /* eslint-disable no-console */ console.log('videoBitsPerSecond', options.videoBitsPerSecond); console.log('detectedMimeType', options.mimeType); console.log('Created MediaRecorder', mediaRecorder, 'with options', options); /* eslint-enable */ } // mediaRecorder.onstop = handleStop; mediaRecorder.ondataavailable = function (event) { if (event.data && event.data.size > 0) { recordedBlobs.push(event.data); } }; mediaRecorder.start(RECORD_TIMESCALE); // collect 20ms of data maxVideoLengthTimeout = setTimeout(function () { VideoRecorder.stopRecording(true); }, Webcam.params.get('video_length')); Webcam.params.set('videoRecording', true); }, handleFileFallbackVideoInput: function handleFileFallbackVideoInput(e) { if (!e.target.files || !e.target.files.length) { return; } var rawFile = e.target.files[0]; var rawFileType = rawFile.type; if (!/^video\//.test(rawFileType)) { return Webcam.dispatch('error', new Webcam.errors.WebcamError('Invalid file type. Please provide video.')); } var reader = new FileReader(); reader.onload = function (readerEvent) { var blob = new Blob([readerEvent.target.result], { type: rawFileType }); Webcam.dispatch('videoTaken', { blob: blob, rawFile: rawFile }); }; reader.readAsArrayBuffer(rawFile); }, videoFormatToExt: function videoFormatToExt(mimeType) { var videoFormat = mimeType.substr(6).split(';')[0]; switch (videoFormat) { case 'x-matroska': return 'mkv'; case 'quicktime': return 'mov'; case 'webm': default: return videoFormat; } }, download: function download(blob) { var fileName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Date.now(); var url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = fileName + '.' + VideoRecorder.videoFormatToExt(blob.type); document.body.appendChild(a); a.click(); setTimeout(function () { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 100); } }; module.exports = VideoRecorder;