如何在 Javascript 中选择合适的后置摄像头? [英] How to select proper backfacing camera in Javascript?

查看:27
本文介绍了如何在 Javascript 中选择合适的后置摄像头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 navigator.mediaDevices.getUserMedia 从网络浏览器中的相机设备打开 MediaStream.我的应用想要在 WebAssembly 中进行一些实时图像处理,为此,我需要直接从相机提供实时图像流.

I am using navigator.mediaDevices.getUserMedia to open MediaStream from camera device within a web browser. My app wants to do some realtime image processing in WebAssembly and for that, I need to provide a live stream of images directly from the camera.

我的解决方案在大多数设备上运行良好,但是,我在具有多个后置摄像头的设备上遇到了问题,例如 Android 版 Google Chrome 上的三星 Galaxy S10.问题在于以下代码段:

My solution works pretty well on most devices, however, I have a problem on devices with multiple back-facing cameras, such as Samsung Galaxy S10 on Google Chrome for Android. The problem is that the following snippet:

const constraints = {
    audio: false,
    video: {
        width: { min: 640, ideal: 1280, max: 1920 },
        height: { min: 480, ideal: 720, max: 1080 },
        facingMode: { ideal: 'environment' },
    }
};
const stream = await navigator.mediaDevices.getUserMedia( constraints );

总是打开错误的相机 - 不支持自动对焦并提供对我的代码来说太失真的图像的广角镜头相机.广角镜头适合风景摄影,但对于条码和文本扫描却很糟糕.

always opens a wrong camera - the wide-lens camera which does not support autofocus and provides images that are too distorted for my code. The wide-lens camera is good for landscape photography but it is terrible for barcode and text scanning.

如何使用 MediaTrackConstraints 选择正确的相机?我也试过添加

How can I select the correct camera by using MediaTrackConstraints? I've tried adding also

focusMode: { ideal: 'continuous' }

对于约束(根据 MDN 文档,这应该是图像轨道的可能约束)但它似乎不起作用.

to the constraints (according to MDN documentation, this should be a possible constraint for image tracks) but it does not seem to work.

我也尝试枚举所有设备(来自 this SO answer),但我不知道如何正确选择正确的相机.

I've also tried enumerating all devices (from this SO answer), but I don't know how to properly select the correct camera.

值得注意的是,这段代码片段:

Notably, this code snippet:

const devices = await navigator.mediaDevices.enumerateDevices();
devices.forEach( ( device: MediaDeviceInfo ) => {
    console.log( "Found device: " + JSON.stringify( device ) );
});

产生以下控制台输出:

Found device: {"deviceId":"default","kind":"audioinput","label":"","groupId":"4852f187ff6a41e6d3fb3ba41c4897f46bd8ff153579da6fcb8f485432a32f66"}
Found device: {"deviceId":"86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e00ec186cb1285ff22869d","kind":"audioinput","label":"","groupId":"c2cfc78763f7668263b0033c44d0f906ca0f33264ebfa6b96e9846265a21ff09"}
Found device: {"deviceId":"4d5fecf5a3eee5d41812bb6c34efe6d25342af9448628b006561c7385a22ca6c","kind":"audioinput","label":"","groupId":"7a86866423279d7b1e12dbe585a14a677a2f2df4e41ec5d388b6c90f7319e88d"}
Found device: {"deviceId":"b46cd34041256d2cf72ed6e8500f71beb698a01b8c47c7c04801c20c47630978","kind":"videoinput","label":"camera2 1, facing front","groupId":"b1bd1a6ed8a87cd07ca0fa84744ae515b1ab2bed61cc257765c37d3426269af7"}
Found device: {"deviceId":"39d63e8a9764261b73785c90beb58399997a5a4de56b3238fff6676c738331a6","kind":"videoinput","label":"camera2 3, facing front","groupId":"a23c2f0e311c0ca0c80a56a8b5ff7c1f8aa093df4f6ac080b051c1d95f60a94e"}
Found device: {"deviceId":"4d5fecf5a3eee5d41812bb6c34efe6d25342af9448628b006561c7385a22ca6c","kind":"videoinput","label":"camera2 2, facing back","groupId":"9b6b1a429e0db2d5094ddebe205d23309464650d8bcd585b2fe4ae8196b86f1c"}
Found device: {"deviceId":"86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e00ec186cb1285ff22869d","kind":"videoinput","label":"camera2 0, facing back","groupId":"0de9556e1253763d7203b3b9e5db313cf89e05dd4bdd4ea0c5aff52d2952cf11"}
Found device: {"deviceId":"default","kind":"audiooutput","label":"","groupId":"default"}

正确的相机标签为camera2 0, face back,出于某种原因,Chrome 总是选择camera2 2, face back.

The correct camera has the label camera2 0, facing back and for some reason Chrome always selects camera2 2, facing back.

当然,我可以通过标签对相机的选择进行硬编码,但这仅适用于三星 Galaxy S10,我希望我的代码适用于具有多个后置摄像头的任何设备.

Of course, I could hardcode the selection of camera by its label, but that would work only on Samsung Galaxy S10 and I would like my code to work on any device having multiple back-facing cameras.

