思路
- 获取摄像头权限
navigator.getUserMedia({ video: true }, success(stream), error(error))
- 获取摄像头列表
navigator.mediaDevices.enumerateDevices().then((mediaDevices)=>{})
- 将多个摄像头流数据展示在页面
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {videoElement.srcObject = stream;})
具体代码(以两个为例)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<p>
<button id="open">打开摄像头</button>
<button id="play">播放摄像头</button>
<button id="snap">截取并上传</button>
</p>
<video id="video" autoplay playsinline></video>
<video id="video2" autoplay playsinline></video>
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</body>
<script>
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia; // 获取媒体对象(这里指摄像头)
let currentStream = null,
cameraList = [],
videoElement = document.getElementById("video"),
videoElement2 = document.getElementById("video2");
// 1. 获取摄像头列表
function getCameraList() {
navigator.mediaDevices.enumerateDevices().then((mediaDevices) => {
cameraList = mediaDevices;
console.log(JSON.stringify(mediaDevices));
});
}
/*** 格式如下
[
{
"deviceId": "4d9f6ffec7e62d5d7cf94d8943ff2b7b77de8b531822e7f514416f004079a5c6",
"kind": "videoinput",
"label": "LHT-820BW (0c45:6300)",
"groupId": "cc83dc58f13c88df5a4b96bce0af43a7779179ee54508f71457ea9f900cf93d4"
},
{
"deviceId": "539cbf57edd3ee728c912c222920ee9cc0971373938da4bd43545a92cb9b5c9f",
"kind": "videoinput",
"label": "LHT-820VM31B (0c45:6367)",
"groupId": "49f8c5f91a4880636bbf919ee8c567e416252593a6754d84fac8614f4581e7e4"
},
{
"deviceId": "",
"kind": "audiooutput",
"label": "",
"groupId": "f1f9c2fc668cfe64155c501cbcdee5ef12d76a1b14134db19929a94ef1d93fcf"
}
]
*/
// 2. 切换摄像头
function toggleCamera(deviceId) {
if (currentStream !== null) {
stopMediaTracks(currentStream); // 先停止当前摄像头视频流的播放
}
// 组装数据(固定格式)
const constraints = {
video: {
deviceId: {
exact: deviceId, // 要切换到的设备ID
},
},
audio: false,
};
navigator.mediaDevices
.getUserMedia(constraints) // 传入要切换到的设备
.then((stream) => {
currentStream = stream; // 获取当前视频流
video.srcObject = stream; // 将当前视频流放到video标签里
return navigator.mediaDevices.enumerateDevices(); // 获取设备列表
})
.then((mediaDevices) => {}) // 这里可以再次获取到摄像头设备列表
.catch((error) => {
console.error(error);
});
}
// 2-2. 多摄像头同时播放
function playCamera(deviceId, videoEle, env = null) {
// 组装数据(固定格式)
let constraints = {};
if (!env) {
constraints = {
video: {
deviceId: {
exact: deviceId, // 要切换到的设备ID
},
},
audio: false,
};
} else {
constraints = {
video: {
facingMode: "environment",
},
audio: false,
};
}
navigator.mediaDevices
.getUserMedia(constraints) // 传入要切换到的设备
.then((stream) => {
if (videoEle) videoEle.srcObject = stream; // 将当前视频流放到video标签里
return navigator.mediaDevices.enumerateDevices(); // 获取设备列表
})
.then((mediaDevices) => {}) // 这里可以再次获取到摄像头设备列表
.catch((error) => {
console.error(error);
});
}
// 3. 停止当前视频流的播放
function stopMediaTracks(stream) {
stream.getTracks().forEach((track) => {
track.stop();
});
}
// 运行demo 每隔10秒切换摄像头播放数据 (两个摄像头)
/* getCameraList();
setInterval(() => {
let playCount = 0;
cameraList
.filter((v) => v.deviceId !== "") // 清除空设备
.map((v) => {
if (v.isPlay !== true && playCount === 0) {
toggleCamera(v.deviceId);
v.isPlay = true;
playCount++;
console.log("toggle", v.deviceId);
} else {
v.isPlay = false;
}
});
}, 10000); */
// 获取摄像头权限
document.getElementById("open").onclick = () => {
playCamera(null, null, true);
};
// 运行demo 两个摄像头同时播放
document.getElementById("play").onclick = () => {
getCameraList();
setTimeout(() => {
const devs = cameraList.filter((v) => v.deviceId !== ""); // 清除空设备
playCamera(devs[0].deviceId, document.getElementById("video"));
playCamera(devs[1].deviceId, document.getElementById("video2"));
});
};
// 截图并上传
document.getElementById("snap").addEventListener(
"click",
function () {
const can1 = document.getElementById("canvas1");
const can2 = document.getElementById("canvas2");
const ctx1 = can1.getContext("2d");
const ctx2 = can2.getContext("2d");
// 视频放到canvas里
ctx1.drawImage(videoElement, 0, 0, 200, 150);
ctx2.drawImage(videoElement2, 0, 0, 200, 150);
// 转成图像blob对象 保存在formData里
const fd = new FormData();
can1.toBlob(function (blob) {
fd.append("img1", blob);
});
can2.toBlob(function (blob) {
fd.append("img2", blob);
});
// 上传到接口 有延迟需要等待blob对象转换完成 或者写成Promise方式
setTimeout(() => {
fetch("/api/upload/xxx", {
method: "POST",
body: fd,
});
}, 2000);
},
false
);
</script>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。