前端实现屏幕录制功能,并给后端发送视频流

该文详细介绍了如何使用navigator.mediaDevices.getDisplayMedia和MediaRecorderAPI在浏览器中实现屏幕录制功能,包括获取用户授权、选择窗口、设置录制参数、处理数据流以及保存和下载录制的视频。此外,还提到了rrweb库作为替代方案,以及canvas元素可能带来的记录问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遇到困难就克服困难
客户有需要,需要在浏览器中进行录屏,然后生成视频,传给后端,保存当前的操作流程,然后进行回看
这里用到了navigator.mediaDevices用来获取需要录制的窗口
首先进行窗口的获取(注:获取窗口是因为安全机制的需要进行授权,如果不想多进行一步这样的操作,可以选择rrweb)
多唠叨一句,rrweb是对与操作的记录,利用的是canvas的原理,只有页面发生变化时才会记录此次操作,但是如果记录的页面有canvas,就会有记录不上的问题

// 屏幕捕获参数
const displayMediaOptions= {
  video: {
    cursor: "always",
  },
  audio: {
    echoCancellation: true,
    noiseSuppression: true,
    sampleRate: 44100,
  },
};
let captureStream = navigator.mediaDevices.getDisplayMedia(displayMediaOptions)

然后进行屏幕的录制

// 找到支持的格式
let recordedBlobs = []
function getSupportedMimeTypes() {
   const possibleTypes = [
     "video/webm;codecs=vp9,opus",
     "video/mp4;codecs=h264,aac",
     "video/webm;codecs=vp8,opus",
     "video/webm;codecs=h264,opus",
   ];
   return possibleTypes.filter((mimeType) => {
     return MediaRecorder.isTypeSupported(mimeType);
   });
 }
const mimeType = this.getSupportedMimeTypes()[0];
const options = { mimeType };
//录制屏幕
let mediaRecorder = new MediaRecorder(captureStream, options);
//设置保存
mediaRecorder.ondataavailable = (event: any) => {
  if (event.data && event.data.size > 0) {
     console.log("handleDataAvailable", event);
     //保存的为二进制
    	recordedBlobs.push(event.data);
   }
 };
//开始录制
mediaRecorder.start();

停止视频的录制

mediaRecorder.stop();

最后进行视频的下载

function downloadVideo() {
  const blob = new Blob(this.recordedBlobs, { type: "video/webm" });
   const url = window.URL.createObjectURL(blob);
   const a = document.createElement("a");
   a.style.display = "none";
   a.href = url;
   a.download = "录屏_" + new Date().getTime() + ".webm";
   document.body.appendChild(a);
   a.click();

   setTimeout(() => {
     document.body.removeChild(a);
     window.URL.revokeObjectURL(url);
   }, 100);
 }

最后对于视频录制功能进行了封装,直接将视频流传给后端

// 屏幕捕获参数
const displayMediaOptions: any = {
  video: {
    cursor: "always",
  },
  audio: {
    echoCancellation: true,
    noiseSuppression: true,
    sampleRate: 44100,
  },
};
// 定义函数
class recordVideo {
  // 保存窗口
  private captureStream: any = null;
  // 保存开始录制的视屏
  private mediaRecorder: any = null;
  //   保存录制视频
  private recordedBlobs: any[] = [];
  constructor() {
    // this.startCapture();
  }
  //   开始捕获
  startCapture() {
    this.recordedBlobs = [];
    var promise = new Promise((resolve: any, reject) => {
      if (!this.captureStream) {
        navigator.mediaDevices
          .getDisplayMedia(displayMediaOptions)
          .then((result: any) => {
            this.captureStream = result;
            console.log("选择窗口后", result);
            this.startRecording(result);
            resolve(true);
          });
      } else {
        this.startRecording(this.captureStream);
        resolve(true);
      }
    });
    return promise;
  //   停止捕获
  stopCapture() {
    let tracks = this.captureStream.getTracks();
    tracks.forEach((track: any) => track.stop());
    this.captureStream = null;
  }
  // 找到支持的格式
  getSupportedMimeTypes() {
    const possibleTypes = [
      "video/webm;codecs=vp9,opus",
      "video/mp4;codecs=h264,aac",
      "video/webm;codecs=vp8,opus",
      "video/webm;codecs=h264,opus",
    ];
    return possibleTypes.filter((mimeType) => {
      return MediaRecorder.isTypeSupported(mimeType);
    });
  }
  // 开始录制
  startRecording(captureStream: any) {
    const mimeType = this.getSupportedMimeTypes()[0];
    const options = { mimeType };
    // console.log(121212, this.captureStream, options);

    try {
      this.mediaRecorder = new MediaRecorder(captureStream, options);
      //   console.log(this.mediaRecorder, "123123");
    } catch (e) {
      //   showMsg(`创建MediaRecorder出错: ${JSON.stringify(e)}`);
      return;
    }
    this.mediaRecorder.ondataavailable = (event: any) => {
      if (event.data && event.data.size > 0) {
        console.log("handleDataAvailable", event);
        this.recordedBlobs.push(event.data);
      }
    };
    this.mediaRecorder.start();
  }
  //   保存
  handleDataAvailable(event: any) {
    console.log("handleDataAvailable", event);
    if (event.data && event.data.size > 0) {
      this.recordedBlobs.push(event.data);
    }
  }
  //   停止录制
  //
  stopRecord(callback: Function) {
    this.mediaRecorder.stop();
    setTimeout(() => {
      callback(this.recordedBlobs);
    }, 1000);
  }
  // 下载视频
  downloadVideo() {
    const blob = new Blob(this.recordedBlobs, { type: "video/webm" });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.style.display = "none";
    a.href = url;
    a.download = "录屏_" + new Date().getTime() + ".webm";
    document.body.appendChild(a);
    a.click();

    setTimeout(() => {
      document.body.removeChild(a);
      window.URL.revokeObjectURL(url);
    }, 100);
  }
}
export default new recordVideo();

调用

recordVideo.startCapture().then(() => {
//获取完屏幕,记录下面的操作,开始录屏
})
//停止录屏
recordVideo.stopRecord((video: any) => {
	const blob = new Blob(video, { type: "video/webm" });
	 let formate = new FormData();
	 formate.append("id", data[0].id);
	 formate.append("file", blob, "video.mp4");
	 //将视频传给后端(formate)
	 。。。
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值