mighty-webcamjs
Version:
HTML5 Webcam Image Capture Library with Flash Fallback
196 lines (168 loc) • 6.4 kB
JavaScript
;
/* 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;