我还没有尝试在 iPhone 11 Pro(有 3 个后置摄像头)上运行我的页面,但它可以在华为 Mate 30 Pro(4 个后置摄像头)和 Oppo Reno 9 上正常运行.此外,问题似乎与 Android 上的谷歌浏览器有关.当我在 Firefox for Android 上打开我的页面时,浏览器会要求我在关闭相机权限对话框后选择应该使用哪个相机,并且只有当多个相机满足给定的限制时.这是非常公平的,因为它可以选择正确的相机来执行扫描.我还没有尝试在 Samsung Internet 和 Opera 浏览器上打开我的页面(还没有).

I still haven't tried running my page on iPhone 11 Pro (which has 3 back-facing cameras), but it works correctly on Huawei Mate 30 Pro (4 back-facing cameras) and Oppo Reno 9. Also, the problem seems to related to Google Chrome on Android. When I open my page on Firefox for Android, the browser asks me to select which camera should be used just after closing the camera permission dialog and only if multiple cameras satisfy the given constraints. That is quite fair, as it makes it possible to select the correct camera for performing the scan. I haven't tried opening my page on Samsung Internet and Opera browsers (yet).

由于谷歌浏览器是 Android 上最受欢迎的网络浏览器,我什至会对 Chrome 特定的解决方案感到满意,但当然,最好的办法是获得适用于任何地方的答案.

Since Google Chrome is the most popular web browser on Android, I would be even satisfied with Chrome-specific solution, but of course, the best would be to get answer that works everywhere.

根据 jib 的评论,我也尝试使用 focusDistance

Following the comment from jib, I've tried also using focusDistance with

focusDistance: { min: 0.05, ideal: 0.12, max: 0.3 }

它没有帮助.

我还尝试使用以下代码段记录 getSettingsgetCapabilities 的输出:

I've also tried logging the outputs of getSettings and getCapabilities with the following snippet:

const devices = await navigator.mediaDevices.enumerateDevices();
let videoDevices: Array< MediaDeviceInfo > = [];
devices.forEach( ( device: MediaDeviceInfo ) => {
    if ( device.kind == 'videoinput' ) {
        console.log( "Found video device: " + JSON.stringify( device ) );
        videoDevices.push( device );
    }
});

console.log( '' );

// open every video device and dump its characteristics
for ( let i in videoDevices ) {
    const device = videoDevices[ i ];
    console.log( "Opening video device " + device.deviceId + " (" + device.label + ")" );
    const stream = await navigator.mediaDevices.getUserMedia( { video: { deviceId: { exact: device.deviceId } } } );
    stream.getVideoTracks().forEach( track => {
            const capabilities = track.getCapabilities();
            console.log( "Track capabilities: " + JSON.stringify( capabilities ) );
            const settings = track.getSettings();
            console.log( "Track settings: " + JSON.stringify( settings ) );
            console.log( '' );
        }
    )

    stream.getTracks().forEach( track => track.stop() );
}

输出如下:

<代码>实测视频设备:{ 设备ID": b46cd34041256d2cf72ed6e8500f71beb698a01b8c47c7c04801c20c47630978", 种类": videoinput", 标签": camera2 1,面向前", 的groupId": 500dd57c6795399100a5ca8bf7f0cc4d7ed8b1bcb0877101d1bef7eb74921868"}发现视频设备:{ 设备ID": 39d63e8a9764261b73785c90beb58399997a5a4de56b3238fff6676c738331a6", 种类": videoinput", 标签": camera2 3,面向前", 的groupId": 245693c8d34be77fe2f15be31b6054a19edb8ea9ed4116d966d2a03695bebebe"}发现视频设备:{ 设备ID": 4d5fecf5a3eee5d41812bb6c34efe6d25342af9448628b006561c7385a22ca6c", 种类": videoinput", 标签": camera2 2,朝后", 的groupId": c219595df2c2a430aea7007f64e6ce8fbfa783b038cf53069336361cc07e71af"}发现视频设备:{ 设备ID": 86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e00ec186cb1285ff22869d", 种类": videoinput", 标签": camera2 0,朝后", 的groupId": 96a68b6d6429786317e3b2c4773082604c5ab9a5cdaaf49c481878e40d67e987"}打开视频设备 b46cd34041256d2cf72ed6e8500f71beb698a01b8c47c7c04801c20c47630978(camera2 1,正面)跟踪功能:{"aspectRatio":{"max":3216,"min":0.0004528985507246377},"deviceId":"b46cd34041256d2cf72ed6e8500f71beb698a01b8004528985507246377},"deviceId":"b46cd34041256d2cf72ed6e8500f71beb698a01b80c407001b8004000f71b80c40701b80c407","cmax040","cmax0",c400c70",c4000c70",c4007",c4000c707",c4007","cmax2007",,"min":0},"groupId":"500dd57c6795399100a5ca8bf7f0cc4d7ed8b1bcb0877101d1bef7eb74921868","height":{"max":2208,"min":2208,"min":"-scalend","cro],"width":{"max":3216,"min":1}}跟踪设置:{ 的aspectRatio":1.3333333333333333 的DeviceID": b46cd34041256d2cf72ed6e8500f71beb698a01b8c47c7c04801c20c47630978", facingMode": 用户", 帧率":30 的groupId": 500dd57c6795399100a5ca8bf7f0cc4d7ed8b1bcb0877101d1bef7eb74921868", 高度":480, resizeMode":无",宽度":640}打开视频设备 39d63e8a9764261b73785c90beb58399997a5a4de56b3238fff6676c738331a6(camera2 3,正面)跟踪能力:{"aspectRatio":{"max":3968,"min":0.0003654970760233918},"deviceId":"39d63e8a9764261b73785c90beb58399997a5a4de86fing","80000000000000000000000000000000000007","min":0},"groupId":"245693c8d34be77fe2f15be31b6054a19edb8ea9ed4116d966d2a03695bebebe","height":{"max":2736,"min":1},"cron-Mode":scale,"cronp"and"],"width":{"max":3968,"min":1}}跟踪设置:{ 的aspectRatio":1.3333333333333333 的DeviceID": 39d63e8a9764261b73785c90beb58399997a5a4de56b3238fff6676c738331a6", facingMode": 用户", 帧率":30 的groupId": 245693c8d34be77fe2f15be31b6054a19edb8ea9ed4116d966d2a03695bebebe", 高度":480, resizeMode":无",宽度":640}打开视频设备 4d5fecf5a3eee5d41812bb6c34efe6d25342af9448628b006561c7385a22ca6c(camera2 2,面朝后)跟踪功能:{"aspectRatio":{"max":4608,"min":0.00028935185185185184},"deviceId":"4d5fecf5a3eee5d41812bb6c34efe6d25342af94406865"cf94068682af94068682af94068682af94068682af9406868"cmax08686"cf9406865"c"0.00028935185185185184","min":0},"groupId":"c219595df2c2a430aea7007f64e6ce8fbfa783b038cf53069336361cc07e71af","height":{"max":3456,"min":"-scale,"cro],"width":{"max":4608,"min":1}}跟踪设置:{ 的aspectRatio":1.3333333333333333, 设备ID": 4d5fecf5a3eee5d41812bb6c34efe6d25342af9448628b006561c7385a22ca6c", facingMode": 环境", 帧率":60 的groupId": c219595df2c2a430aea7007f64e6ce8fbfa783b038cf53069336361cc07e71af", 高度":480, resizeMode":无",宽度":640}打开视频设备 86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e00ec186cb1285ff22869d(camera2 0,面朝后)跟踪能力:{"aspectRatio":{"max":4032,"min":0.00033068783068783067},"deviceId":"86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e0033068783068783067","min":0},"groupId":"96a68b6d6429786317e3b2c4773082604c5ab9a5cdaaf49c481878e40d67e987","height":{"max":3024},"croone-p"1"],"width":{"max":4032,"min":1}}跟踪设置:{ 的aspectRatio":1.3333333333333333, 设备ID": 86d4706b0bf160ff12fa75535173edcc68d4fa7ad5e00ec186cb1285ff22869d", facingMode": 环境", 帧率":60 的groupId": 96a68b6d6429786317e3b2c4773082604c5ab9a5cdaaf49c481878e40d67e987", 高度":480, resizeMode":无",宽度":640}

因此,除了最大可用分辨率不同之外,camera2 0,面向后camera2 2,面向后仍然没有区别.

So, still, nothing to distinguish between camera2 0, facing back and camera2 2, facing back, except different maximum available resolution.

我也尝试过使用三星互联网浏览器,它的行为与谷歌浏览器相同.

I've also tried with Samsung Internet browser and it behaves the same as Google Chrome.

还有其他想法吗(除了遍历所有后置摄像头并选择分辨率最低的摄像头)?

Any other ideas (except iterating over all back-facing camera and selecting the one with least resolution)?

推荐答案

我把所有的相机按照 id 放到了数组中

I placed all the cameras by id into array like that

      navigator.mediaDevices.enumerateDevices()
        .then(function(devices) {
        
        for(;devices[i];){
        if(devices[i].kind == "videoinput"){
            that.aCameras.push(   [devices[i].deviceId , devices[i].label]   )
            j++;            
            }
        i++;
        }
    });

在按下按钮翻转相机的事件中,我这样做了:

Than on the event that flip the camera by pressing the button i did this:

      var defaultsOpts = { audio: false, video: true };
      defaultsOpts.video = { 
              deviceId: that.aCameras[that.currentCamera][0]
      };
      if ( that.aCameras.length-1 != that.currentCamera ){
          that.currentCamera++;
      }
      else{
          that.currentCamera = 0;
      }      
      navigator.mediaDevices.getUserMedia(defaultsOpts)
            .then(function (stream) {
                  vid.srcObject = stream;
                  localstream = stream;
                  vid.play();
               });
          
       });

像那样而不是使用用户/环境,我的问题已经解决了.

like that instead of using user/enviroment, my problem was sort of solved.

希望也能帮到你.

问候,视频.

这篇关于如何在 Javascript 中选择合适的后置摄像头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