​Roader​ 2024-12-04 10:01 采纳率: 38.5%
浏览 63
已结题

前端高拍仪调用问题报错

前端调用高拍仪的时候requestMediaPermissions先去获取权限,但是navigator.mediaDevices.getUserMedia调用参数如果改成video: true会报错OverconstrainedError,如果将参数改成 video: {width: 500, height: 500},有的摄像头又不支持也依然报错OverconstrainedError。并且如何优化提高摄像头调用速度
以下是我的代码,初始化的时候调用changeDevice() 这个方法

 async function requestMediaPermissions() {
            if (navigator.mediaDevices === undefined) {
                layer.alert("未检测到设备,请检查是否已接入拍摄仪器或已安装驱动!", { icon: 0 });
                return Promise.reject(new Error("设备未检测到"));
            }

            try {
                const stream = await navigator.mediaDevices.getUserMedia(
                    {
                        audio: false,
                        video: {width: 500, height: 500}
                    }
                );
                console.log("摄像头权限获取成功!");
                return stream;
            } catch (err) {
                console.error("获取摄像头权限失败:", err);
                if (err.name === 'OverconstrainedError') {
                    layer.alert("摄像头权限获取失败,请检查设备是否已连接或已被其他应用占用!", { icon: 0 });
                } else {
                    layer.alert("获取摄像头权限失败,请检查设备或允许权限!", { icon: 0 });
                }
                return Promise.reject(err);
            }
        }
        async function getMediaStream(constraints) {
            try {
                const stream = await navigator.mediaDevices.getUserMedia(constraints);
                return stream;
            } catch (err) {
                console.error("获取摄像头权限失败:", err);
                layer.alert("获取摄像头权限失败,请检查设备或允许权限!", {icon: 0});
                return Promise.reject(err);
            }
        }

        async function changeDevice() {
            tcindex = layer.msg("电子设备加载检测中...", {shade: 0.3});
            try {
                await requestMediaPermissions();
                const devices = await navigator.mediaDevices.enumerateDevices();
                const cameraSelect = document.getElementById('cameraSelect');
                cameraSelect.innerHTML = '';

                const cameraDevices = await Promise.all(devices
                    .filter(device => device.kind === 'videoinput')
                    .map(async device => {
                        try {
                            const stream = await getMediaStream({video: {deviceId: {exact: device.deviceId}}});
                            const tracks = stream.getVideoTracks();
                            if (tracks.length > 0) {
                                let resolution = '未知';
                                // 检查 getCapabilities 是否存在
                                if (typeof tracks[0].getCapabilities === 'function') {
                                    const capabilities = tracks[0].getCapabilities();
                                    if (capabilities.width && capabilities.height) {
                                        resolution = `${capabilities.width.max}x${capabilities.height.max}`;
                                    }
                                } else {
                                    // 如果 getCapabilities 不存在,尝试其他方式获取分辨率
                                    const settings = tracks[0].getSettings();
                                    if (settings.width && settings.height) {
                                        resolution = `${settings.width}x${settings.height}`;
                                    }
                                }
                                stream.getTracks().forEach(track => track.stop());
                                return {device, resolution};
                            }
                            return {device, resolution: '未知'};
                        } catch (err) {
                            console.error("获取摄像头设备信息失败:", err);
                            return {device, resolution: '未知'};
                        }
                    }));

                cameraDevices.sort((a, b) => {
                    const resolutionA = a.resolution.split('x')[0];
                    const resolutionB = b.resolution.split('x')[0];
                    return resolutionB - resolutionA;
                });

                cameraDevices.forEach(camera => {
                    const option = document.createElement('option');
                    option.value = camera.device.deviceId;
                    option.text = camera.device.label || `无名摄像头 (${camera.resolution})`;
                    cameraSelect.appendChild(option);
                });

                layui.use('form', function () {
                    layui.form.render('select');
                    const selectElem = $('#cameraSelect');
                    if (selectElem.find('option').length >= 1) {
                        const firstOptionValue = selectElem.find('option:first').val();
                        console.log('摄像头ID:', firstOptionValue);
                        setCurrentDevice(firstOptionValue);
                    }
                });
            } catch (err) {
                layer.alert(err.name + ": " + err.message, {icon: 2});
            }
        }

        async function setCurrentDevice(deviceId) {
            console.log("ID:" + deviceId)
            const videoConstraints = {};
            if (deviceId === '') {
                videoConstraints.facingMode = 'environment';
            } else {
                videoConstraints.deviceId = {ideal: deviceId}; // 使用 ideal 而不是 exact
            }

            try {
                const stream = await getMediaStream({video: videoConstraints});
                const tracks = stream.getVideoTracks();
                if (tracks.length > 0) {
                    var capabilities;
                    var width;
                    var height;
                    if (typeof tracks[0].getCapabilities === 'function') {
                        capabilities = tracks[0].getCapabilities();
                        width = capabilities.width.max;
                        ttWidth = width;
                        height = capabilities.height.max;
                        ttHeight = height;
                    } else {
                        // 如果 getCapabilities 不存在,尝试其他方式获取分辨率
                        capabilities = tracks[0].getSettings();
                        width = capabilities.width;
                        ttWidth = width;
                        height = capabilities.height;
                        ttHeight = height;
                    }
                    console.log(`摄像头分辨率:${width}x${height}`);
                    stream.getTracks().forEach(track => track.stop());

                    const constraints = {
                        video: {
                            ...videoConstraints,
                            width: {exact: width},
                            height: {exact: height},
                            frameRate: {ideal: FPS}
                        }
                    };

                    // 添加回退选项
                    if (!await getUserMedia(constraints)) {
                        constraints.video.width = {ideal: width};
                        constraints.video.height = {ideal: height};
                        await getUserMedia(constraints);
                    }
                }
            } catch (err) {
                layer.alert(err.name + ": " + err.message, {icon: 2});
            }
        }

        async function getUserMedia(constraints) {
            return new Promise((resolve, reject) => {
                if (navigator.mediaDevices.getUserMedia) {
                    navigator.mediaDevices.getUserMedia(constraints)
                        .then(function (stream) {
                            videoElement.srcObject = stream;
                            videoElement.play();
                            layer.close(tcindex);
                            resolve(true);
                        }).catch(function (error) {
                        console.log(error);
                        layer.alert('摄像头开启失败,请检查摄像头是否可用!', {icon: 2});
                        reject(error);
                    });
                } else if (navigator.webkitGetUserMedia) {
                    navigator.webkitGetUserMedia(constraints, function (stream) {
                        videoElement.srcObject = stream;
                        videoElement.play();
                        layer.close(tcindex);
                        resolve(true);
                    }, function (error) {
                        console.log(error);
                        layer.alert('摄像头开启失败,请检查摄像头是否可用!', {icon: 2});
                        reject(error);
                    });
                } else if (navigator.mozGetUserMedia) {
                    navigator.mozGetUserMedia(constraints, function (stream) {
                        videoElement.srcObject = stream;
                        videoElement.play();
                        layer.close(tcindex);
                        resolve(true);
                    }, function (error) {
                        console.log(error);
                        layer.alert('摄像头开启失败,请检查摄像头是否可用!', {icon: 2});
                        reject(error);
                    });
                } else if (navigator.getUserMedia) {
                    navigator.getUserMedia(constraints, function (stream) {
                        videoElement.srcObject = stream;
                        videoElement.play();
                        layer.close(tcindex);
                        resolve(true);
                    }, function (error) {
                        console.log(error);
                        layer.alert('摄像头开启失败,请检查摄像头是否可用!', {icon: 2});
                        reject(error);
                    });
                } else {
                    reject(new Error('浏览器不支持getUserMedia'));
                }
            });
        }
  • 写回答

30条回答 默认 最新

  • 阿里嘎多学长 2024-12-04 10:13
    关注
    获得0.30元问题酬金

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    前端高拍仪调用问题报错

    你遇到了前端调用高拍仪时的报错问题,具体来说是 navigator.mediaDevices.getUserMedia 调用参数如果改成 video: true 会报错 O

    这个问题可能是因为高拍仪的权限获取问题。高拍仪需要在调用 getUserMedia 方法时指定正确的媒体类型,否则可能会报错。

    可以尝试以下解决方案:

    1. 检查高拍仪的权限是否正确,确保高拍仪已经在浏览器中启用了权限。
    2. 在调用 getUserMedia 方法时,指定正确的媒体类型,例如:
    navigator.mediaDevices.getUserMedia({ video: true, audio: false })
    
    1. 检查浏览器的版本是否支持高拍仪的调用,高拍仪的支持可能会因浏览器版本而异。

    如果以上解决方案都不能解决问题,可以提供更多的错误信息和代码,帮助我更好地 debug。

    评论

报告相同问题?

问题事件

  • 系统已结题 12月12日
  • 修改了问题 12月4日
  • 创建了问题 12月4日