第7章 摄像头访问
在本章中,我们将学习如何通过RecordRTC访问和使用摄像头设备,包括设备枚举、约束设置和错误处理。
7.1 摄像头访问基础
访问摄像头是使用RecordRTC进行视频录制的前提,需要正确获取媒体流:
基本摄像头访问
// 基本摄像头访问
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(function(stream) {
// 成功获取媒体流
console.log('摄像头访问成功');
// 显示预览
const video = document.getElementById('preview');
video.srcObject = stream;
// 初始化RecordRTC
const recorder = RecordRTC(stream, {
type: 'video'
});
}).catch(function(error) {
// 处理错误
console.error('摄像头访问失败:', error);
});
7.2 设备枚举
可以枚举所有可用的摄像头设备:
设备枚举
// 枚举摄像头设备
async function enumerateCameras() {
try {
// 获取所有媒体设备
const devices = await navigator.mediaDevices.enumerateDevices();
// 筛选出视频输入设备
const videoDevices = devices.filter(device =>
device.kind === 'videoinput'
);
console.log('可用的摄像头设备:', videoDevices);
// 显示设备列表
const select = document.getElementById('cameraSelect');
videoDevices.forEach((device, index) => {
const option = document.createElement('option');
option.value = device.deviceId;
option.text = device.label || `摄像头 ${index + 1}`;
select.appendChild(option);
});
return videoDevices;
} catch (error) {
console.error('枚举设备失败:', error);
}
}
7.3 摄像头约束设置
可以通过约束条件精确控制摄像头的行为:
摄像头约束设置
// 摄像头约束设置
const cameraConstraints = {
video: {
// 分辨率约束
width: { ideal: 1280 },
height: { ideal: 720 },
// 帧率约束
frameRate: { ideal: 30 },
// 摄像头选择
facingMode: 'user', // 'user' 前置摄像头, 'environment' 后置摄像头
// 特定设备
// deviceId: 'specific-device-id'
// 高级约束
aspectRatio: 16/9,
resizeMode: 'none'
},
audio: {
// 音频约束
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
};
// 使用约束获取媒体流
navigator.mediaDevices.getUserMedia(cameraConstraints)
.then(function(stream) {
// 处理媒体流
console.log('使用约束获取媒体流成功');
})
.catch(function(error) {
console.error('获取媒体流失败:', error);
});
7.4 多摄像头支持
可以同时使用多个摄像头:
多摄像头支持
// 多摄像头管理器
class MultiCameraManager {
constructor() {
this.streams = [];
this.recorders = [];
}
// 添加摄像头
async addCamera(deviceId) {
try {
const constraints = {
video: {
deviceId: deviceId ? { exact: deviceId } : undefined
},
audio: false
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
this.streams.push(stream);
// 创建对应的录制器
const recorder = RecordRTC(stream, {
type: 'video',
mimeType: 'video/webm'
});
this.recorders.push(recorder);
return stream;
} catch (error) {
console.error('添加摄像头失败:', error);
}
}
// 开始录制所有摄像头
startAllRecording() {
this.recorders.forEach(recorder => {
recorder.startRecording();
});
}
// 停止录制所有摄像头
stopAllRecording(callback) {
const blobs = [];
this.recorders.forEach((recorder, index) => {
recorder.stopRecording(() => {
const blob = recorder.getBlob();
blobs.push({
index: index,
blob: blob,
stream: this.streams[index]
});
// 如果所有录制都完成了
if (blobs.length === this.recorders.length) {
callback(blobs);
}
});
});
}
// 释放所有资源
releaseAll() {
this.streams.forEach(stream => {
stream.getTracks().forEach(track => track.stop());
});
this.streams = [];
this.recorders = [];
}
}
7.5 摄像头错误处理
正确处理摄像头访问中的各种错误:
错误处理
// 摄像头错误处理
async function handleCameraAccess() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
// 成功处理
setupCameraStream(stream);
} catch (error) {
// 根据错误类型处理
switch (error.name) {
case 'NotAllowedError':
console.error('用户拒绝了摄像头访问权限');
showPermissionMessage();
break;
case 'NotFoundError':
console.error('未找到摄像头设备');
showDeviceNotFoundMessage();
break;
case 'NotReadableError':
console.error('摄像头设备无法读取');
showDeviceBusyMessage();
break;
case 'OverconstrainedError':
console.error('摄像头约束条件无法满足');
showConstraintErrorMessage();
break;
default:
console.error('摄像头访问未知错误:', error);
showGenericErrorMessage();
}
}
}
// 显示权限提示
function showPermissionMessage() {
alert('请允许访问摄像头和麦克风权限以继续使用录制功能。');
}
// 显示设备未找到提示
function showDeviceNotFoundMessage() {
alert('未检测到摄像头设备,请检查设备连接。');
}
7.6 摄像头预览和控制
实现摄像头预览和控制功能:
摄像头控制
// 摄像头控制器
class CameraController {
constructor(videoElementId) {
this.videoElement = document.getElementById(videoElementId);
this.stream = null;
this.recorder = null;
}
// 开始摄像头预览
async startPreview() {
try {
this.stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
this.videoElement.srcObject = this.stream;
return this.stream;
} catch (error) {
console.error('启动预览失败:', error);
}
}
// 切换摄像头
async switchCamera(deviceId) {
// 停止当前流
if (this.stream) {
this.stream.getTracks().forEach(track => track.stop());
}
// 获取新流
try {
const constraints = {
video: {
deviceId: deviceId ? { exact: deviceId } : undefined
},
audio: true
};
this.stream = await navigator.mediaDevices.getUserMedia(constraints);
this.videoElement.srcObject = this.stream;
} catch (error) {
console.error('切换摄像头失败:', error);
}
}
// 调整摄像头设置
adjustSettings(brightness, contrast, saturation) {
if (this.stream) {
const videoTrack = this.stream.getVideoTracks()[0];
const capabilities = videoTrack.getCapabilities();
// 检查是否支持这些设置
if (capabilities.brightness) {
videoTrack.applyConstraints({
advanced: [{ brightness: brightness }]
});
}
}
}
// 停止摄像头
stopCamera() {
if (this.stream) {
this.stream.getTracks().forEach(track => track.stop());
this.stream = null;
this.videoElement.srcObject = null;
}
}
}