mighty-webcamjs
Version:
HTML5 Webcam Image Capture Library with Flash Fallback
225 lines (191 loc) • 9 kB
JavaScript
;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var React = require('react');
var PropTypes = require('prop-types');
var _require = require('react-dom'),
findDOMNode = _require.findDOMNode;
var atom = require('atom-js');
var debounce = require('lodash/debounce');
var BaseComponent = require('./BaseComponent.js');
var navigator = global.navigator || {};
var ua = navigator.userAgent || '';
var WebRTCComponent = function (_BaseComponent) {
_inherits(WebRTCComponent, _BaseComponent);
function WebRTCComponent() {
var _ref;
var _temp, _this, _ret;
_classCallCheck(this, WebRTCComponent);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = WebRTCComponent.__proto__ || Object.getPrototypeOf(WebRTCComponent)).call.apply(_ref, [this].concat(args))), _this), _this.handleVideoLoadedMetadata = function () {
var webcam = _this.props.webcam;
webcam.params.set({
load: true,
live: true
});
webcam.flip();
}, _this.handleUserMediaVideoPlaying = function (e) {
var video = e.target;
var webcam = _this.props.webcam;
var dimensions = {
width: video.videoWidth,
height: video.videoHeight
};
var debouncedFindBestResolutionCallback = debounce(function () {
dimensions = {
width: video.videoWidth,
height: video.videoHeight
};
webcam.params.set('loadedVideoDimensions', dimensions);
}, 250);
webcam.findBestResolution(video, dimensions).then(function () {
setTimeout(debouncedFindBestResolutionCallback(), 1000);
});
}, _this.handleVideoRef = function (element) {
_this.video = findDOMNode(element);
_this.props.onVideoRef(_this.video);
}, _temp), _possibleConstructorReturn(_this, _ret);
}
_createClass(WebRTCComponent, [{
key: 'startupWebRTC',
value: function startupWebRTC() {
var webcam = this.props.webcam;
var video = this.video;
var _webcam$constants = webcam.constants,
STANDARD_RESOLUTIONS = _webcam$constants.STANDARD_RESOLUTIONS,
CAPTURE_MODE_VIDEO = _webcam$constants.CAPTURE_MODE_VIDEO,
DETECTION_MODE_LABELS = _webcam$constants.DETECTION_MODE_LABELS;
// ask user for access to their camera
webcam.helpers.detectVideoInputs(webcam.mediaDevices).then(function () {
var cameraInfs = webcam.params.get('cameraInfs');
if (!cameraInfs.length) {
webcam.dispatch('error', 'Camera not detected.');
} else if (cameraInfs.length > 1) {
webcam.switchCamera(webcam.params.get('camera'));
}
var maxWidth = 9999;
var androidVersion = webcam.helpers.getAndroidVersion();
if (androidVersion && webcam.params.get('capture_mode') === CAPTURE_MODE_VIDEO) {
// android-only optimisationon so video is not lagging
//
// NOTE: following code fails when maxWidth is set too low
// on some devices (Pixel XL, Huawei p8 lite, Huawei P10), Android 5 devices
if (androidVersion < 6) {
maxWidth = 1280;
} else if (parseInt(androidVersion, 10) === 6) {
maxWidth = 1280;
} else if (parseInt(androidVersion, 10) === 7) {
maxWidth = 1680;
} else if (androidVersion >= 8) {
maxWidth = 1920;
}
if (/(HUAWEIVTR-L29|SM-G950|; Pixel|Nexus 6P)/.test(ua)) {
maxWidth = 1920;
}
}
// TODO: this code should not be called until webcam.params.get('cameraId') is set. Investigate.
var videoConstraints = void 0;
if (webcam.params.get('cameraDetectionMode') === DETECTION_MODE_LABELS) {
// http://stackoverflow.com/a/27444179/2590921
var allSizes = STANDARD_RESOLUTIONS.reduce(function (result, val) {
if (val <= maxWidth && val <= webcam.params.get('dest_width')) {
result.push({ minWidth: val });
}
return result;
}, [{ sourceId: cameraInfs[webcam.params.get('cameraId')].deviceId }]);
videoConstraints = {
optional: allSizes
};
} else {
videoConstraints = {
facingMode: webcam.constants.WEBRTC_CAMERAS[webcam.params.get('camera')],
width: { min: STANDARD_RESOLUTIONS[0], ideal: Math.min(webcam.params.get('dest_width'), maxWidth), max: maxWidth }
};
}
if (process.env.NODE_ENV !== 'production' && webcam.params.get('verbose')) {
console.log('videoConstraints used to getUserMedia', videoConstraints);
}
webcam.mediaDevices.getUserMedia({
audio: false,
video: videoConstraints
}).then(function (stream) {
// mediaDevices.getUserMedia callback fires ONLY when camera access is granted.
// detectVideoInputs will provide new list with labels.
webcam.helpers.detectVideoInputs(webcam.mediaDevices, true);
if (process.env.NODE_ENV !== 'production' && webcam.params.get('verbose')) {
console.log('stream from getUserMedia ready.', video);
}
var run = function run() {
// got access, attach stream to video
video.srcObject = stream; // NOTE: Polyfilled with adapter-js
webcam.stream = stream; // TODO: if not working, put it in onloadedmetadata
};
if (webcam.params.get('use_ImageCapture_API')) {
// Create image capture object and get camera capabilities
var imageCapture = new ImageCapture(stream.getVideoTracks()[0]);
imageCapture.getPhotoCapabilities().then(function (photoCapabilities) {
webcam.params.set({ photoCapabilities: photoCapabilities });
run();
}).catch(function (err) {
console.error('error while ImageCapture.getPhotoCapabilities', err);
run();
});
} else {
run();
}
}).catch(function (err) {
if (process.env.NODE_ENV !== 'production' && webcam.params.get('verbose')) {
console.log('getUserMedia failed', err);
}
// JH 2016-07-31 Instead of dispatching error, now falling back to Flash if userMedia fails (thx @john2014)
// JH 2016-08-07 But only if flash is actually installed -- if not, dispatch error here and now.
if (webcam.params.get('enable_flash') && webcam.detectFlash()) {
setTimeout(function () {
webcam.params.set('force_flash', 1);
webcam.reattach();
});
} else {
webcam.dispatch('error', err);
}
});
});
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
this.startupWebRTC();
}
}, {
key: 'render',
value: function render() {
return React.createElement('video', {
ref: this.handleVideoRef,
className: this.props.cssPrefix + '__video',
autoPlay: 'autoplay',
playsInline: 'playsinline' // THIS IS IMPORTANT FOR iOS11 !
, muted: true
// oncanplay={() => { console.log('video: canplay'); }}
// onseeked={() => { console.log('video: seeked'); }}
// onseeking={() => { console.log('video: seeking'); }}
// onstalled={() => { console.log('video: stalled'); }}
// onsuspend={() => { console.log('video: suspend'); }}
// onwaiting={() => { console.log('video: onwaiting'); }}
// onended={() => { console.log('video: onended'); }}
, onPlaying: this.handleUserMediaVideoPlaying,
onLoadedMetadata: this.handleVideoLoadedMetadata
});
}
}]);
return WebRTCComponent;
}(BaseComponent);
WebRTCComponent.propTypes = {
webcam: PropTypes.object.isRequired,
model: PropTypes.object.isRequired,
cssPrefix: PropTypes.string.isRequired
};
WebRTCComponent.defaultProps = {};
module.exports = atom.reactConnect('model', ['live', 'use_ImageCapture_API', 'photoCapabilities', 'flash_light_node'])(WebRTCComponent);