getUserMedia检测前置摄像头



我使用"facingMode"约束来在两个相机之间切换,但我无法完全决定用户端是否有"环境"摄像头(背面摄像头)。。仅仅计算返回的promise of enumerateDevices函数的"videoinput"是不够的。

我试着搜索它,我发现的只是使用视频MediaTrack标签并搜索包含";"面朝后";字符串,在所有浏览器(例如IOS)中它似乎都不是常量。

我相信肯定有更好的方法:)

这里是第二个答案。选择正面(facingMode:'user')和背面(facingMode:'environment')相机是我正在研究的一个问题

如果你有一个打开的.getUserMedia()流到一台相机,就可以知道你在使用哪台相机。stream.getTracks[0].getCapabilities()返回一个对象,其中有一个facingMode:'user'facingMode:'environment'字段。但您必须已经向特定设备打开了一个流才能获得它。

以下是我在移动设备测试场中使用多个设备所发现的内容。这些是由.enumerateDevices()产生的device条目的顺序。

tl;dr:在iOs设备上,前置摄像头是列表中的第一个视频输入设备,后置摄像头是第二个在Android设备上,前置摄像头具有字符串";前面的";在它们的CCD_ 9值中;返回";。

iOS设备

  1. 运行Mobile Safari的iOS设备:device.label项目均本地化为当前选定的国家语言
  2. 设备总是按此顺序出现在设备阵列中,前置摄像头总是作为device.kind:'videoinput'阵列中的第一个设备出现。以下是我从我尝试过的每台iOS设备上获得的设备标签列表,auf Deutsch:
    • 音频输入:iPhone Mikrofon
    • 视频输入:Frontkamera
    • 视频输入:Rückkamera
  3. 有些iPhone背面有多个摄像头。尽管如此,Mobile Safari中的MediaStream API仅显示一个摄像头

当时,你可以判断你在iPhone上

navigator.userAgent.indexOf(' iPhone ') >= 0  

时,你可以看出你在iPad上

typeof navigator.maxTouchPoints === 'number' 
&& navigator.maxTouchPoints > 2
&& typeof navigator.vendor === 'string'
&& navigator.vendor.indexOf('Apple') >= 0

注意,iPad Safari现在撒谎并声称它是英特尔Mac。它显示以下用户代理字符串:

Mozilla/5.0(Macintosh;Intel Mac OS X 10_15_6)AppleWebKit/60.1.15(KHTML,类似Gecko)版本/14.0.1 Safari/60.1.15

安卓设备

  1. Android设备:"device.label"项目是本地化的。

  2. 我查看的设备有不同的设备标签列表。但我发现的所有相机的设备标签中都有字符串frontback

  3. 运行Android 11的Pixel 3A有以下设备列表。

    • 音频输入:标准
    • 音频输入:扬声器
    • 音频输入:耳机
    • 视频输入:摄像头2 1,正面
    • 视频输入:camera2 0,面朝后
    • 音频输出:标准
  4. 运行安卓9的三星SM-A205F有这些设备。

    • 音频输入:默认
    • 音频输入:扬声器
    • 音频输入:耳机
    • 视频输入:摄像头2 1,正面
    • 视频输入:摄像头2 2,正面
    • 视频输入:camera2 0,面朝后
    • 音频输出:默认

    这个列举了两个不同的正面自拍器。第一个提供了比第二个更高的分辨率。

  5. 运行Android 6.0.1 的三星SM-G925I

    • 音频输入:默认
    • 音频输入:扬声器
    • 音频输入:耳机
    • 视频输入:摄像头2 1,正面
    • 视频输入:camera2 0,面朝后
    • 音频输出:默认

顺便说一句,.getSupportedConstraints()的结果没有多大帮助:iOS和Android都给出了facingMode:true

根据我的经验,在以英语为默认语言的各种移动设备中,您从enumerateDevices()返回的device.label属性包含用户或环境相机的字符串'front''back'。但在某些设备上,字符串是大写的。因此,您需要以不区分大小写的方式检查这些字符串。

此外,除非用户已授予访问媒体的权限,否则enumerateDevices()会隐藏标签值。在大多数浏览器中,权限是粘性。也就是说,一旦用户将其授予您的网站,它就会保持授予状态。但在Mobile Safari设备上,权限是不粘的:每次加载页面时,用户都必须授予权限。您可以让用户通过getUserMedia()调用授予权限。

这个代码应该让你知道你是否有前置和后置摄像头。

async function hasFrontBack() {
let result = {hasBack: false, hasFront: false, videoDevices: []}
try {
const stream = await navigator.mediaDevices.getUserMedia(
{video: true, audio: false})
let devices = await navigator.mediaDevices.enumerateDevices()
const videoDevices = devices.filter(device => {
if (device.kind === 'videoinput') {
if (device.label && device.label.length > 0) {
if (device.label.toLowerCase().indexOf('back') >= 0) {
result.hasBack = true
} else if (device.label.toLowerCase().indexOf('front') >= 0) {
result.hasFront = true
} else { /* some other device label ... desktop browser? */ }
}
return true
}
return false
})
result.videoDevices = videoDevices
/* drop stream */
const tracks = stream.getTracks()
if (tracks) {
for (let t = 0; t < tracks.length; t++) tracks[t].stop()
}
return result
}
catch (ex) {
/* log and swallow exception, this is a probe only */
console.error(ex)
return result
}
}

一旦得到此结果,就可以再次使用getUserMedia(),而无需再次提示用户获得权限。

要确定我们是否使用移动后置摄像头,请在加载流后使用。目前Firefox不支持getCapabilities()。在MacOS/iOS/Android、Safari/Chrome/FFirefox上测试。

if (stream.getTracks()[0].getCapabilities) {
isBackCamera = stream.getTracks()[0].getCapabilities()?.facingMode?.[0] === 'environment';
}

我找到了一个不错的解决方案,仍然不完美,但可以提供帮助。由MediaStreamTrack应用的约束确定:

MediaStream.getVideoTracks()[0].getConstraints().facingMode

只要你在使用"facingMode"时没有使用"exact",就不能保证。。

最新更新