前言
该文章记录一下工作中遇到的一些问题,后续将会逐步增加,所有内容均从网上整理而来,加上自己得理解做一个整合,方便工作中使用。
1.需求
- 开启摄像头,生成视频
- 截图
- 关闭摄像头
2.代码
//检测是否有摄像头硬件
const checkForCamera = async () => {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const videoDevices = devices.filter(device => device.kind === 'videoinput');
let hasCamera = videoDevices.length > 0
if (!hasCamera) {
console.log('未检测到摄像头设备,请检查硬件连接!')
}
return hasCamera
} catch (error) {
console.log(error)
}
};
//检测浏览器调用摄像头权限
const checkPermissionStatus = async () => {
if (!navigator.permissions) {
return "unknown"; // 旧浏览器兼容性处理
}
try {
const status = await navigator.permissions.query({
name: "camera"
});
return status;
} catch (err) {
console.error("权限查询失败:", err);
return "unknown";
}
};
//根据摄像头权限状态-处理
const handlePermissionStatus = (status:string) => {
switch (status) {
case "granted":
startCamera(); // 权限允许时启动摄像头
break;
case "denied":
// 权限拒绝时显示引导弹窗
console.log("摄像头权限被拒绝,请在浏览器设置中开启权限");
break;
case "prompt":
// 权限未决(首次请求),尝试获取权限
startCamera();
break;
default:
console.log('浏览器版本不支持!')
break;
}
};
// 启动摄像头
const startCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: 400, height: 260 },
audio: false
});
//MediaStream对象挂载在window上,好全局删除
window.floatCameraMediaStream = stream
//将stream(视频流)赋值给video元素的srcObject属性
if (videoRef.current) {
videoRef.current.srcObject = stream;
videoRef.current.play();
}
} catch (error) {
showPermissionModal('开启摄像头失败!')
setLoading(false);
}
};
// 停止摄像头
const stopCamera = () => {
// 方案一:
let videoStream = window.floatCameraMediaStream
if (videoStream) {
if (typeof videoStream.stop === "function") {
videoStream.stop();
} else {
videoStream.getTracks().forEach(track => track.stop());
}
}
//方案二
if (videoRef.current && videoRef.current.srcObject) {
const stream = videoRef.current.srcObjec;
stream.getTracks().forEach(track => track.stop());
videoRef.current.srcObject = null;
}
};
const init = async ()=>{
try {
//1.检测是否有摄像头
let hasCamera = await checkForCamera()
if(!hasCamera) return
//2.检测权限
let hasRootStatus:any = await checkPermissionStatus()
handlePermissionStatus(hasRootStatus.state)
} catch (error) {
console.log(error)
}finally{
startInterval()
}
}
// 截图功能
const shotImg = async () => {
if (!videoRef.current || !canvasRef.current) return;
try {
const video = videoRef.current;
const canvas = canvasRef.current;
// 适配设备像素比以获得更高清截图
const scale = window.devicePixelRatio || 1;
// 设置canvas尺寸为视频尺寸的2倍(提高清晰度)
canvas.width = video.videoWidth * scale;
canvas.height = video.videoHeight * scale;
// 获取绘图上下文并应用缩放
const ctx = canvas.getContext('2d');
if (ctx) {
// 应用缩放
ctx.scale(scale, scale);
// 启用抗锯齿
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
// 绘制当前视频帧到canvas
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
// 将canvas内容转换为高质量JPEG图片URL
const imageUrl = canvas.toDataURL('image/jpeg', 1); // 质量参数0.95 (0-1)
message.success('截图成功',imageUrl);
}
} catch (error) {
message.error('截图失败,请重试');
}
};