You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何阻止网站被OBS虚拟摄像头注入内容?

有效阻止虚拟摄像头注入内容的方案

以下是几种可落地的技术方案,能在一定程度上识别并拦截虚拟摄像头:

  • 帧动态性检测
    虚拟摄像头常注入静态图片或循环视频,可通过计算连续视频帧的像素差异来识别。如果连续N帧的差异值低于阈值,判定为可疑流。示例代码思路:

    // 获取视频流并绘制到canvas
    const video = document.createElement('video');
    video.srcObject = stream;
    video.play();
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    let prevFrameData = null;
    let staticFrameCount = 0;
    
    setInterval(() => {
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      const currFrameData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
      if (prevFrameData) {
        let diff = 0;
        for (let i = 0; i < currFrameData.length; i += 4) {
          diff += Math.abs(currFrameData[i] - prevFrameData[i]) +
                  Math.abs(currFrameData[i+1] - prevFrameData[i+1]) +
                  Math.abs(currFrameData[i+2] - prevFrameData[i+2]);
        }
        const avgDiff = diff / (canvas.width * canvas.height);
        if (avgDiff < 10) { // 可根据场景调整阈值
          staticFrameCount++;
          if (staticFrameCount > 5) {
            // 判定为静态/循环流,执行拦截逻辑
            console.log('疑似虚拟摄像头');
            stream.getTracks().forEach(track => track.stop());
          }
        } else {
          staticFrameCount = 0;
        }
      }
      prevFrameData = currFrameData;
    }, 100);
    
  • 实时动作验证
    如果你的场景涉及人脸,可要求用户完成简单的互动动作(如眨眼、转头),通过前端AI模型(如TensorFlow.js的FaceLandmarkDetector)检测动作是否完成。虚拟摄像头无法响应实时的动作指令,以此区分真实设备:

    // 示例:用TensorFlow.js检测眨眼动作
    import * as faceLandmarksDetection from '@tensorflow-models/face-landmarks-detection';
    
    async function detectBlink(video) {
      const model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh);
      const predictions = await model.estimateFaces({input: video});
      if (predictions.length > 0) {
        const landmarks = predictions[0].scaledMesh;
        // 计算眼睛开合度(上下眼睑距离)
        const leftEyeTop = landmarks[159];
        const leftEyeBottom = landmarks[145];
        const leftEyeDistance = Math.sqrt(Math.pow(leftEyeTop[0]-leftEyeBottom[0],2) + Math.pow(leftEyeTop[1]-leftEyeBottom[1],2));
        if (leftEyeDistance < 5) { // 阈值根据实际调整
          return true;
        }
      }
      return false;
    }
    
    // 调用:要求用户眨眼,检测到后允许继续
    async function verifyUserAction(video) {
      let blinkDetected = false;
      const timer = setInterval(async () => {
        blinkDetected = await detectBlink(video);
        if (blinkDetected) {
          clearInterval(timer);
          // 验证通过
        } else {
          // 提示用户完成动作
        }
      }, 200);
    }
    
  • 设备元数据分析
    检查摄像头设备的元数据特征,真实物理摄像头通常有唯一的groupId(关联到同一硬件设备的不同能力),而虚拟摄像头可能没有groupId或与其他设备重复。同时可验证帧率、分辨率是否符合真实设备的常见范围:

    navigator.mediaDevices.enumerateDevices().then(devices => {
      const videoDevices = devices.filter(d => d.kind === 'videoinput');
      videoDevices.forEach(device => {
        // 检查groupId是否存在且唯一
        if (!device.groupId || videoDevices.filter(d => d.groupId === device.groupId).length > 2) {
          console.log('疑似虚拟摄像头设备');
        }
      });
    });
    
    // 获取流后检查设置
    stream.getVideoTracks()[0].getSettings().then(settings => {
      // 检查帧率是否在合理范围(如15-60fps)
      if (settings.frameRate < 15 || settings.frameRate > 60) {
        console.log('异常帧率,疑似虚拟摄像头');
      }
    });
    
  • 多维度交叉验证
    单一方法可能存在误判,建议结合多种方式:比如先通过元数据初筛,再进行帧动态检测,最后加上动作验证,大幅提升识别准确率。

需要注意的是,没有100%完美的拦截方案(极端情况下虚拟摄像头也能模拟真实动态),但组合使用上述方法可以覆盖绝大多数场景,有效降低滥用风险。

内容的提问来源于stack exchange,提问作者Izabella Melo

火山引擎 最新活动