GetUserMedia - 面对模式

IT技术 javascript getusermedia
2021-01-14 17:26:48

我目前正在使用 Android 平板电脑和 GetUserMedia 在我的程序中拍照。

显然,GetUserMedia 使用的默认摄像头是前置摄像头。如何默认使用后置摄像头?

这是我的 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.");
        });

我在“强制”部分插入了 facesMode 但没有奏效。

请帮忙。

6个回答

更新: facingMode现在可通过adapter.js polyfill在Android 版Chrome 中使用

facingMode不是在Chrome尚未实施的Android,但在Firefox原生支持的Android。

但是,您必须使用标准约束:(Chrome使用https fiddle):

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>

{ exact: }语法意味着需要进行约束,如果用户没有正确的相机事情失败。如果您省略它,则约束是可选的,这在 Firefox for Android 中意味着它仅更改权限提示中相机选择器中的默认值。

或者,您可以使用enumerateDevices()让用户翻转相机。webrtc.github.io/samples/src/content/devices/input-output
2021-03-21 17:26:48
现在,在我的手机上,这不起作用。Chrome 声称支持 facesMode,但它实际上并没有工作,这似乎弄乱了adapter-latest.js。我能够使用adapter-latest.js 中的代码来想出一些有效的东西,有点像Peter Unsworth 的回答所显示的那样。
2021-03-22 17:26:48
@ user12861即将修复适配器。
2021-03-27 17:26:48
谢谢,你救了我的工作 :D
2021-03-29 17:26:48
bugs.chromium.org/p/chromium/issues/detail?id=290161现在已修复, facesMode 应该可以工作了!
2021-04-11 17:26:48

使用彼得的代码(https://stackoverflow.com/a/41618462/7723861)我想出了这个解决方案来获取后置摄像头:

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);
});
facingMode在不同的计算机和浏览器上尝试了几次 - 它几乎从未奏效(但我也将其他约束设置为精确,例如宽度和高度)
2021-03-25 17:26:48
不要使用标签来识别设备:此代码依赖于设备标签,并且设备标签是本地化的。例如,在使用加泰罗尼亚语的 iPhone 6S 中,标签将是“Càmera del darrere”和“Càmera del davant”,因此无法选择正确的设备
2021-04-03 17:26:48
这种在某些情况下有效,但对于 iOS11 则失败。相反,我正在使用constraints.video.facingMode = { exact: "environment" }
2021-04-13 17:26:48

通过 Cordova 将我们的 Web 应用程序部署到 android,我尝试了多种解决方案来访问后置摄像头。对我有用的解决方案是:

constraints = {
    audio: false,
    video: {
        width: 400,
        height: 300,
        deviceId: deviceId ? {exact: deviceId} : undefined
    }
};

通过以下方式检索 deviceId:

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);
});

我选择不使用 Cordova 插件,这样如果我们选择离开 Cordova,就不会有如此大的迁移。

因此,在某些情况下,我们可以依赖 device.label 为“相机 1,正面”或“相机 0,背面”。但我也看到一些手机没有报告,例如在 LG D852 上,相机设备的两个 device.labels 都是空字符串。
2021-03-29 17:26:48
你怎么知道 enumerateDevices 中哪一个摄像头在前面,哪个在后面?我认为第一个是面向用户的(前面),第二个是后面的,但是(在哪里)是指定的?
2021-04-04 17:26:48

您可以使用的一个漂亮的花花公子片段是:

var front = false;
document.getElementById('flip-button').onclick = function() { front =` !front; };
var constraints = { video: { facingMode: (front? "user" : "environment") } };

这应该对你有用。

在较新版本的 Chrome(v52 之后)中,adaper.js 解决方案似乎不起作用。所以我首先通过枚举设备来解决问题。这是我的解决方案。我不确定是否有更好的方法来翻转相机并在屏幕上显示视频。但是我必须先停止轨道并获得新的流。

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);
    }
};