简体   繁体   中英

HTML5 & javascript - taking pictures from a device supporting multiple cameras

I am developing a Vuejs based PWA. I have implemented a component to take pictures using the device built-in camera. It is using

  • the navigator.mediaDevices.getUserMedia API with a video element to display the stream from the camera.
  • a canva and its getContext("2d").drawImage methods to get the picture from the stream and show it to the user
  • the navigator.mediaDevices.enumerateDevices API to get a list of available cameras and the constraint parameter of getUserMedia to switch between these.

This is all working great :)

But now I have stumbled on a new issue: some recent smartphones have multiple rear cameras that the built-in camera software would combine to take only one shoot (one camera would be good at low exposure, another one at high exposure and yet another one in some other conditions, etc.). In this case my app will show all the cameras and will let the user use them independently. The intended behavior would be to combine them just like the built-in software. How is that possible?

After trying on multiple devices having 1 (front), 2 (back and front) and multiples camera sensors (1 front, several back), my solution consists in using the label property of the MediaDeviceInfo object returned by mediaDevices.enumerateDevices() :

  • If it contains 'front' it is a front camera
  • If is contains 'back' it is a back camera
  • If it contains several front camera and/or back camera then the one whose label contains '0' is the one combining the others. Moreover, The first in the list always seems to be the front camera, and the last the combined back camera.

Then my code getting the id of the front camera and of the combined backed camera is the following (it assumes there is always one and only one front camera):

return navigator.mediaDevices.enumerateDevices()
.then(mediaDevices => {
  let cameras = mediaDevices.filter(mediaDevice => mediaDevice.kind === 'videoinput');
  console.log("#potential camera=" + cameras.length);
  if(cameras.length<=2)
    return cameras.map(x => x.deviceId);
  else {
    let front = cameras.find(x => x.label.match(/\bfront\b/));
    let back = cameras.filter(x => x.label.match(/\bback\b/) && x.label.match(/\b0\b/))
    if(!front || back.length!=1) {
      console.log("no clear front and back, taking first and last one - cameras=", cameras);
      return [cameras[0].deviceId, cameras[cameras.length-1].deviceId];
    }
    else {
      console.log("clear front and back");
      return [front.deviceId, back[0].deviceId];
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM