当前位置: 首页 > 知识库问答 >
问题:

javascript - 求助:getUserMedia展示本机摄像头只能展示两个吗?为什么第三个会报错?

乜华翰
2024-07-15

navigator.mediaDevices.getUserMedia 方法最多只能获取两个摄像头数据吗?

这边有一个设备有三个摄像头。使用navigator.mediaDevices.enumerateDevices方法获取到设备列表之后,循环调用getUserMedia,结果就是前两个可以展示在video标签中,第三个调用getUserMedia时会报错:DOMException: Could not start video source。

调整过展示顺序,三个摄像头的确没问题,谁第三个加载谁就不行。

html中有三个video标签,id分别是v0,v1,v2。 下面是js的调试代码。第三个getUserMedia会报错。好无奈啊。

export default {
    data(){
        return {

        }
    },
    mounted(){
        this.test();
    },
    methods:{
        async test(){
            let arr = await navigator.mediaDevices.enumerateDevices();
            console.log(arr);
            let list = [];

            for(let i=0;i<arr.length;i++){
                let di = arr[i];
                if(di.kind === 'videoinput'){
                    list.push({
                        video: {
                            deviceId:di.deviceId
                        }
                    });
                }
                
                /*if(window.stream){
                    window.stream.getTracks().forEach(function(track) {
                        track.stop();
                    });
                }*/
            }            
            
            navigator.mediaDevices.getUserMedia(list[0]).then((stram)=>{
                let element1 = document.getElementById("v0");
                element1.srcObject = stram;
            }).catch((e)=>{
                console.log('Error',list[0],e)
            });

            navigator.mediaDevices.getUserMedia(list[1]).then((stram)=>{
                let element2 = document.getElementById("v1");
                element2.srcObject = stram;
            }).catch((e)=>{
                console.log('Error',list[1],e)
            });

            navigator.mediaDevices.getUserMedia(list[2]).then((stram)=>{
                let element3 = document.getElementById("v2");
                element3.srcObject = stram;
            }).catch((e)=>{
                console.log('Error',list[2],e)
            });

        },
    }
}

共有2个答案

萧芷阳
2024-07-15
export default {
    data(){
        return {}
    },
    mounted(){
        this.test();
    },
    methods:{
        async test(){
            let devices = await navigator.mediaDevices.enumerateDevices();
            console.log(devices);
            let videoInputs = devices.filter(device => device.kind === 'videoinput');

            if (videoInputs.length < 3) {
                console.log('Not enough video inputs available.');
                return;
            }

            const startVideoStream = async (deviceId, elementId) => {
                try {
                    let stream = await navigator.mediaDevices.getUserMedia({ video: { deviceId } });
                    document.getElementById(elementId).srcObject = stream;
                } catch (error) {
                    console.log(`Error accessing video input ${deviceId}:`, error);
                }
            };

            await startVideoStream(videoInputs[0].deviceId, 'v0');
            await startVideoStream(videoInputs[1].deviceId, 'v1');
            await startVideoStream(videoInputs[2].deviceId, 'v2');
        },
    }
}
厉坚
2024-07-15

回答

navigator.mediaDevices.getUserMedia 方法本身并没有限制只能获取两个摄像头数据。然而,在您的代码中遇到的问题可能与多个因素有关。

首先,错误 DOMException: Could not start video source 通常意味着浏览器无法启动指定的视频源。这可能是由于多种原因造成的,包括但不限于:

  1. 摄像头权限:确保用户已经授权了网站访问摄像头的权限,并且没有因为某些原因(如隐私设置)而阻止了第三个摄像头的访问。
  2. 摄像头硬件问题:第三个摄像头可能存在硬件问题或驱动程序问题,导致无法正常工作。
  3. 浏览器限制:某些浏览器可能限制了同时打开的视频流数量,但这种情况不太常见,并且通常会与内存或系统资源相关。
  4. 系统资源限制:如果系统资源(如CPU、内存或GPU)已经接近或达到上限,那么尝试打开第三个视频流可能会导致失败。
  5. 代码问题:虽然您的代码看起来是正确的,但可能存在一些微妙的错误或遗漏。例如,您没有处理前一个流(如果有的话)的关闭,这可能会导致资源泄露或其他问题。

