UNPKG

mighty-webcamjs

Version:

HTML5 Webcam Image Capture Library with Flash Fallback

225 lines (191 loc) 9 kB
'use strict'; 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);