I am currently using an Android tablet and GetUserMedia to take pictures in my program.
Apparently, the default camera used by GetUserMedia is the front camera. How do I use the rear camera as a default?
Here's my code for GetUserMedia:
navigator.getUserMedia({
"audio": false,
"video": {
mandatory: {
minWidth: this.params.dest_width,
minHeight: this.params.dest_height,
//facingMode: "environment",
},
}
},
function(stream) {
// got access, attach stream to video
video.src = window.URL.createObjectURL( stream ) || stream;
Webcam.stream = stream;
Webcam.loaded = true;
Webcam.live = true;
Webcam.dispatch('load');
Webcam.dispatch('live');
Webcam.flip();
},
function(err) {
return self.dispatch('error', "Could not access webcam.");
});
I inserted facingMode in the "mandatory" part but didn't work.
Please help.
Update: facingMode
is now available in Chrome for Android through the adapter.js polyfill!
facingMode
is not yet implemented in Chrome for Android, but works natively in Firefox for Android.
You must use standard constraints however: (use https fiddle for Chrome):
var gum = mode =>
navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: mode}}})
.then(stream => (video.srcObject = stream))
.catch(e => log(e));
var stop = () => video.srcObject && video.srcObject.getTracks().forEach(t => t.stop());
var log = msg => div.innerHTML += msg + "<br>";
<button onclick="stop();gum('user')">Front</button>
<button onclick="stop();gum('environment')">Back</button>
<div id="div"></div><br>
<video id="video" height="320" autoplay></video>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
The { exact: }
syntax means the constraint is required, and things fail if the user doesn't have the right camera. If you leave it out then the constraint is optional, which in Firefox for Android means it only changes the default in the camera chooser in the permission prompt.
Using Peter's code (https://stackoverflow.com/a/41618462/7723861) I came up with this solution to get the rear camera:
function handleSuccess(stream) {
window.stream = stream; // make stream available to browser console
video.srcObject = stream;
}
function handleError(error) {
console.log('navigator.getUserMedia error: ', error);
}
var DEVICES = [];
var final = null;
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
var arrayLength = devices.length;
for (var i = 0; i < arrayLength; i++)
{
var tempDevice = devices[i];
//FOR EACH DEVICE, PUSH TO DEVICES LIST THOSE OF KIND VIDEOINPUT (cameras)
//AND IF THE CAMERA HAS THE RIGHT FACEMODE ASSING IT TO "final"
if (tempDevice.kind == "videoinput")
{
DEVICES.push(tempDevice);
if(tempDevice.facingMode == "environment" ||tempDevice.label.indexOf("facing back")>=0 )
{final = tempDevice;}
}
}
var totalCameras = DEVICES.length;
//If couldnt find a suitable camera, pick the last one... you can change to what works for you
if(final == null)
{
//console.log("no suitable camera, getting the last one");
final = DEVICES[totalCameras-1];
};
//Set the constraints and call getUserMedia
var constraints = {
audio: false,
video: {
deviceId: {exact: final.deviceId}
}
};
navigator.mediaDevices.getUserMedia(constraints).
then(handleSuccess).catch(handleError);
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
Deploying our web app to android through Cordova, I tried multiple solutions to access the rear camera. The solution that worked for me was:
constraints = {
audio: false,
video: {
width: 400,
height: 300,
deviceId: deviceId ? {exact: deviceId} : undefined
}
};
Retrieving the deviceId through:
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
// devices is an array of accessible audio and video inputs. deviceId is the property I used to switch cameras
})
.catch(function(err) {
console.log(err.name + ": " + error.message);
});
I chose not to use a Cordova plugin so that if we choose to move away from Cordova, there would not be such a hefty migration.
A pretty dandy snippet you can use is:
var front = false;
document.getElementById('flip-button').onclick = function() { front =` !front; };
var constraints = { video: { facingMode: (front? "user" : "environment") } };
This should work for you hopefully.
In the newer version of Chrome (after v52) the adaper.js solutions seem not working. So I solve the problem by enumerating devices first. Here is my solution. I am not sure if there is a better way to flip the camera and show the video on the screen. But I have to stop the track first and get a new stream.
let Video = function() {
let cameras = [];
let currCameraIndex = 0;
let constraints = {
audio: true,
video: {
deviceId: { exact: "" }
}
};
let videoCanvas = $('video#gum');
this.initialize = function() {
return enumerateDevices()
.then(startVideo);
};
this.flipCamera = function() {
currCameraIndex += 1;
if (currCameraIndex >= cameras.length) {
currCameraIndex = 0;
}
if (window.stream) {
window.stream.getVideoTracks()[0].stop();
}
return startVideo();
};
function enumerateDevices() {
return navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
devices.forEach(function(device) {
console.log(device);
if (device.kind === "videoinput") {
cameras.push(device.deviceId);
}
});
console.log(cameras);
});
}
function startVideo() {
constraints.video.deviceId.exact = cameras[currCameraIndex];
return navigator.mediaDevices.getUserMedia(constraints)
.then(handleSuccess).catch(handleError);
}
function handleSuccess(stream) {
videoCanvas[0].srcObject = stream;
window.stream = stream;
}
function handleError(error) {
alert(error);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With