前端如何錄制屏幕

需求

最近需要做的一個功能就是:通過你的網(wǎng)頁應(yīng)用上的一個按鈕可以錄制當(dāng)前的瀏覽器屏幕,保存成視頻文件,并上傳。這個需求的難點不在于文件的上傳,而是如何去錄制瀏覽器的屏幕,找了大量的資料,回答的都是這么調(diào)用攝像頭和麥克風(fēng)去錄屏,這個錄屏錄得就不是web應(yīng)用的內(nèi)容了。

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

接口

目前找到的接口是chrome的接口chrome.desktopCapture,對于這個接口的描述是:它能用來捕獲屏幕的內(nèi)容, 包含了windows窗口或者tabs。

捕獲屏幕的信息對于用戶來說比較隱私,有很大的安全方面的考慮,所以無法mediaDevices接口獲取屏幕。這個設(shè)計也合理,如果開發(fā)了這個權(quán)限,如果一些網(wǎng)站嵌入了捕獲屏幕的腳本,那么用戶的上網(wǎng)隱私就泄露了。

那對于我們確實需要這個功能的時候,可以怎么去實現(xiàn)呢?
對于Chrome瀏覽器,我們可以寫一個extension應(yīng)用,或者叫插件,通過這個extension來讓我有權(quán)限獲取瀏覽器屏幕。

extension

創(chuàng)建一個extension很簡單,只需要兩個文件:manifest.json和extension.js。
1.創(chuàng)建一個文件夾,放這兩個文件
2.manifest.json中放置的是對于extension的一些描述性信息,里面會指定腳本為extension.js,并且?guī)в袡?quán)限信息。

{
  "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商店中,但是在各個瀏覽器安裝時,生產(chǎn)的key必須是一致的,所以就指定了key值。

3.extension.js中是腳本,腳本中創(chuàng)建一個事件監(jiān)聽,接受從web APP發(fā)來的消息,通過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

調(diào)用extension錄屏

這個是angular版的代碼,創(chuàng)建了一個插件。點擊開始,開始錄制,點擊結(jié)束,生成文件下載到本地。

<button *ngIf="!recording" (click)="startCaptureScreen()">開始錄制</button>
<button *ngIf="recording" (click)="stopCaptureScreen()">結(jié)束錄制</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 開發(fā)與實作 24-打造螢?zāi)讳浻肮δ?chrome.desktopCapture

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,230評論 3 119
  • 無論是小禮服還是晚禮服,只要跟這個“禮”沾邊,價格都不便宜,所以自然心疼愛惜,要好好保護起來。 慵懶收納術(shù)第三十九...
    收了納個Queen閱讀 2,295評論 0 2
  • 沒有經(jīng)歷過什么大的演講,回顧自己幾次上臺的經(jīng)歷,總是差強人意。把文中介紹的步驟套用下來反思。問題主要存在主菜和甜點...
    我是珊珊呀閱讀 247評論 1 1
  • 六六裂變增長實驗室挑戰(zhàn)第二天:學(xué)習(xí)了,海報的制作,及文案的思路,結(jié)合第一天的實操項目一起做了實操 第一次知道 墨刀...
    煜昊閱讀 318評論 0 0
  • 01. 找閨密聊天,一打就是175分鐘。美其名曰:談人生談理想。 我和她性格相似,很多觀點不謀而合。于結(jié)婚這件事的...
    鴨蛋00閱讀 319評論 1 1

友情鏈接更多精彩內(nèi)容