React + ts + react-webcam + CamSplitter 实现虚拟摄像头解决win摄像头独占的问题

一、安装 CamSplitter

这块网上有很多教程了,这里不再赘述,就一点,需要分几个虚拟摄像头,就要在CamSplitter 的安装目录下 driver_install.cmd 执行几次。

二、React + ts + react-webcam 调用虚拟摄像头

TypeScript 复制代码
import { useState, useEffect, useCallback, useMemo } from "react";
import Webcam from "react-webcam";

interface DeviceInfo {
  deviceId: string;
  label: string;
  kind: string;
}

export const VirtualCameraViewer = () => {
  const [_, setDevices] = useState<DeviceInfo[]>([]);
  const [selectedDevice, setSelectedDevice] = useState<string | null>(null);

  //这里实现了跨系统的适配
  const systemSpecificConstraints = useMemo(() => {
    const isLinux = navigator.userAgent.includes("Linux");
    const isWindows = navigator.userAgent.includes("Windows");

    if (isLinux) {
      return {
        width: { ideal: 640 },
        height: { ideal: 480 },
        frameRate: { ideal: 15 },
        facingMode: "environment",
      };
    } else if (isWindows) {
      return {
        width: { ideal: 640 },
        height: { ideal: 480 },
        frameRate: { ideal: 30 },
        facingMode: "user",
      };
    }
    return {};
  }, [navigator.userAgent]);

  // 必须先请求摄像头权限才能获取完整设备信息
  async function initCamera() {
    try {
      //浏览器webRTC 请求摄像头权限
      const stream = await navigator.mediaDevices.getUserMedia({ video: true });
      stream.getTracks().forEach((track) => track.stop()); // 释放初始流
      //获取摄像头列表
      const devices = await navigator.mediaDevices.enumerateDevices();
      //过滤出来虚拟摄像头 这里 linux系统可以使用 v4l2loopback实现
      //v4l2loopback label 包含 Virtual。
      //CamSplitter的虚拟摄像头默认名称为CamSplitter #1,CamSplitter #2
      const cameras = devices.filter(
        (d) =>
          d.kind === "videoinput" &&
          (d.label.includes("Virtual") || d.label.includes("CamSplitter"))
      );
      console.log("摄像头列表:", cameras); // 检查label和deviceId
      handleDevices(cameras);
    } catch (error) {
      console.error("权限获取失败:", error);
    }
  }

  const handleDevices = useCallback((mediaDevices: MediaDeviceInfo[]) => {
    setDevices(mediaDevices);
    if (mediaDevices.length > 0) {
      setSelectedDevice(mediaDevices[0].deviceId);
    }
  }, []);

  useEffect(() => {
    initCamera();
  }, [handleDevices]);

  return (
    <>
      {selectedDevice && (
        <Webcam
          audio={false}
          videoConstraints={
            selectedDevice
              ? {
                  ...systemSpecificConstraints,
                  deviceId: { exact: selectedDevice },
                }
              : { ...systemSpecificConstraints }
          }
        />
      )}
    </>
  );
};

上面就实现了一个简单 的 浏览器通过webRTC 调用虚拟摄像头,避免摄像头被占用的问题。

注意:1、webRTC只有现代浏览器支持,成熟方案应该考虑老旧版本浏览器不支持webRTC的问题。

2、考虑摄像头流资源释放问题。

3、浏览器调用摄像头,第一次要获取权限。

4、CamSplitter 要读取真实的摄像头流并最小化。

相关推荐
NiceCloud喜云5 小时前
Opus 4.8 的 Effort Control 怎么选:Low 到 Max 五档策略
android·java·大数据·前端·c++·python·spring
wordbaby6 小时前
React Native + RNOH:跨页面数据回传的最佳实践与避坑指南
前端·react native
丷丩6 小时前
MapLibre GL JS第22课:查看本地GeoJSON
前端·javascript·map·mapbox·maplibre gl js
Front思7 小时前
AI前端工程师需要具备能力+
前端·人工智能·ai
ZC跨境爬虫9 小时前
跟着 MDN 学CSS day_29:(掌握文本与字体样式的核心艺术)
前端·css·ui·html·tensorflow
李子琪。9 小时前
网络空间安全深度实战:CSRF 漏洞原理剖析与基于 Token 的纵深防御体系构建(全栈实验报告)
前端·安全·csrf
冰暮流星10 小时前
javascript之history对象介绍
前端·笔记
IT_陈寒10 小时前
Vite热更新失灵?你可能漏了这个配置
前端·人工智能·后端
丷丩10 小时前
MapLibre GL JS第19课:实时更新要素
前端·javascript·gis·map·mapbox·maplibre gl js
Mr.Daozhi10 小时前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具