前端调用高拍仪的时候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: { ideal: 4096 },
height: { ideal: 2160 }
}
}
);
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'));
}
});
}
调用摄像头如何速度方面加快一些,能够适配多种类型的高拍仪
对于你遇到的问题,以下是可能的解决方案和优化建议:
处理 OverconstrainedError
:
OverconstrainedError
通常表示请求的媒体约束(如分辨率、帧率等)超出了设备的支持范围。为了解决这个问题,你可以:
ideal
而不是 exact
约束,这样可以允许浏览器选择最接近请求值的可用设置。getCapabilities()
方法检测摄像头的支持能力,并据此设置合理的约束。优化调用速度:
getUserMedia
请求,例如,你可以在用户选择摄像头后再请求视频流。async/await
)来避免阻塞主线程,提高应用性能。适配多种类型的高拍仪:
enumerateDevices()
:通过 enumerateDevices()
方法列出所有可用的媒体输入和输出设备,让用户选择他们想要使用的设备。device.kind
属性来确定设备类型(如视频输入设备、音频输入设备等),并据此提供不同的选项或界面。代码优化:
navigator.mediaDevices.getUserMedia
和一些过时的 API(如 navigator.webkitGetUserMedia
、navigator.mozGetUserMedia
)。建议只使用标准的 navigator.mediaDevices.getUserMedia
API,因为现代浏览器都支持这个 API。综上所述,通过优化约束设置、减少不必要的请求、异步加载、减少 DOM 操作以及适配多种设备类型,你可以提高前端调用高拍仪的速度和兼容性。
后端 前端 请求报错
[cordova] [cordova] FAILURE: Build failed with an exception. [cordova] [cordova] * What went wrong: [cordova] A problem occurred configuring project ':CordovaLib'. [cordova] > Could not resolve all ar
vitest测试报错? 按照这篇教程我配置了测试环境来测试react组件,但是报错了,不知道为什么? 环境的介绍 用vite来构建我们的项目 安装vitest、jsdom、@testing-library/react、@testing-library/jsdom 在根目录下创建testSetup.js 修改vite.config.js 修改package.json文件 React组件 测试 报错
看不懂。。。 log日志如下
js 代码如下 报错日志: ReferenceError: escodegen is not defined
装了ts的几个依赖就报错了,这是什么错误呢
uniapp小程序上传图片到minio报错信息: 哈哈哈哈哈哈 我想前端直传minio
window.URL 报错,提示 问题出现的原因: 我写了一个工具函数,该函数引入页面报错,通过排查发现是window.URL这一步导致的