by fanxiushu 2024-12-11 转载或引用请注明原作者。
续上文,
间隔的时间有点长,因此先简单回忆上文描述的内容。
上文主要是阐述在浏览器中如何通过 javascript脚本语言,通过WebRTC通讯方式,
把浏览器中的摄像头图像传输到 xdisp_virt程序,然后再通过xdisp_virt丰富的扩展功能把浏览器摄像头共享出去。
本文将主要阐述如何再进一步,把浏览器摄像头传递到xdisp_virt的图像再次模拟成电脑的摄像头。
为了让大家更明白本文以及上文在讲什么,我们还是先来一段演示视频和示列图:
手机浏览器摄像头映射到电脑端并且再次模拟成电脑摄像头
xdisp_virt程序的配置界面图如下:
更多和更详细的演示视频,可以去我的GITHUB对应项目下去查看:
GitHub - fanxiushu/xdisp_virt: xfsredir file system
本文主要是阐述如何实现电脑系统的虚拟摄像头驱动,
电脑系统以windows和linux为主,macOS因为驱动接触不多,所以目前并没实现对应的摄像头驱动。
windows平台的虚拟摄像头,以前的文章,以及以以前的文章都阐述了,讲的也挺多,
而且还是阐述的各种方式的,多种花样的实现windows平台下的摄像头驱动,因此这里也就不再罗嗦。
本文主要阐述linux平台下,实现V4L2框架的虚拟摄像头驱动。
V4L2驱动框架在linux系统中的地位类似于AVStream驱动框架在windows平台中的地位,都是实现流媒体的核心框架类。
但是V4L2对应的应用层接口显得非常原始,基本使用ioctl与驱动交互;
并不像windows平台做了各种封装,已经看不到原始的ioctl与驱动交互了。
我们来看看应用层如何ioctl来打开并且使用摄像头,这有助于我们了解V4L2驱动框架的大致运作过程。
1, 打开摄像头,通常是
int handle =open( "/dev/videoXX“, O_RDWR) , XX是具体的数字,
ioctl(handle, VIDIOC_QUERYCAP, &vcap);
通过VIDIOC_QUERYCAP命令获取设备的属性,判断是不是摄像头,以及摄像头名字等,
类似 VIDIOC_XXXX 的命令是非常多的,基本构成了V4L2 的主旋律。
2,查询图像格式,查询分辨率,设置图像格式等前期预备操作,
v4l2_format format; //
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(handle, VIDIOC_G_FMT, &format); ///VIDIOC_G_FMT查询图像格式
format.fmt.pix.height =height;
format.fmt.pix.width = width; 设置自己期望得宽高,其他参数保持不变
ioctl(handle, VIDIOC_S_FMT, &format); ///设置
ioctl(handle, VIDIOC_G_FMT, &format); /再次获取,因为我们期望的宽高与摄像头实际值可能有出入。
...... 还可以有许多其他参配置,比如 VIDIOC_ENUM_FRAMESIZES查询所有分辨率,VIDIOC_ENUM_FMT,
VIDIOC_S_PARM, VIDIOC_S_PARM, 等等,反正是非常多,估计这些参数命令得有十多个。
3,分配内存队列,用于图像数据传输,通常使用映射内存。
int len_arrar[4];
char* buf_array[4]; //用来保存从驱动映射到应用层的内存地址。
struct v4l2_requestbuffers req;
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(handle, VIDIOC_REQBUFS, &req); VIDIOC_REQBUFS命令分配映射内存,req.count返回实际分配到多少个内存块,
for (int i = 0; i < req.count; ++i) {
struct v4l2_buffer buffer;
memset(&buffer, 0, sizeof(buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = V4L2_MEMORY_MMAP;
buffer.index = i;
ioctl(handle, VIDIOC_QUERYBUF, &buffer) ; / 查询buffer信息,用于map映射内存到应用层。