我使用"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设备
- 运行Mobile Safari的iOS设备:
device.label
项目均本地化为当前选定的国家语言 - 设备总是按此顺序出现在设备阵列中,前置摄像头总是作为
device.kind:'videoinput'
阵列中的第一个设备出现。以下是我从我尝试过的每台iOS设备上获得的设备标签列表,auf Deutsch:- 音频输入:iPhone Mikrofon
- 视频输入:Frontkamera
- 视频输入:Rückkamera
- 有些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
安卓设备
Android设备:"device.label"项目是非本地化的。
我查看的设备有不同的设备标签列表。但我发现的所有相机的设备标签中都有字符串
front
或back
运行Android 11的Pixel 3A有以下设备列表。
- 音频输入:标准
- 音频输入:扬声器
- 音频输入:耳机
- 视频输入:摄像头2 1,正面
- 视频输入:camera2 0,面朝后
- 音频输出:标准
运行安卓9的三星SM-A205F有这些设备。
- 音频输入:默认
- 音频输入:扬声器
- 音频输入:耳机
- 视频输入:摄像头2 1,正面
- 视频输入:摄像头2 2,正面
- 视频输入:camera2 0,面朝后
- 音频输出:默认
这个列举了两个不同的正面自拍器。第一个提供了比第二个更高的分辨率。
运行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",就不能保证。。