基于USB总线的虚拟摄像头(UVC)原理简介
前面文章中我们分析了虚拟声卡的实现,在文章中我们展示了创建一个虚拟麦克风和虚拟扬声器的技术原理。完成了音频的虚拟化之后,这里就要谈论一下对于视频的虚拟化了——虚拟摄像头的实现。
关于虚拟麦克风和虚拟扬声器的实现,可以参考https://blog.csdn.net/tianxilink/article/details/135170764?spm=1001.2014.3001.5502。
虚拟摄像头应用也是非常普遍的,例如云桌面远程摄像头的实现,直播技术。目前对于虚拟摄像头有三种实现方式:
-
DirectShow虚拟摄像头,这个是一种比较古老的技术;在新版本应用中,该项技术基本失效了,尤其是UWP框架程序,DirectShow虚拟摄像头就失效了。早期很多虚拟摄像头都是采用这种方式来实现,该技术的优点就是简单,实现简单的COM组件就能完成虚拟摄像头了。
-
AVstream流内核虚拟摄像头,该方案基于内核流框架实现,是一种兼容性稳定的实现方案。
-
USB Video Class(UVC)虚拟摄像头,该方案是虚拟USB总线,在虚拟总线模拟插入USB摄像头设备,让系统识别到虚拟的摄像头。
本文我们从USB总线出发,实现USB Video Class(UVC)虚拟摄像头,如下:
1. 技术概览
我们先来看一下USB摄像头的基本框架结构,如下:
从这里我们可以发现,对于一个USB摄像头来说,厂商无需为驱动编写相关硬件驱动,只需要在硬件上面能够支持USB Camera协议即可,其他都交给Windows来完成工作,在该框架中:
- usbport.sys:USB控制器驱动程序。
- usbhub.sys:USB集线器驱动程序。
- usbvideo.sys:将通用视频转换为USB类兼容的驱动。
- ks.sys:微软内核流驱动。
因此我们实现虚拟摄像头,加载的驱动架构如下:
我们只需要完成NanosVirtualBus总线驱动的开发即可,例如加载的设备结构我们可以看到如下:
2. UVC描述符
UVC,全称为:USB video(device) class,是微软与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标准,目前已成为USB org标准之一。
我们一般都用过摄像头,其中使用最广的的就是WebCamera,当厂商生产的摄像头WebCamera接入系统知乎后,USB总线其上报插入USB设备,Windows根据其设备类型判断为视频类驱动,固使用usbvideo.sys来驱动设备,usbvideo对上层Kernel streaming (KS)提供接口,再由KS对应用层提供通过的应用层接口。
厂商只需要遵照UVC协议即可实现生产的摄像头,无需开发任何相关驱动来辅助硬件的运行,因此对于虚拟摄像头来说,我们也无需额外的驱动开发工作,只需要在虚拟总线上面上报USB视频类设备,然后在总线提供相关硬件特性即可,对于USB设备来说,这些特性通过UVC描述符来提供。
因此在我们的驱动中,只需要在软件层模拟相关的描述符,当系统从总线请求相关硬件属性的时候,我们提供相关的描述符信息即可。
UVC描述符是USB设备的子类,和通用的USB设备一样,UVC设备也含设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符。USB设备描述符是USB设备在进行插拔和初始化过程中,最先被主机读取的一部分信息,它包含了设备的一些基本属性信息,如USB规范版本、设备类、设备子类、设备协议、最大数据包长度等。
UVC设备除了常用的标准描述符,另外还定义了视频设备的特殊类描述符,包括接口联合描述符,视频控制接口描述符,视频控制端点描述符,视频流接口描述符,视频流端点描述符。
Windows下USB系统描述符的结构体定义大致如下:
struct _DEVICE_DESCRIPTOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号ÿ