虚拟摄像头

简述:在Unity中实现Camera画面输出到虚拟摄像头,然后让其他应用程序来读取虚拟摄像头画面(如:OBS)。

原生Unity是实现不了这个功能的,只能使用第三方语言来操作。

1.  下载UnityCam并运行

Github链接

  1. 下载此工程压缩包,然后解压缩。
  2. 进入RunMe First文件夹,根据电脑版本选择x32还是x64
  3. 以管理员运行Register.bat,会出现弹窗提示成功。
  4. Unity打开运行UnitySample工程。
  5. 运行CubeScene
  6. 打开第三方程序(OBS),捕获UnityCam摄像头,然后启动虚拟摄像头

这样就能看到Unity输出了一个虚拟摄像头,并能让第三方应用程序进行获取。

UnityCam默认输出的是1280*720的分辨率,所以第三方应用程序捕获的也是这个分辨率。

但是项目中往往需要1920*1080的分辨率,所以就需要修改一下c++工程并重新编译一个dll。

2. 重新编译

进入UnityWebcam文件夹,使用VS2017打开UnityWebcam.sln

2.1 重定向解决方案

  1. 找到解决方案资源管理器,右键UnityWebcam解决方案,选择属性,可以在常规中看到Windows SDK版本10.0.18362.0
  2. 点击工具栏中的项目,选择重定解决方案目标。根据自己的VS环境选择一个Windows SDK版本(本文使用的是10.0.19041.0)。点击确定按钮。

2.2 编译UnityWebCam解决方案(可选)

UnityWebCam解决方案并不涉及虚拟摄像头分辨率相关的东西,所以如果不想编译的话可以略过。

2.2.1 添加目录

解决方案资源管理器中,右键UnityWebcam解决方案,选择属性。找到VC++目录,包含目录、引用目录、库目录,都添加一个UnityCam→UnityWebcam→UnityWebcam这个目录(就是选择UnityCam工程里面的文件夹目录)。

2.2.2 解决报错问题

这个时候选择重新生成,还是会报上面的错误。

2.2.2.1 “SendTexture”:不允许重载函数的第二个C链接

UnityWebcam解决方案中,分别找到UnityAPI.cppUnityAPI.h并双击打开。

注释掉UnityAPI.h文件中的第11行:

//extern "C" __declspec(dllexport) bool SendTexture(const unsigned char* data, int width, int height);

注释掉UnityAPI.cpp文件中的33-38行:

//extern "C" __declspec(dllexport) bool SendTexture(const unsigned char* data, int width, int height)
//{
//	if (!wrapper)
//		wrapper = new SharedImageWrapper();
//	wrapper->SendImage(data, width, height);
//}
2.2.2.2 语法错误:缺少";"(在"*"的前面);缺少类型说明符 - 假定为int。注意:c++不支持默认int

打开UnityAPI.h文件,在顶部添加代码:

#include "SharedImageWrapper.h"
using namespace mray;

2.2.3 编译

根据需要选择DebugReleaseWin32x64版本。编译最终输出的文件夹就在Win32x64文件夹中。

编译好后文件夹中会有一个UnityWebcam.dll的文件,但是在RunMe First文件夹中却是UnityCamService.dll文件,所以最后需要再编译UnityCamService解决方案。

2.3 编译UnityCamService解决方案*

2.3.1 解决报错问题

此时右键UnityCamService解决方案并选择重新生成,会出现一些错误:

  1. 编译UnityWebcam解决方案添加目录一样,右键UnityCamService解决方案,然后给三个目录都添加UnityWebcam→UnityCamService这个文件夹。
  2. 右键UnityCamService解决方案,找到链接器输入附加依赖项,添加legacy_stdio_definitions.lib

2.3.2 修改虚拟摄像头输出的分辨率

找到CaptureSource.cpp文件并双击打开。

  1. 修改第7行的DEFAULT_WIDTH参数为1920。
  2. 修改第8行的DEFAULT_HEIGHT参数为1080。
  3. 修改第11行(MAX_WIDTH)、第12行(MAX_HEIGHT)的参数分别为1920、1080。
  4. 可选)第13行(MAX_FPS)、第14行(MIN_FPS)、第18行(DEFAULT_FPS)可设置为自己需要的FPS。
  5. 修改第539行、第540行分别为m_iPrefWidthm_iPrefHeight。下图是修改后的样子:

重新生成 UnityCamService解决方案,并选择DebugReleaseWin32x64版本。

将生成好的UnityCamService.dll复制到RunMe First文件夹中并替换旧有的dll。先Unregister.batRegister.bat

到此,虚拟摄像头的分辨率就重新设置好了。

3. dll复制到新设备使用

经过上面的步骤重新编译了dll后,可能需要把新的dll放到另外一台电脑上进行使用。当双击运行Register.bat时有可能会出现dll注册失败的弹窗提示。

这时就需要在使用的电脑上安装VS(2017、2019、2022都行),然后勾选.Net桌面开发使用C++的桌面开发,并根据编译时使用的Windows 10 SDK 版本来勾选对应的版本。

如:编译时使用的Win10 SDK是10.0.19041.0,那么就勾选右侧的10.0.17134.0。总之就是要选一个最靠近你编译版本的win10 SDK。

4. OBS代码自动运行虚拟摄像头(可选)

obs软件的设置里面是没有自动运行操作的,某些场景下:如电脑开机后自动运行Unity程序并且运行obs来获取Unity虚拟摄像头的话,那么就需要obs在被打开后自动运行虚拟摄像头。

操作步骤:

  1. obs先设置好场景,也就是要打开的摄像头之类的。
  2. 设置websocket。在"工具"→"WebSocket服务器设置"中进行设置。
  3. 运行python脚本。点击下载工程→ObsVirtualCam.zip 

Python工程目录如下:

venv是虚拟环境,可以自行删除或重新设置。

config.ini是连接obs的websocket配置。配置项主要是ip、端口、websocket密码。

requirements.txt是依赖性。工程初始化的时候可以重新安装一次。

StartVirtualCam.py、StopVirtualCam.py两个脚本分别是控制obs虚拟摄像头开关的。