为了解决您的问题,您可以尝试以下方法:

  1. 检查并重新授予摄像头权限:确保用户已经授权了网站访问所有摄像头的权限。
  2. 检查摄像头硬件:尝试在其他应用程序或操作系统中测试第三个摄像头,以确定其是否正常工作。
  3. 测试其他浏览器和设备:看看问题是否仍然存在,以确定是否与特定的浏览器或设备相关。
  4. 检查系统资源:在尝试打开第三个视频流时,查看系统的CPU、内存和GPU使用情况,以确定是否有资源瓶颈。
  5. 更新代码:在尝试打开新的视频流之前,确保关闭前一个视频流。这可以通过调用 MediaStreamTrack.stop() 方法来实现。

以下是一个更新后的代码示例,它包含了关闭前一个视频流的逻辑:

export default {
    // ...
    methods: {
        async test() {
            // ...

            let streams = []; // 用于存储所有打开的流

            for (let i = 0; i < list.length; i++) {
                // ...

                navigator.mediaDevices.getUserMedia(list[i]).then((stream) => {
                    let element = document.getElementById(`v${i}`);
                    element.srcObject = stream;
                    streams.push(stream); // 将流添加到数组中
                }).catch((e) => {
                    console.log('Error', list[i], e);
                    // 如果出现错误,关闭所有已打开的流
                    streams.forEach((stream) => {
                        stream.getTracks().forEach((track) => {
                            track.stop();
                        });
                    });
                });
            }

            // ...
        },
    },
};

注意:在上面的代码中,我添加了一个 streams 数组来存储所有打开的流。如果在尝试打开新的流时发生错误,我将关闭所有已打开的流。这可以防止资源泄露和其他潜在问题。然而,请注意,这种方法可能不适用于所有情况,因为它会关闭所有流,而不仅仅是出错的流。在更复杂的应用程序中,您可能需要更精细地控制流的打开和关闭。

 类似资料:
  • 本类用于展示本地摄像头信号 start(cfg) 开始展示摄像头 具体cfg的类型如下 属性 类型 名称 备注 identifier string 信号源标识符 如传入“”则默认为本地摄像头 width number 组件宽 height number 组件高 needFaceTracker boolean 是否开启人脸检测 skipFaceTrackerNum number 人脸检测帧频 pos

  • 我有三星Galaxy S9,我看到设备上有两个后部物理摄像头。尽管如此,

  • 我试图在一个Jasper报告中显示多个表,我使用子报告来实现这个功能。但我一直在显示几个子报告。实际上,只显示其中一个(第一个)。 以下是我的主report.jrxml: 下面是subjectSubreport.jrxml: 这是printersSubreport.jrxml: 当我切换子报告时,第一个报告正确显示,另一个报告消失。在JasperSoft Studio中,一切都很好,当我将它们导出

  • 二个维度的逻辑 大于35 小于35 本科 1万 2万 非本科 3万 4万 再加一个维度,比如男女,表格要怎么展示?二维表格展示不了,那用哪种方式展示比较好?

  • 我们希望使用后摄像头进行扫描,并选择正确的后摄像头-主摄像头,而不是宽镜头摄像头。 较新的移动设备(例如三星galaxy s10)有几个前后摄像头。调用enumerateDevices()时,我们会得到前后摄像头的列表。我们想从后摄像机列表中选择主摄像机。我们可以使用约束来选择后置摄像机(面向:“环境”),但我们不知道如何区分每个设备的摄像机是主摄像机还是宽镜头摄像机。

  • ActiveReports 报表功能展示-ASP.NET 通过ActiveReports报表控件,您除了可以创建常用的子报表、交叉报表、分组报表、分栏报表、主从报表等商业报表外,还可以创建具备数据筛选、数据过滤、数据钻取、报表互链等交互能力的数据分析报表,并把数据以可视化的方式呈现出来,快速为应用程序添加强大的报表功能。