mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-12 21:21:42 +08:00
Implemented new MediaDevices API; Fallback for facingMode on Chrome-Mobile
This commit is contained in:
@@ -98,8 +98,7 @@ $(function() {
|
|||||||
var values = value.split('x');
|
var values = value.split('x');
|
||||||
return {
|
return {
|
||||||
width: parseInt(values[0]),
|
width: parseInt(values[0]),
|
||||||
height: parseInt(values[1]),
|
height: parseInt(values[1])
|
||||||
facing: "environment"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -118,7 +117,7 @@ $(function() {
|
|||||||
constraints: {
|
constraints: {
|
||||||
width: 640,
|
width: 640,
|
||||||
height: 480,
|
height: 480,
|
||||||
facing: "environment" // or user
|
facingMode: "environment"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
|
|||||||
+2
-1
@@ -77,6 +77,7 @@
|
|||||||
"gl-matrix": "^2.3.1",
|
"gl-matrix": "^2.3.1",
|
||||||
"lodash": "^3.10.1",
|
"lodash": "^3.10.1",
|
||||||
"ndarray": "^1.0.18",
|
"ndarray": "^1.0.18",
|
||||||
"ndarray-linear-interpolate": "^1.0.0"
|
"ndarray-linear-interpolate": "^1.0.0",
|
||||||
|
"webrtc-adapter": "^1.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ if (typeof window !== 'undefined') {
|
|||||||
window.setTimeout(callback, 1000 / 60);
|
window.setTimeout(callback, 1000 / 60);
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia ||
|
|
||||||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
|
||||||
}
|
}
|
||||||
Math.imul = Math.imul || function(a, b) {
|
Math.imul = Math.imul || function(a, b) {
|
||||||
var ah = (a >>> 16) & 0xffff,
|
var ah = (a >>> 16) & 0xffff,
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ module.exports = {
|
|||||||
constraints: {
|
constraints: {
|
||||||
width: 640,
|
width: 640,
|
||||||
height: 480,
|
height: 480,
|
||||||
minAspectRatio: 0,
|
// aspectRatio: 640/480, // optional
|
||||||
maxAspectRatio: 100,
|
facingMode: "environment", // or user
|
||||||
facing: "environment" // or user
|
// deviceId: "38745983457387598375983759834"
|
||||||
},
|
},
|
||||||
area: {
|
area: {
|
||||||
top: "0%",
|
top: "0%",
|
||||||
|
|||||||
+64
-95
@@ -1,28 +1,13 @@
|
|||||||
const merge = require('lodash/object/merge');
|
const merge = require('lodash/object/merge');
|
||||||
|
const pick = require('lodash/object/pick');
|
||||||
|
const mapKeys = require('lodash/object/mapKeys');
|
||||||
|
|
||||||
var streamRef,
|
var streamRef,
|
||||||
loadedDataHandler;
|
loadedDataHandler;
|
||||||
|
|
||||||
/**
|
function waitForVideo(video) {
|
||||||
* Wraps browser-specific getUserMedia
|
return new Promise((resolve, reject) => {
|
||||||
* @param {Object} constraints
|
let attempts = 10;
|
||||||
* @param {Object} success Callback
|
|
||||||
* @param {Object} failure Callback
|
|
||||||
*/
|
|
||||||
function getUserMedia(constraints, success, failure) {
|
|
||||||
if (typeof navigator.getUserMedia !== 'undefined') {
|
|
||||||
navigator.getUserMedia(constraints, function (stream) {
|
|
||||||
streamRef = stream;
|
|
||||||
var videoSrc = (window.URL && window.URL.createObjectURL(stream)) || stream;
|
|
||||||
success.apply(null, [videoSrc]);
|
|
||||||
}, failure);
|
|
||||||
} else {
|
|
||||||
failure(new TypeError("getUserMedia not available"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadedData(video, callback) {
|
|
||||||
var attempts = 10;
|
|
||||||
|
|
||||||
function checkVideo() {
|
function checkVideo() {
|
||||||
if (attempts > 0) {
|
if (attempts > 0) {
|
||||||
@@ -30,16 +15,17 @@ function loadedData(video, callback) {
|
|||||||
if (ENV.development) {
|
if (ENV.development) {
|
||||||
console.log(video.videoWidth + "px x " + video.videoHeight + "px");
|
console.log(video.videoWidth + "px x " + video.videoHeight + "px");
|
||||||
}
|
}
|
||||||
callback();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
window.setTimeout(checkVideo, 500);
|
window.setTimeout(checkVideo, 500);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback('Unable to play video stream. Is webcam working?');
|
reject('Unable to play video stream. Is webcam working?');
|
||||||
}
|
}
|
||||||
attempts--;
|
attempts--;
|
||||||
}
|
}
|
||||||
checkVideo();
|
checkVideo();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,89 +33,72 @@ function loadedData(video, callback) {
|
|||||||
* and calls the callback function when the content is ready
|
* and calls the callback function when the content is ready
|
||||||
* @param {Object} constraints
|
* @param {Object} constraints
|
||||||
* @param {Object} video
|
* @param {Object} video
|
||||||
* @param {Object} callback
|
|
||||||
*/
|
*/
|
||||||
function initCamera(constraints, video, callback) {
|
function initCamera(video, constraints) {
|
||||||
getUserMedia(constraints, function(src) {
|
return navigator.mediaDevices.getUserMedia(constraints)
|
||||||
video.src = src;
|
.then((stream) => {
|
||||||
if (loadedDataHandler) {
|
return new Promise((resolve, reject) => {
|
||||||
video.removeEventListener("loadeddata", loadedDataHandler, false);
|
streamRef = stream;
|
||||||
}
|
video.src = window.URL.createObjectURL(stream);
|
||||||
loadedDataHandler = loadedData.bind(null, video, callback);
|
video.onloadedmetadata = (e) => {
|
||||||
video.addEventListener('loadeddata', loadedDataHandler, false);
|
|
||||||
video.play();
|
video.play();
|
||||||
}, function(e) {
|
resolve();
|
||||||
callback(e);
|
};
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.then(waitForVideo.bind(null, video));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function deprecatedConstraints(videoConstraints) {
|
||||||
* Normalizes the incoming constraints to satisfy the current browser
|
const normalized = pick(videoConstraints, ["width", "height", "facingMode",
|
||||||
* @param config
|
"aspectRatio", "deviceId"]);
|
||||||
* @param cb Callback which is called whenever constraints are created
|
|
||||||
* @returns {*}
|
if (typeof videoConstraints["minAspectRatio"] !== 'undefined' &&
|
||||||
*/
|
videoConstraints["minAspectRatio"] > 0) {
|
||||||
function normalizeConstraints(config, cb) {
|
normalized["aspectRatio"] = videoConstraints["minAspectRatio"];
|
||||||
var constraints = {
|
console.log("WARNING: Constraint 'minAspectRatio' is deprecated; Use 'aspectRatio' instead");
|
||||||
|
}
|
||||||
|
if (typeof videoConstraints["facing"] !== 'undefined') {
|
||||||
|
normalized["facingMode"] = videoConstraints["facing"];
|
||||||
|
console.log("WARNING: Constraint 'facing' is deprecated. Use 'facingMode' instead'");
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCameraFacing(facing, constraints) {
|
||||||
|
if (typeof constraints.video.deviceId !== 'undefined' || !facing){
|
||||||
|
return Promise.resolve(constraints);
|
||||||
|
}
|
||||||
|
if ( typeof MediaStreamTrack !== 'undefined' &&
|
||||||
|
typeof MediaStreamTrack.getSources !== 'undefined') {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
MediaStreamTrack.getSources((sourceInfos) => {
|
||||||
|
const videoSource = sourceInfos.filter((sourceInfo) => (
|
||||||
|
sourceInfo.kind === "video" && sourceInfo.facing === facing
|
||||||
|
))[0];
|
||||||
|
if (videoSource) {
|
||||||
|
return resolve(merge({}, constraints,
|
||||||
|
{video: {deviceId: videoSource.id}}));
|
||||||
|
}
|
||||||
|
return resolve(constraints);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(merge({}, videoConstraints, {facingMode: facing}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickConstraints(videoConstraints) {
|
||||||
|
const constraints = {
|
||||||
audio: false,
|
audio: false,
|
||||||
video: true
|
video: deprecatedConstraints(videoConstraints)
|
||||||
},
|
|
||||||
videoConstraints = merge({
|
|
||||||
width: 640,
|
|
||||||
height: 480,
|
|
||||||
minAspectRatio: 0,
|
|
||||||
maxAspectRatio: 100,
|
|
||||||
facing: "environment"
|
|
||||||
}, config);
|
|
||||||
|
|
||||||
if ( typeof MediaStreamTrack !== 'undefined' && typeof MediaStreamTrack.getSources !== 'undefined') {
|
|
||||||
MediaStreamTrack.getSources(function(sourceInfos) {
|
|
||||||
var videoSourceId;
|
|
||||||
for (var i = 0; i < sourceInfos.length; ++i) {
|
|
||||||
var sourceInfo = sourceInfos[i];
|
|
||||||
if (sourceInfo.kind === "video" && sourceInfo.facing === videoConstraints.facing) {
|
|
||||||
videoSourceId = sourceInfo.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
constraints.video = {
|
|
||||||
mandatory: {
|
|
||||||
minWidth: videoConstraints.width,
|
|
||||||
minHeight: videoConstraints.height,
|
|
||||||
minAspectRatio: videoConstraints.minAspectRatio,
|
|
||||||
maxAspectRatio: videoConstraints.maxAspectRatio
|
|
||||||
},
|
|
||||||
optional: [{
|
|
||||||
sourceId: videoSourceId
|
|
||||||
}]
|
|
||||||
};
|
};
|
||||||
return cb(constraints);
|
return applyCameraFacing(constraints.video.facingMode, constraints);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
constraints.video = {
|
|
||||||
mediaSource: "camera",
|
|
||||||
width: { min: videoConstraints.width, max: videoConstraints.width },
|
|
||||||
height: { min: videoConstraints.height, max: videoConstraints.height },
|
|
||||||
require: ["width", "height"]
|
|
||||||
};
|
|
||||||
return cb(constraints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests the back-facing camera of the user. The callback is called
|
|
||||||
* whenever the stream is ready to be consumed, or if an error occures.
|
|
||||||
* @param {Object} video
|
|
||||||
* @param {Object} callback
|
|
||||||
*/
|
|
||||||
function request(video, videoConstraints, callback) {
|
|
||||||
normalizeConstraints(videoConstraints, function(constraints) {
|
|
||||||
initCamera(constraints, video, callback);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
request: function(video, constraints, callback) {
|
request: function(video, videoConstraints) {
|
||||||
request(video, constraints, callback);
|
return pickConstraints(videoConstraints)
|
||||||
|
.then(initCamera.bind(null, video));
|
||||||
},
|
},
|
||||||
release: function() {
|
release: function() {
|
||||||
var tracks = streamRef && streamRef.getVideoTracks();
|
var tracks = streamRef && streamRef.getVideoTracks();
|
||||||
|
|||||||
+4
-4
@@ -1,4 +1,5 @@
|
|||||||
import TypeDefs from './common/typedefs'; // eslint-disable-line no-unused-vars
|
import TypeDefs from './common/typedefs'; // eslint-disable-line no-unused-vars
|
||||||
|
import WebrtcAdapter from 'webrtc-adapter'; // eslint-disable-line no-unused-vars
|
||||||
import ImageWrapper from './common/image_wrapper';
|
import ImageWrapper from './common/image_wrapper';
|
||||||
import BarcodeLocator from './locator/barcode_locator';
|
import BarcodeLocator from './locator/barcode_locator';
|
||||||
import BarcodeDecoder from './decoder/barcode_decoder';
|
import BarcodeDecoder from './decoder/barcode_decoder';
|
||||||
@@ -56,12 +57,11 @@ function initInputStream(cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_inputStream = InputStream.createLiveStream(video);
|
_inputStream = InputStream.createLiveStream(video);
|
||||||
CameraAccess.request(video, _config.inputStream.constraints, function(err) {
|
CameraAccess.request(video, _config.inputStream.constraints)
|
||||||
if (!err) {
|
.then(() => {
|
||||||
_inputStream.trigger("canrecord");
|
_inputStream.trigger("canrecord");
|
||||||
} else {
|
}).catch((err) => {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user