前端获取本地摄像头和麦克风并录制为mp4导出其实很简单,只是可能你不太了解相关的知识点,我已经在项目中实战过。
前端获取本地摄像头麦克风,并录制视频
export class VideoRecording { // 录视频mediaRecorder: MediaRecorder | null;stream: MediaStream | null;chunks: any[];endCallback: any[];constructor() {this.mediaRecorder = null; // 录音对象this.stream = null; // 轨道this.chunks = []; // 录制缓存this.endCallback = []; // 结束回调}create() { // 创建一个录制任务return new Promise((resolve, reject) => {this.resetState();navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {this.stream = stream;const mime = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? "video/webm\;codecs=h264" : "video/webm";this.mediaRecorder = new MediaRecorder(stream, { mimeType: mime });resolve({format: mime === "video/webm;codecs=h264" ? 'mp4': 'webm'});}).catch((err) => {reject(err);});});}start() { // 开始return new Promise((resolve, reject) => {this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {mediaRecorder.start();mediaRecorder.addEventListener('dataavailable', (e) => {this.chunks.push(e.data);this.endCallback.forEach((resolve) => {resolve();this.endCallback.shift();});});resolve('');}).catch((err) => {reject(err);});});}stop() { // 结束return new Promise((resolve, reject) => {this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {if (mediaRecorder.state === 'inactive') {return reject({code: 0, message: '已结束'});};mediaRecorder.stop();this.stream.getTracks().forEach((track) => { track.stop(); })this.endCallback.push(resolve);}).catch((err) => {reject(err);});});}download() { // 下载return new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let url = URL.createObjectURL(blob);let a = document.createElement('a');a.href = url;a.download = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video.mp4' : 'video.webm';a.click();resolve(url);}).catch((err) => {reject(err);});});}viewRecording() { // 获取本地播放urlreturn new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let url = URL.createObjectURL(blob);resolve(url);}).catch((err) => {reject(err);});});}toFile() { // 录音缓存转filereturn new Promise((resolve, reject) => {this.handleChunksToBolb().then((blob: Blob) => {let filename = MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video.mp4' : 'video.webm';let fileType = filename.includes('.mp4') ? 'video/mp4' : 'video/webm';resolve(new File([blob], filename, { type: fileType }));}).catch((err) => {reject(err);});});}handleChunksToBolb() { // 录音缓存转bolbreturn new Promise((resolve, reject) => {this.judgeChunksIs().then((chunks: any) => {let blob = new Blob(chunks, { type: MediaRecorder.isTypeSupported("video/webm\;codecs=h264") ? 'video/mp4' : chunks[0].type })resolve(blob);}).catch((err) => {reject(err);});});}judgeChunksIs() { // 判断是否有录音缓存return new Promise((resolve, reject) => {let chunks = this.chunks;if (chunks.length === 0) {return reject({code: 0, message: '没有录制的缓冲'});};return resolve(chunks);});}judgeMediaRecorderIs() { // 判断是否创建录制任务return new Promise((resolve, reject) => {let mediaRecorder = this.mediaRecorder;if (!mediaRecorder) { return reject({code: 0, message: '请先创建一个录制对象'}); };resolve(mediaRecorder);});}setEndCallback(callback) { // 存录音结束回调this.endCallback.push(callback);}resetState() { // 重置状态this.chunks = [];this.mediaRecorder = null;this.stream = null;}
};
实用方法
let myVideoRecording = new VideoRecording();
@params res: {format: 'mp4', type: String; value: 'mp4' | 'webm'; 说明:当前支持的录制格式;
}
myVideoRecording.create().then((res: {format: 'mp4'}) => {// 开始录制myVideoRecording.start();// 可选择自己注册一个结束回调, 也可以调用stop()结束成功后执行下载、播放url、转filelet endRecording = () => {// 下载到本地myVideoRecording.download();// 本地播放urlmyVideoRecording.viewRecording().then((srcObject) => {});// 转file可上传到后台服务器myVideoRecording.toFile().then((file) => {});};// 存结束录音回调函数myVideoRecording.setEndCallback(endRecording);// 手动结束录屏,then后才可以下载、获取本地播放url、转file对象myVideoRecording.stop().then(() => {// 下载到本地myVideoRecording.download();// 本地播放urlmyVideoRecording.viewRecording().then((srcObject) => {});// 转file可上传到后台服务器myVideoRecording.toFile().then((file) => {});});
});