2

I'm working on a mobile web project that needs to access the camera and take a photo and then manipulate it. The problem is that we need to take the photo directly from the browser, and not open the native camera app to take it.

Ok, I use WebRTC for this task. I access to getUserMedia() and play a "video" that is the real time camera view. This task is for Android and iOS.

This works perfectly on Firefox. I assume that in Safari this will be impossible to achieve since getUserMedia() is still not supported by this browser, but Google Chrome have support but I'm unable to make it work on Chrome.

The problem on Chrome seems to be a bug that user is unable to select rear or front camera, so the image never displays, it always is a black image.

My code is very simple, I take it from https://davidwalsh.name/browser-camera but theorically it works on all browsers, but I can't make it work on Chrome. This is the code:

<video id="video" width="480" height="640" autoplay controls></video>
<button id="snap">Capture</button>
<canvas id="canvas" width="480" height="740"></canvas>

<script>
// Grab elements, create settings, etc.
var video = document.getElementById('video');
var i = 0;
// Get access to the camera!
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    // Not adding `{ audio: true }` since we only want video now
    navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
        video.src = window.URL.createObjectURL(stream);
        video.play();
    });
}
else if(navigator.getUserMedia) { // Standard
    navigator.getUserMedia({ video: true }, function(stream) {
        video.src = stream;
        video.play();
    }, errBack);
} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
    navigator.webkitGetUserMedia({ video: true }, function(stream){
    alert(window.webkitURL);
    alert(window.webkitURL.createObjectURL(stream));
        video.src = window.webkitURL.createObjectURL(stream);
        video.play();
    }, errBack);
} else if(navigator.mozGetUserMedia) { // Mozilla-prefixed
    navigator.mozGetUserMedia({ video: true }, function(stream){
        video.src = window.URL.createObjectURL(stream);
        video.play();
    }, errBack);
}

// Elements for taking the snapshot
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var video = document.getElementById('video');

// Trigger photo take
document.getElementById("snap").addEventListener("click", function() {
    context.drawImage(video, 0, 0, 640, 480);
});
</script>

How can I make it work on Chrome? How can I make that Chrome ask to user what camera he needs to use (rear / front)? I've found over internet a user that tells Chrome has a bug selecting the camera, so I think this is the problem.

Note that on Chrome Desktop it works perfectly, since there is only one camera and has not to delegate on the user to choose what camera should use. But on mobile devices with two cameras is impossible to choose how.

Thank you.

I'm not using polyfills. The duplicate mark is not solving my issue. I need some help with this. I need a canonical answer with a solution to the problem. Thank you for your time! I offer a bounty.

Marcos Pérez Gude
  • 21,869
  • 4
  • 38
  • 69

2 Answers2

6

Are you deploying on https? Chrome does not allow getUserMedia on http pages for security reasons.

See also this sample for enumerating and selecting cameras. The facingmode constraint you're asking about is unfortunately broken right now.

Philipp Hancke
  • 15,855
  • 2
  • 23
  • 31
  • Yes, I'm with a valid SSL certificate. So that's not the problem – Marcos Pérez Gude Nov 25 '16 at 09:18
  • In that example there is a select box to select the camera manually. Can I select the camera automatically? – Marcos Pérez Gude Nov 25 '16 at 09:19
  • I am seeing that the link you've attached, to work in chrome needs to enable experimental web features on the browser. Is there a way to make it work on chrome without making craps to allow all users to use the functionality, instead of only developers? – Marcos Pérez Gude Nov 25 '16 at 09:39
  • The note about flags applies only to output devices and is outdated. you can select a camera of your choice by calling enumerateDevices yourself and then passing a deviceId to getUserMedia. You don't need the box but another criterion to choose which deviceId (which is a uuid) – Philipp Hancke Nov 25 '16 at 17:51
  • And how can I know what is the front and the rear camera? – Marcos Pérez Gude Nov 29 '16 at 10:08
  • take a look at the labels (if available), they might contain something along the lines of "front" or "back". – Philipp Hancke Nov 29 '16 at 15:16
  • It seems a crap. A chrome crap, obvious. I need the dialog on the client to choose what camera he wants, like firefox, not choose by myself on the code a camera that I "think" is the correct camera. As usual, Chrome touching balls. – Marcos Pérez Gude Dec 02 '16 at 11:37
  • If you elaborate some this answer I will give you the bounty and the accepted answer. Easy to win. – Marcos Pérez Gude Dec 05 '16 at 12:05
2

To chose the camera add a constraint paramater with facingMode set to "user" or "environment". To let the user chose don't add these details.

var myConstraints = {
    audio: false, 
    video: {
        facingMode: "user"
    }
};

see https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia

The new API will become Promised based:

navigator.getUserMedia(myConstraints).then(function(stream) {
    video.srcObject = stream;
    video.play();
}).catch(errBack);

To use a future proof API and make it work now you can use a polyfill like https://github.com/webrtc/adapter

Walle Cyril
  • 3,087
  • 4
  • 23
  • 55