【问题标题】:Can a browser plugin "mitm" the local webcam?浏览器插件可以“mitm”本地网络摄像头吗?
【发布时间】:2020-08-21 05:30:45
【问题描述】:

我想创建一个浏览器扩展程序,允许用户在任何使用 javascript Web api 的网站上为他们的视频/音频流添加效果,而无需特殊插件。

Google 搜索并不是特别有用,所以我开始怀疑这是否可能。

我有两个主要问题:

  1. 这可以用javascript+chrome实现吗?

  2. 非常感谢任何指向其他资源的链接。

【问题讨论】:

  • 为什么投反对票?

标签: javascript getusermedia browser-extension mediastream


【解决方案1】:

我并不是很喜欢网络扩展,所以甚至可能有一个更简单的 API 可用,我不会详细介绍实现,但理论上你确实可以做到。

只需覆盖获取 MediaStream 的方法,将原始 MediaStream 绘制到可以应用过滤器的 HTML 画布上,然后简单地返回一个由以下组成的新 MediaStream来自 canvas 元素 captureStream() 的 MediaStream 的 VideoTrack,可能还有来自原始 MediaStream 的其他轨道。

gUM 的一个非常基本的概念证明实现可能如下所示:

// overrides getUserMedia so it applies an invert filter on the videoTrack
{
  const mediaDevices = navigator.mediaDevices;
  const original_gUM = mediaDevices.getUserMedia.bind(mediaDevices);
  
  mediaDevices.getUserMedia = async (...args) => {
    const original_stream = await original_gUM(...args);

    // no video track, no filter
    if( !original_stream.getVideoTracks().length ) {
      return original_stream;
    }

    // prepare our DOM elements
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const video = document.createElement('video');
    // a flag to know if we should keep drawing on the canvas or not
    let should_draw = true;

    // no need for audio there
    video.muted = true;
    // gUM video tracks can change size
    video.onresize = (evt) => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
    };
    // in case users blocks the camera?
    video.onpause = (evt) => {
      should_draw = false;
    };
    video.onplaying = (evt) => {
      should_draw = true;
      drawVideoToCanvas();
    };
    
    video.srcObject = original_stream;
    
    await video.play();

    const canvas_track = canvas.captureStream().getVideoTracks()[0];
    const originalStop = canvas_track.stop.bind(canvas_track);
    // override the #stop method so we can revoke the camera stream
    canvas_track.stop = () => {
      originalStop();
      should_draw = false;
      original_stream.getVideoTracks()[0].stop();
    };

    // merge with audio tracks
    return new MediaStream( original_stream.getAudioTracks().concat( canvas_track ) );
    
    // the drawing loop
    function drawVideoToCanvas() {
      if(!should_draw) {
        return;
      }
      ctx.filter = "none";
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.filter = "invert(100%)";
      ctx.drawImage(video,0,0);
      requestAnimationFrame( drawVideoToCanvas );
    }

  };
}

然后每个调用此方法的脚本都会收到一个过滤后的 videoTrack。

Outsourced example since gUM is not friend with StackSnippets.

现在我不确定如何覆盖网络扩展中的方法,您必须自己学习,并注意这个脚本实际上只是一个概念证明,还没有准备好投入生产。除了演示案例,我什么都没做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多