前端如何录制屏幕

作者: 前端进城打工仔 | 来源:发表于2018-11-21 17:54 被阅读110次

    需求

    最近需要做的一个功能就是:通过你的网页应用上的一个按钮可以录制当前的浏览器屏幕,保存成视频文件,并上传。这个需求的难点不在于文件的上传,而是如何去录制浏览器的屏幕,找了大量的资料,回答的都是这么调用摄像头和麦克风去录屏,这个录屏录得就不是web应用的内容了。

    在做了很多探索以后,目前唯一可行的方案如下:(如果有别的方案欢迎交流)

    接口

    目前找到的接口是chrome的接口chrome.desktopCapture,对于这个接口的描述是:它能用来捕获屏幕的内容, 包含了windows窗口或者tabs。

    捕获屏幕的信息对于用户来说比较隐私,有很大的安全方面的考虑,所以无法mediaDevices接口获取屏幕。这个设计也合理,如果开发了这个权限,如果一些网站嵌入了捕获屏幕的脚本,那么用户的上网隐私就泄露了。

    那对于我们确实需要这个功能的时候,可以怎么去实现呢?
    对于Chrome浏览器,我们可以写一个extension应用,或者叫插件,通过这个extension来让我有权限获取浏览器屏幕。

    extension

    创建一个extension很简单,只需要两个文件:manifest.json和extension.js。
    1.创建一个文件夹,放这两个文件
    2.manifest.json中放置的是对于extension的一些描述性信息,里面会指定脚本为extension.js,并且带有权限信息。

    {
      "name": "Desktop Capture",
      "description": "Allows you to capture your desktop for use in video applications",
      "version": "0.1.0",
      "manifest_version": 2,
      "background": {
        "scripts": ["extension.js"],
        "persistent": false
      },
      "externally_connectable": {
        "matches": [
          "*://localhost/*"
        ]
      },
      "permissions": ["desktopCapture"],
      "key": ""
    }
    
    

    一般的extension可以不用指定key,在上传extension到chrome上时会自动配置。点击下图的pack extension可以打包extension,会自动补上pem文件包含private key。


    image.png

    我的extension中指定了key,因为我的extension没有上传到chrome的extension商店中,但是在各个浏览器安装时,生产的key必须是一致的,所以就指定了key值。

    3.extension.js中是脚本,脚本中创建一个事件监听,接受从web APP发来的消息,通过chrome.desktopCapture.chooseDesktopMedia弹出选择屏幕选择框,包含“screen”、“window”、 “tab”和 “audio”。

    chrome.runtime.onMessageExternal.addListener(
      (message, sender, sendResponse) => {
        if (message == 'version') {
          sendResponse({
            type: 'success',
            version: '0.1.0'
          });
          return true;
        }
        const sources = message.sources;
        const tab = sender.tab;
        chrome.desktopCapture.chooseDesktopMedia(sources, tab, streamId => {
          if (!streamId) {
            sendResponse({
              type: 'error',
              message: 'Failed to get stream ID'
            });
          } else {
            sendResponse({
              type: 'success',
              streamId: streamId
            });
          }
        });
        return true;
      }
    );
    

    上传extension

    打开chrome://extensions/
    点击打开developer mode,然后点击Load unpacked,上传我们的extension文件夹。会看到下图一样的extension。

    image.png

    调用extension录屏

    这个是angular版的代码,创建了一个插件。点击开始,开始录制,点击结束,生成文件下载到本地。

    <button *ngIf="!recording" (click)="startCaptureScreen()">开始录制</button>
    <button *ngIf="recording" (click)="stopCaptureScreen()">结束录制</button>
    
    
    import { Component, OnInit } from '@angular/core';
    
    declare var MediaRecorder: any;
    declare var chrome: any;
    
    @Component({
      selector: 'app-screen-capture',
      templateUrl: './screen-capture.component.html',
      styleUrls: ['./screen-capture.component.scss']
    })
    export class ScreenCaptureComponent implements OnInit {
      public recording = false;
      public recordedBlobs = [];
      public EXTENSION_ID = 'XXXXXXX';
    
      public mediaRecorder;
      public stream;
    
      constructor() {}
    
      ngOnInit() {}
    
      download() {
        const blob = new Blob(this.recordedBlobs, { type: 'video/mp4' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        document.body.appendChild(a);
        a.style.display = 'none';
        a.href = url;
        a.download = 'test.mp4';
        a.click();
        window.URL.revokeObjectURL(url);
      }
    
      stopCaptureScreen() {
        this.stream.getTracks().forEach(track => track.stop());
        this.recording = false;
        this.mediaRecorder.stop();
      }
    
      startCaptureScreen() {
        this.recording = true;
        const request = { sources: ['window', 'tab'] };
        chrome.runtime.sendMessage(this.EXTENSION_ID, request, response => {
          if (!response) {
            console.log('No extension');
            return;
          }
          if (response && response.type === 'success') {
            navigator.mediaDevices
              .getUserMedia({
                video: {
                  mandatory: {
                    chromeMediaSource: 'desktop',
                    chromeMediaSourceId: response.streamId
                  }
                } as MediaTrackConstraints
              })
              .then(returnedStream => {
                this.stream = returnedStream;
                const options = {
                  audioBitsPerSecond: 128000,
                  videoBitsPerSecond: 2500000,
                  mimeType: 'video/webm'
                };
                this.mediaRecorder = new MediaRecorder(this.stream, options);
    
                this.mediaRecorder.ondataavailable = event => {
                  if (event.data.size > 0) {
                    this.recordedBlobs.push(event.data);
                    this.download();
                  }
                };
                this.mediaRecorder.start();
              })
              .catch(err => {
                console.error('Could not get stream: ', err);
              });
          } else {
            console.error('Could not get stream');
          }
        });
      }
    }
    
    

    参考文章:
    Screen capture in Google Chrome
    Chrome Extension 開發與實作 24-打造螢幕錄影功能 chrome.desktopCapture

    相关文章

      网友评论

        本文标题:前端如何录制屏幕

        本文链接:https://www.haomeiwen.com/subject/ujucqqtx.html