如何在JavaScript中仅获取物理视频输入设备?
如何在Web应用中过滤虚拟摄像头,仅获取物理摄像头
目前Web API没有提供直接区分物理/虚拟摄像头的原生方法,但可以通过以下两种更可靠的方案来过滤虚拟设备:
方案一:利用groupId关联音频与视频设备
物理摄像头通常和同一硬件设备的麦克风共享相同的groupId(比如笔记本内置的摄像头和麦克风),而虚拟摄像头一般没有对应的关联音频设备。基于这个特性可以过滤:
// 先请求媒体权限,确保能获取完整的设备信息 await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); // 获取所有设备列表 const allDevices = await navigator.mediaDevices.enumerateDevices(); // 提取所有音频输入设备的groupId,存入集合 const audioGroupIds = new Set( allDevices.filter(device => device.kind === 'audioinput').map(device => device.groupId) ); // 过滤视频设备:仅保留groupId存在于音频集合中的设备 const physicalVideoDevices = allDevices.filter( device => device.kind === 'videoinput' && audioGroupIds.has(device.groupId) );
局限性:如果是单独的外接摄像头(无内置麦克风),会被误过滤,但这种场景相对少见,大部分常规物理设备都适用。
方案二:捕获设备流并检查硬件能力
物理摄像头通常支持更多硬件级控制(比如自动曝光、自动对焦),虚拟摄像头一般不具备这些能力。可以通过捕获每个设备的流,检查其硬件能力来判断:
async function getPhysicalVideoDevices() { // 先获取权限 await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); // 获取所有视频输入设备 const allVideoDevices = (await navigator.mediaDevices.enumerateDevices()).filter( device => device.kind === 'videoinput' ); const physicalDevices = []; for (const device of allVideoDevices) { try { // 单独捕获当前设备的视频流 const stream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: device.deviceId } } }); const videoTrack = stream.getVideoTracks()[0]; const capabilities = videoTrack.getCapabilities(); // 检查是否具备物理摄像头特有的硬件能力 const hasPhysicalCapabilities = capabilities.exposureMode?.includes('continuous') || capabilities.focusMode?.includes('continuous'); if (hasPhysicalCapabilities) { physicalDevices.push(device); } // 释放资源 videoTrack.stop(); } catch (err) { // 捕获失败的设备大概率是虚拟设备或无权限,直接跳过 continue; } } return physicalDevices; } // 使用示例 const physicalCameras = await getPhysicalVideoDevices();
优势:准确率更高,能识别单独的外接摄像头;注意:需要逐个捕获设备流,会短暂占用设备,但用完后立即释放,对用户体验影响极小。
内容的提问来源于stack exchange,提问作者Shehan DMG
相关产品推荐
相关产品推荐

